From 9c333ade1a1b694fc6ce22e483f5de3e952c17ad Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 22 May 2017 17:50:30 +0200 Subject: move everying into sources/shiboken2 (5.9 edition) in preparation for a subtree merge. this should not be necessary to do in a separate commit, but git is a tad stupid about following history correctly without it. --- sources/shiboken2/.gitattributes | 2 + sources/shiboken2/.gitignore | 8 + sources/shiboken2/AUTHORS | 12 + sources/shiboken2/ApiExtractor/AUTHORS | 8 + sources/shiboken2/ApiExtractor/CMakeLists.txt | 90 + sources/shiboken2/ApiExtractor/COPYING | 342 ++ .../shiboken2/ApiExtractor/abstractmetabuilder.cpp | 3459 ++++++++++++ .../shiboken2/ApiExtractor/abstractmetabuilder.h | 106 + .../shiboken2/ApiExtractor/abstractmetabuilder_p.h | 194 + .../shiboken2/ApiExtractor/abstractmetalang.cpp | 2784 ++++++++++ sources/shiboken2/ApiExtractor/abstractmetalang.h | 1976 +++++++ .../ApiExtractor/abstractmetalang_typedefs.h | 50 + sources/shiboken2/ApiExtractor/apiextractor.cpp | 317 ++ sources/shiboken2/ApiExtractor/apiextractor.h | 111 + .../shiboken2/ApiExtractor/apiextractormacros.h | 41 + .../ApiExtractor/clangparser/clangbuilder.cpp | 770 +++ .../ApiExtractor/clangparser/clangbuilder.h | 58 + .../ApiExtractor/clangparser/clangdebugutils.cpp | 150 + .../ApiExtractor/clangparser/clangdebugutils.h | 48 + .../ApiExtractor/clangparser/clangparser.cpp | 266 + .../ApiExtractor/clangparser/clangparser.h | 93 + .../ApiExtractor/clangparser/clangutils.cpp | 227 + .../ApiExtractor/clangparser/clangutils.h | 101 + .../ApiExtractor/clangparser/compilersupport.cpp | 155 + .../ApiExtractor/clangparser/compilersupport.h | 40 + .../shiboken2/ApiExtractor/cmake_uninstall.cmake | 21 + sources/shiboken2/ApiExtractor/dependency.h | 43 + sources/shiboken2/ApiExtractor/doc/CMakeLists.txt | 10 + .../ApiExtractor/doc/_templates/index.html | 27 + .../ApiExtractor/doc/_templates/layout.html | 41 + .../doc/_themes/pysidedocs/searchbox.html | 12 + .../doc/_themes/pysidedocs/static/bg_header.png | Bin 0 -> 36012 bytes .../doc/_themes/pysidedocs/static/bg_topo.jpg | Bin 0 -> 14237 bytes .../doc/_themes/pysidedocs/static/fakebar.png | Bin 0 -> 101 bytes .../doc/_themes/pysidedocs/static/logo_indt.jpg | Bin 0 -> 3138 bytes .../_themes/pysidedocs/static/logo_openbossa.png | Bin 0 -> 4702 bytes .../doc/_themes/pysidedocs/static/logo_python.jpg | Bin 0 -> 2660 bytes .../doc/_themes/pysidedocs/static/logo_qt.png | Bin 0 -> 4618 bytes .../doc/_themes/pysidedocs/static/pysidedocs.css | 409 ++ .../doc/_themes/pysidedocs/static/pysidelogo.png | Bin 0 -> 12969 bytes .../doc/_themes/pysidedocs/static/relbar_bg.png | Bin 0 -> 130 bytes .../ApiExtractor/doc/_themes/pysidedocs/theme.conf | 7 + sources/shiboken2/ApiExtractor/doc/conf.py.in | 163 + sources/shiboken2/ApiExtractor/doc/contents.rst | 9 + .../ApiExtractor/doc/dependency-apiextractor.svg | 360 ++ sources/shiboken2/ApiExtractor/doc/overview.rst | 15 + sources/shiboken2/ApiExtractor/doc/ownership.rst | 85 + sources/shiboken2/ApiExtractor/doc/typesystem.rst | 29 + .../ApiExtractor/doc/typesystem_arguments.rst | 192 + .../ApiExtractor/doc/typesystem_conversionrule.rst | 113 + .../ApiExtractor/doc/typesystem_documentation.rst | 43 + .../doc/typesystem_manipulating_objects.rst | 132 + .../doc/typesystem_modify_function.rst | 78 + .../doc/typesystem_solving_compilation.rst | 70 + .../doc/typesystem_specifying_types.rst | 371 ++ .../ApiExtractor/doc/typesystem_templates.rst | 55 + sources/shiboken2/ApiExtractor/docparser.cpp | 174 + sources/shiboken2/ApiExtractor/docparser.h | 127 + sources/shiboken2/ApiExtractor/doxygenparser.cpp | 198 + sources/shiboken2/ApiExtractor/doxygenparser.h | 43 + sources/shiboken2/ApiExtractor/fileout.cpp | 231 + sources/shiboken2/ApiExtractor/fileout.h | 62 + sources/shiboken2/ApiExtractor/graph.cpp | 135 + sources/shiboken2/ApiExtractor/graph.h | 72 + sources/shiboken2/ApiExtractor/header_paths.h | 62 + sources/shiboken2/ApiExtractor/icecc.cmake | 11 + sources/shiboken2/ApiExtractor/include.cpp | 71 + sources/shiboken2/ApiExtractor/include.h | 92 + sources/shiboken2/ApiExtractor/merge.xsl | 82 + .../shiboken2/ApiExtractor/parser/codemodel.cpp | 1207 ++++ sources/shiboken2/ApiExtractor/parser/codemodel.h | 687 +++ .../ApiExtractor/parser/codemodel_enums.h | 38 + .../shiboken2/ApiExtractor/parser/codemodel_fwd.h | 82 + sources/shiboken2/ApiExtractor/qtdocparser.cpp | 189 + sources/shiboken2/ApiExtractor/qtdocparser.h | 44 + sources/shiboken2/ApiExtractor/reporthandler.cpp | 149 + sources/shiboken2/ApiExtractor/reporthandler.h | 71 + sources/shiboken2/ApiExtractor/symbols.filter | 7 + .../shiboken2/ApiExtractor/tests/CMakeLists.txt | 74 + sources/shiboken2/ApiExtractor/tests/a.xml | 13 + .../ApiExtractor/tests/testabstractmetaclass.cpp | 527 ++ .../ApiExtractor/tests/testabstractmetaclass.h | 55 + .../ApiExtractor/tests/testabstractmetatype.cpp | 216 + .../ApiExtractor/tests/testabstractmetatype.h | 47 + .../ApiExtractor/tests/testaddfunction.cpp | 453 ++ .../shiboken2/ApiExtractor/tests/testaddfunction.h | 54 + .../ApiExtractor/tests/testarrayargument.cpp | 130 + .../ApiExtractor/tests/testarrayargument.h | 42 + .../ApiExtractor/tests/testcodeinjection.cpp | 106 + .../ApiExtractor/tests/testcodeinjection.h | 45 + .../shiboken2/ApiExtractor/tests/testcontainer.cpp | 105 + .../shiboken2/ApiExtractor/tests/testcontainer.h | 41 + .../ApiExtractor/tests/testconversionoperator.cpp | 188 + .../ApiExtractor/tests/testconversionoperator.h | 44 + .../ApiExtractor/tests/testconversionruletag.cpp | 250 + .../ApiExtractor/tests/testconversionruletag.h | 43 + .../ApiExtractor/tests/testctorinformation.cpp | 76 + .../ApiExtractor/tests/testctorinformation.h | 44 + .../ApiExtractor/tests/testdroptypeentries.cpp | 145 + .../ApiExtractor/tests/testdroptypeentries.h | 44 + .../ApiExtractor/tests/testdtorinformation.cpp | 86 + .../ApiExtractor/tests/testdtorinformation.h | 46 + sources/shiboken2/ApiExtractor/tests/testenum.cpp | 416 ++ sources/shiboken2/ApiExtractor/tests/testenum.h | 47 + .../ApiExtractor/tests/testextrainclude.cpp | 85 + .../ApiExtractor/tests/testextrainclude.h | 42 + .../ApiExtractor/tests/testfunctiontag.cpp | 97 + .../shiboken2/ApiExtractor/tests/testfunctiontag.h | 42 + .../ApiExtractor/tests/testimplicitconversions.cpp | 163 + .../ApiExtractor/tests/testimplicitconversions.h | 46 + .../ApiExtractor/tests/testinserttemplate.cpp | 130 + .../ApiExtractor/tests/testinserttemplate.h | 44 + .../ApiExtractor/tests/testmodifydocumentation.cpp | 80 + .../ApiExtractor/tests/testmodifydocumentation.h | 41 + .../ApiExtractor/tests/testmodifyfunction.cpp | 249 + .../ApiExtractor/tests/testmodifyfunction.h | 45 + .../ApiExtractor/tests/testmultipleinheritance.cpp | 75 + .../ApiExtractor/tests/testmultipleinheritance.h | 43 + .../shiboken2/ApiExtractor/tests/testnamespace.cpp | 96 + .../shiboken2/ApiExtractor/tests/testnamespace.h | 44 + .../ApiExtractor/tests/testnestedtypes.cpp | 128 + .../shiboken2/ApiExtractor/tests/testnestedtypes.h | 41 + .../ApiExtractor/tests/testnumericaltypedef.cpp | 119 + .../ApiExtractor/tests/testnumericaltypedef.h | 42 + .../ApiExtractor/tests/testprimitivetypetag.cpp | 60 + .../ApiExtractor/tests/testprimitivetypetag.h | 41 + .../ApiExtractor/tests/testrefcounttag.cpp | 100 + .../shiboken2/ApiExtractor/tests/testrefcounttag.h | 42 + .../ApiExtractor/tests/testreferencetopointer.cpp | 59 + .../ApiExtractor/tests/testreferencetopointer.h | 41 + .../ApiExtractor/tests/testremovefield.cpp | 62 + .../shiboken2/ApiExtractor/tests/testremovefield.h | 41 + .../ApiExtractor/tests/testremoveimplconv.cpp | 69 + .../ApiExtractor/tests/testremoveimplconv.h | 41 + .../tests/testremoveoperatormethod.cpp | 117 + .../ApiExtractor/tests/testremoveoperatormethod.h | 41 + .../ApiExtractor/tests/testresolvetype.cpp | 64 + .../shiboken2/ApiExtractor/tests/testresolvetype.h | 41 + .../ApiExtractor/tests/testreverseoperators.cpp | 139 + .../ApiExtractor/tests/testreverseoperators.h | 41 + .../shiboken2/ApiExtractor/tests/testtemplates.cpp | 439 ++ .../shiboken2/ApiExtractor/tests/testtemplates.h | 51 + .../shiboken2/ApiExtractor/tests/testtoposort.cpp | 69 + .../shiboken2/ApiExtractor/tests/testtoposort.h | 42 + .../ApiExtractor/tests/testtyperevision.cpp | 71 + .../ApiExtractor/tests/testtyperevision.h | 42 + sources/shiboken2/ApiExtractor/tests/testutil.h | 78 + .../tests/testvaluetypedefaultctortag.cpp | 64 + .../tests/testvaluetypedefaultctortag.h | 41 + .../shiboken2/ApiExtractor/tests/testvoidarg.cpp | 87 + sources/shiboken2/ApiExtractor/tests/testvoidarg.h | 42 + sources/shiboken2/ApiExtractor/tests/utf8code.txt | 1 + sources/shiboken2/ApiExtractor/typedatabase.cpp | 745 +++ sources/shiboken2/ApiExtractor/typedatabase.h | 186 + .../shiboken2/ApiExtractor/typedatabase_typedefs.h | 49 + sources/shiboken2/ApiExtractor/typeparser.cpp | 318 ++ sources/shiboken2/ApiExtractor/typeparser.h | 60 + sources/shiboken2/ApiExtractor/typesystem.cpp | 2737 ++++++++++ sources/shiboken2/ApiExtractor/typesystem.h | 1975 +++++++ sources/shiboken2/ApiExtractor/typesystem_enums.h | 86 + sources/shiboken2/ApiExtractor/typesystem_p.h | 176 + .../shiboken2/ApiExtractor/typesystem_typedefs.h | 49 + sources/shiboken2/CMakeLists.txt | 285 + sources/shiboken2/COPYING | 342 ++ sources/shiboken2/COPYING.libsample | 501 ++ sources/shiboken2/COPYING.libshiboken | 501 ++ sources/shiboken2/Doxyfile | 311 ++ sources/shiboken2/LICENSE.GPLv3 | 686 +++ sources/shiboken2/LICENSE.LGPLv21 | 514 ++ sources/shiboken2/LICENSE.LGPLv3 | 175 + sources/shiboken2/LICENSE.PREVIEW.COMMERCIAL | 630 +++ sources/shiboken2/README.md | 19 + sources/shiboken2/cmake_uninstall.cmake | 21 + sources/shiboken2/data/CMakeLists.txt | 28 + .../shiboken2/data/GeneratorRunnerConfig.cmake.in | 17 + .../data/GeneratorRunnerConfigVersion.cmake.in | 10 + .../shiboken2/data/Shiboken2Config-spec.cmake.in | 29 + sources/shiboken2/data/Shiboken2Config.cmake.in | 5 + .../shiboken2/data/Shiboken2ConfigVersion.cmake.in | 10 + sources/shiboken2/data/docgenerator.1 | 1 + sources/shiboken2/data/generatorrunner.1 | 76 + sources/shiboken2/data/generatorrunner.pc.in | 13 + sources/shiboken2/data/shiboken2.pc.in | 13 + sources/shiboken2/doc/CMakeLists.txt | 24 + sources/shiboken2/doc/_templates/index.html | 35 + sources/shiboken2/doc/_templates/layout.html | 29 + .../doc/_themes/pysidedocs/searchbox.html | 12 + .../doc/_themes/pysidedocs/static/bg_header.png | Bin 0 -> 36012 bytes .../doc/_themes/pysidedocs/static/bg_topo.jpg | Bin 0 -> 14237 bytes .../doc/_themes/pysidedocs/static/fakebar.png | Bin 0 -> 101 bytes .../doc/_themes/pysidedocs/static/logo_python.jpg | Bin 0 -> 2660 bytes .../doc/_themes/pysidedocs/static/logo_qt.png | Bin 0 -> 1032 bytes .../doc/_themes/pysidedocs/static/pysidedocs.css | 475 ++ .../doc/_themes/pysidedocs/static/pysidelogo.png | Bin 0 -> 12969 bytes .../doc/_themes/pysidedocs/static/relbar_bg.png | Bin 0 -> 130 bytes .../shiboken2/doc/_themes/pysidedocs/theme.conf | 7 + sources/shiboken2/doc/codeinjectionsemantics.rst | 397 ++ sources/shiboken2/doc/commandlineoptions.rst | 105 + sources/shiboken2/doc/conf.py.in | 166 + sources/shiboken2/doc/contents.rst | 17 + sources/shiboken2/doc/dependency-pyqtb.svg | 600 ++ sources/shiboken2/doc/dependency-pyside.svg | 527 ++ sources/shiboken2/doc/faq.rst | 67 + sources/shiboken2/doc/images/.directory | 3 + .../doc/images/bindinggen-development.png | Bin 0 -> 34333 bytes .../doc/images/bindinggen-development.svg | 543 ++ sources/shiboken2/doc/images/boostgen.png | Bin 0 -> 153473 bytes sources/shiboken2/doc/images/boostqtarch.png | Bin 0 -> 34257 bytes sources/shiboken2/doc/images/boostqtarch.svg | 226 + sources/shiboken2/doc/images/converter.dot | 14 + sources/shiboken2/doc/images/converter.png | Bin 0 -> 37485 bytes sources/shiboken2/doc/images/genrunnerarch.png | Bin 0 -> 68761 bytes sources/shiboken2/doc/images/genrunnerarch.svg | 654 +++ sources/shiboken2/doc/overview.rst | 46 + sources/shiboken2/doc/ownership.rst | 153 + sources/shiboken2/doc/projectfile.rst | 65 + sources/shiboken2/doc/sequenceprotocol.rst | 23 + sources/shiboken2/doc/shiboken2.1 | 73 + sources/shiboken2/doc/shibokenmodule.rst | 79 + sources/shiboken2/doc/typeconverters.rst | 288 + sources/shiboken2/doc/typesystemvariables.rst | 336 ++ sources/shiboken2/doc/wordsofadvice.rst | 109 + sources/shiboken2/generator/CMakeLists.txt | 40 + sources/shiboken2/generator/generator.cpp | 864 +++ sources/shiboken2/generator/generator.h | 448 ++ sources/shiboken2/generator/main.cpp | 552 ++ sources/shiboken2/generator/qtdoc/CMakeLists.txt | 21 + .../shiboken2/generator/qtdoc/qtdocgenerator.cpp | 1715 ++++++ sources/shiboken2/generator/qtdoc/qtdocgenerator.h | 235 + .../shiboken2/generator/shiboken2/CMakeLists.txt | 28 + .../shiboken2/generator/shiboken2/cppgenerator.cpp | 5755 ++++++++++++++++++++ .../shiboken2/generator/shiboken2/cppgenerator.h | 370 ++ .../generator/shiboken2/headergenerator.cpp | 569 ++ .../generator/shiboken2/headergenerator.h | 67 + .../shiboken2/generator/shiboken2/overloaddata.cpp | 1092 ++++ .../shiboken2/generator/shiboken2/overloaddata.h | 163 + .../generator/shiboken2/shibokengenerator.cpp | 2728 ++++++++++ .../generator/shiboken2/shibokengenerator.h | 556 ++ sources/shiboken2/generator/shibokenconfig.h.in | 6 + sources/shiboken2/generatorrunnerconfig.h.in | 13 + sources/shiboken2/generatorrunnermacros.h | 48 + sources/shiboken2/generators/shiboken/shiboken.cpp | 32 + sources/shiboken2/header.COMM | 20 + sources/shiboken2/header.LGPL-ONLY | 22 + sources/shiboken2/header.LGPL21 | 33 + sources/shiboken2/header.LGPL3 | 36 + sources/shiboken2/header.LGPL3-COMM | 28 + sources/shiboken2/icecc.cmake | 11 + sources/shiboken2/libshiboken/CMakeLists.txt | 69 + sources/shiboken2/libshiboken/autodecref.h | 115 + sources/shiboken2/libshiboken/basewrapper.cpp | 1516 ++++++ sources/shiboken2/libshiboken/basewrapper.h | 451 ++ sources/shiboken2/libshiboken/basewrapper_p.h | 287 + sources/shiboken2/libshiboken/bindingmanager.cpp | 341 ++ sources/shiboken2/libshiboken/bindingmanager.h | 109 + sources/shiboken2/libshiboken/conversions.h | 731 +++ sources/shiboken2/libshiboken/debugfreehook.cpp | 194 + sources/shiboken2/libshiboken/debugfreehook.h | 61 + sources/shiboken2/libshiboken/gilstate.cpp | 68 + sources/shiboken2/libshiboken/gilstate.h | 63 + sources/shiboken2/libshiboken/helper.cpp | 142 + sources/shiboken2/libshiboken/helper.h | 136 + sources/shiboken2/libshiboken/python25compat.h | 104 + sources/shiboken2/libshiboken/sbkconverter.cpp | 571 ++ sources/shiboken2/libshiboken/sbkconverter.h | 367 ++ sources/shiboken2/libshiboken/sbkconverter_p.h | 574 ++ sources/shiboken2/libshiboken/sbkdbg.h | 124 + sources/shiboken2/libshiboken/sbkenum.cpp | 618 +++ sources/shiboken2/libshiboken/sbkenum.h | 118 + sources/shiboken2/libshiboken/sbkmodule.cpp | 111 + sources/shiboken2/libshiboken/sbkmodule.h | 115 + sources/shiboken2/libshiboken/sbkpython.h | 74 + sources/shiboken2/libshiboken/sbkstring.cpp | 202 + sources/shiboken2/libshiboken/sbkstring.h | 75 + sources/shiboken2/libshiboken/sbkversion.h.in | 50 + sources/shiboken2/libshiboken/shiboken.h | 60 + sources/shiboken2/libshiboken/shibokenbuffer.cpp | 96 + sources/shiboken2/libshiboken/shibokenbuffer.h | 85 + sources/shiboken2/libshiboken/shibokenmacros.h | 63 + sources/shiboken2/libshiboken/threadstatesaver.cpp | 69 + sources/shiboken2/libshiboken/threadstatesaver.h | 66 + .../tmp-referencetopython/sbkconverter.cpp | 213 + .../tmp-referencetopython/sbkconverter.h | 191 + sources/shiboken2/libshiboken/typeresolver.cpp | 160 + sources/shiboken2/libshiboken/typeresolver.h | 139 + sources/shiboken2/shibokenmodule/CMakeLists.txt | 40 + sources/shiboken2/shibokenmodule/nothing.h | 0 .../shiboken2/shibokenmodule/shibokenmodule.txt.in | 16 + .../shibokenmodule/typesystem_shiboken.xml | 120 + sources/shiboken2/tests/CMakeLists.txt | 102 + .../shiboken2/tests/dumpcodemodel/CMakeLists.txt | 5 + sources/shiboken2/tests/dumpcodemodel/main.cpp | 82 + sources/shiboken2/tests/libminimal/CMakeLists.txt | 13 + .../shiboken2/tests/libminimal/libminimalmacros.h | 46 + sources/shiboken2/tests/libminimal/listuser.cpp | 124 + sources/shiboken2/tests/libminimal/listuser.h | 75 + sources/shiboken2/tests/libminimal/minbool.h | 68 + sources/shiboken2/tests/libminimal/obj.cpp | 44 + sources/shiboken2/tests/libminimal/obj.h | 59 + sources/shiboken2/tests/libminimal/typedef.cpp | 75 + sources/shiboken2/tests/libminimal/typedef.h | 54 + sources/shiboken2/tests/libminimal/val.h | 59 + sources/shiboken2/tests/libother/CMakeLists.txt | 18 + .../tests/libother/extendsnoimplicitconversion.h | 45 + sources/shiboken2/tests/libother/libothermacros.h | 46 + sources/shiboken2/tests/libother/number.cpp | 59 + sources/shiboken2/tests/libother/number.h | 57 + sources/shiboken2/tests/libother/otherderived.cpp | 61 + sources/shiboken2/tests/libother/otherderived.h | 65 + .../tests/libother/othermultiplederived.cpp | 50 + .../tests/libother/othermultiplederived.h | 46 + .../shiboken2/tests/libother/otherobjecttype.cpp | 36 + sources/shiboken2/tests/libother/otherobjecttype.h | 49 + sources/shiboken2/tests/libsample/CMakeLists.txt | 57 + sources/shiboken2/tests/libsample/abstract.cpp | 97 + sources/shiboken2/tests/libsample/abstract.h | 107 + sources/shiboken2/tests/libsample/blackbox.cpp | 131 + sources/shiboken2/tests/libsample/blackbox.h | 67 + sources/shiboken2/tests/libsample/bucket.cpp | 86 + sources/shiboken2/tests/libsample/bucket.h | 59 + sources/shiboken2/tests/libsample/bytearray.cpp | 214 + sources/shiboken2/tests/libsample/bytearray.h | 89 + sources/shiboken2/tests/libsample/collector.cpp | 62 + sources/shiboken2/tests/libsample/collector.h | 71 + sources/shiboken2/tests/libsample/complex.cpp | 54 + sources/shiboken2/tests/libsample/complex.h | 55 + sources/shiboken2/tests/libsample/ctorconvrule.h | 45 + sources/shiboken2/tests/libsample/cvlist.h | 53 + sources/shiboken2/tests/libsample/derived.cpp | 119 + sources/shiboken2/tests/libsample/derived.h | 92 + sources/shiboken2/tests/libsample/echo.cpp | 29 + sources/shiboken2/tests/libsample/echo.h | 55 + sources/shiboken2/tests/libsample/expression.cpp | 137 + sources/shiboken2/tests/libsample/expression.h | 64 + sources/shiboken2/tests/libsample/filter.cpp | 73 + sources/shiboken2/tests/libsample/filter.h | 99 + sources/shiboken2/tests/libsample/functions.cpp | 214 + sources/shiboken2/tests/libsample/functions.h | 93 + sources/shiboken2/tests/libsample/handle.cpp | 44 + sources/shiboken2/tests/libsample/handle.h | 72 + sources/shiboken2/tests/libsample/implicitconv.cpp | 66 + sources/shiboken2/tests/libsample/implicitconv.h | 83 + sources/shiboken2/tests/libsample/injectcode.cpp | 108 + sources/shiboken2/tests/libsample/injectcode.h | 65 + .../shiboken2/tests/libsample/libsamplemacros.h | 46 + sources/shiboken2/tests/libsample/list.h | 106 + sources/shiboken2/tests/libsample/listuser.cpp | 91 + sources/shiboken2/tests/libsample/listuser.h | 74 + sources/shiboken2/tests/libsample/main.cpp | 244 + sources/shiboken2/tests/libsample/mapuser.cpp | 69 + sources/shiboken2/tests/libsample/mapuser.h | 65 + sources/shiboken2/tests/libsample/modelindex.h | 72 + .../shiboken2/tests/libsample/modifications.cpp | 151 + sources/shiboken2/tests/libsample/modifications.h | 142 + .../tests/libsample/modified_constructor.cpp | 42 + .../tests/libsample/modified_constructor.h | 46 + .../shiboken2/tests/libsample/multiple_derived.cpp | 64 + .../shiboken2/tests/libsample/multiple_derived.h | 195 + .../tests/libsample/noimplicitconversion.h | 49 + sources/shiboken2/tests/libsample/nondefaultctor.h | 75 + sources/shiboken2/tests/libsample/null.h | 44 + sources/shiboken2/tests/libsample/objectmodel.cpp | 42 + sources/shiboken2/tests/libsample/objectmodel.h | 58 + sources/shiboken2/tests/libsample/objecttype.cpp | 311 ++ sources/shiboken2/tests/libsample/objecttype.h | 176 + .../shiboken2/tests/libsample/objecttypebyvalue.h | 46 + .../shiboken2/tests/libsample/objecttypeholder.cpp | 52 + .../shiboken2/tests/libsample/objecttypeholder.h | 51 + .../shiboken2/tests/libsample/objecttypelayout.cpp | 68 + .../shiboken2/tests/libsample/objecttypelayout.h | 56 + .../tests/libsample/objecttypeoperators.cpp | 63 + .../tests/libsample/objecttypeoperators.h | 61 + sources/shiboken2/tests/libsample/objectview.cpp | 54 + sources/shiboken2/tests/libsample/objectview.h | 58 + sources/shiboken2/tests/libsample/oddbool.h | 83 + sources/shiboken2/tests/libsample/onlycopy.cpp | 57 + sources/shiboken2/tests/libsample/onlycopy.h | 59 + sources/shiboken2/tests/libsample/overload.cpp | 50 + sources/shiboken2/tests/libsample/overload.h | 143 + sources/shiboken2/tests/libsample/overloadsort.cpp | 30 + sources/shiboken2/tests/libsample/overloadsort.h | 88 + sources/shiboken2/tests/libsample/pairuser.cpp | 57 + sources/shiboken2/tests/libsample/pairuser.h | 55 + sources/shiboken2/tests/libsample/pen.cpp | 67 + sources/shiboken2/tests/libsample/pen.h | 62 + sources/shiboken2/tests/libsample/photon.cpp | 50 + sources/shiboken2/tests/libsample/photon.h | 140 + sources/shiboken2/tests/libsample/point.cpp | 155 + sources/shiboken2/tests/libsample/point.h | 99 + sources/shiboken2/tests/libsample/pointerholder.h | 45 + sources/shiboken2/tests/libsample/pointf.cpp | 126 + sources/shiboken2/tests/libsample/pointf.h | 88 + sources/shiboken2/tests/libsample/polygon.cpp | 75 + sources/shiboken2/tests/libsample/polygon.h | 66 + sources/shiboken2/tests/libsample/privatector.h | 55 + sources/shiboken2/tests/libsample/privatedtor.h | 60 + sources/shiboken2/tests/libsample/protected.cpp | 32 + sources/shiboken2/tests/libsample/protected.h | 151 + sources/shiboken2/tests/libsample/rect.h | 86 + sources/shiboken2/tests/libsample/reference.cpp | 78 + sources/shiboken2/tests/libsample/reference.h | 81 + .../shiboken2/tests/libsample/removednamespaces.h | 68 + sources/shiboken2/tests/libsample/sample.cpp | 39 + sources/shiboken2/tests/libsample/sample.h | 48 + .../shiboken2/tests/libsample/samplenamespace.cpp | 128 + .../shiboken2/tests/libsample/samplenamespace.h | 162 + sources/shiboken2/tests/libsample/sbkdate.cpp | 48 + sources/shiboken2/tests/libsample/sbkdate.h | 50 + sources/shiboken2/tests/libsample/simplefile.cpp | 108 + sources/shiboken2/tests/libsample/simplefile.h | 56 + sources/shiboken2/tests/libsample/size.cpp | 39 + sources/shiboken2/tests/libsample/size.h | 206 + sources/shiboken2/tests/libsample/sometime.cpp | 99 + sources/shiboken2/tests/libsample/sometime.h | 92 + sources/shiboken2/tests/libsample/str.cpp | 185 + sources/shiboken2/tests/libsample/str.h | 78 + sources/shiboken2/tests/libsample/strlist.cpp | 57 + sources/shiboken2/tests/libsample/strlist.h | 65 + sources/shiboken2/tests/libsample/templateptr.cpp | 33 + sources/shiboken2/tests/libsample/templateptr.h | 43 + sources/shiboken2/tests/libsample/transform.cpp | 65 + sources/shiboken2/tests/libsample/transform.h | 45 + .../shiboken2/tests/libsample/valueandvirtual.h | 47 + .../shiboken2/tests/libsample/virtualmethods.cpp | 59 + sources/shiboken2/tests/libsample/virtualmethods.h | 139 + sources/shiboken2/tests/libsample/voidholder.h | 50 + sources/shiboken2/tests/libsmart/CMakeLists.txt | 11 + sources/shiboken2/tests/libsmart/libsmartmacros.h | 46 + sources/shiboken2/tests/libsmart/smart.cpp | 174 + sources/shiboken2/tests/libsmart/smart.h | 210 + .../shiboken2/tests/minimalbinding/CMakeLists.txt | 38 + sources/shiboken2/tests/minimalbinding/global.h | 33 + .../tests/minimalbinding/listuser_test.py | 323 ++ .../shiboken2/tests/minimalbinding/minbool_test.py | 64 + .../tests/minimalbinding/minimal-binding.txt.in | 15 + sources/shiboken2/tests/minimalbinding/obj_test.py | 114 + .../shiboken2/tests/minimalbinding/typedef_test.py | 116 + .../tests/minimalbinding/typesystem_minimal.xml | 93 + sources/shiboken2/tests/minimalbinding/val_test.py | 115 + .../shiboken2/tests/otherbinding/CMakeLists.txt | 48 + .../collector_external_operator_test.py | 58 + ..._for_class_without_implicit_conversions_test.py | 73 + .../extended_multiply_operator_test.py | 64 + sources/shiboken2/tests/otherbinding/global.h | 35 + .../tests/otherbinding/module_reload_test.py | 61 + .../tests/otherbinding/new_ctor_operator_test.py | 56 + .../tests/otherbinding/objtypehashes_test.py | 53 + .../tests/otherbinding/other-binding.txt.in | 18 + .../tests/otherbinding/otherderived_test.py | 120 + .../tests/otherbinding/test_module_template.py | 40 + .../tests/otherbinding/typediscovery_test.py | 64 + .../tests/otherbinding/typesystem_other.xml | 15 + .../usersprimitivefromothermodule_test.py | 52 + .../shiboken2/tests/otherbinding/wrongctor_test.py | 53 + sources/shiboken2/tests/py3k.py | 2 + sources/shiboken2/tests/py3kcompat.py | 54 + .../shiboken2/tests/samplebinding/CMakeLists.txt | 145 + .../shiboken2/tests/samplebinding/__del___test.py | 50 + .../shiboken2/tests/samplebinding/abstract_test.py | 111 + .../tests/samplebinding/addedfunction_test.py | 62 + .../addedfunction_with_container_args_test.py | 51 + .../samplebinding/argumentmodifications_test.py | 111 + .../shiboken2/tests/samplebinding/bug_554_test.py | 45 + .../shiboken2/tests/samplebinding/bug_704_test.py | 68 + .../samplebinding/bytearray_bufferprotocol.cpp | 55 + .../tests/samplebinding/bytearray_test.py | 151 + .../tests/samplebinding/child_return_test.py | 58 + .../tests/samplebinding/class_fields_test.py | 168 + .../tests/samplebinding/collector_test.py | 81 + .../shiboken2/tests/samplebinding/complex_test.py | 84 + .../samplebinding/conversion_operator_test.py | 55 + sources/shiboken2/tests/samplebinding/copy_test.py | 86 + .../tests/samplebinding/ctorconvrule_test.py | 49 + .../shiboken2/tests/samplebinding/cyclic_test.py | 109 + sources/shiboken2/tests/samplebinding/date_test.py | 58 + .../shiboken2/tests/samplebinding/decisor_test.py | 65 + .../shiboken2/tests/samplebinding/delete_test.py | 47 + .../tests/samplebinding/deprecated_test.py | 44 + .../shiboken2/tests/samplebinding/derived_test.py | 153 + .../tests/samplebinding/duck_punching_test.py | 176 + sources/shiboken2/tests/samplebinding/echo_test.py | 52 + sources/shiboken2/tests/samplebinding/enum_test.py | 168 + .../samplebinding/enumfromremovednamespace_test.py | 53 + .../samplebinding/event_loop_call_virtual_test.py | 70 + .../tests/samplebinding/event_loop_thread_test.py | 96 + .../shiboken2/tests/samplebinding/filter_test.py | 45 + sources/shiboken2/tests/samplebinding/global.h | 90 + .../tests/samplebinding/handleholder_test.py | 57 + .../tests/samplebinding/hashabletype_test.py | 54 + .../tests/samplebinding/ignorederefop_test.py | 38 + .../samplebinding/implicitconv_numerical_test.py | 151 + .../tests/samplebinding/implicitconv_test.py | 66 + .../samplebinding/inheritanceandscope_test.py | 48 + .../tests/samplebinding/injectcode_test.py | 132 + .../tests/samplebinding/innerclass_test.py | 42 + .../shiboken2/tests/samplebinding/intlist_test.py | 98 + .../samplebinding/invalid_virtual_return_test.py | 65 + .../tests/samplebinding/keep_reference_test.py | 81 + sources/shiboken2/tests/samplebinding/list_test.py | 121 + sources/shiboken2/tests/samplebinding/lock_test.py | 95 + sources/shiboken2/tests/samplebinding/map_test.py | 80 + .../tests/samplebinding/metaclass_test.py | 61 + .../tests/samplebinding/mi_virtual_methods_test.py | 88 + .../shiboken2/tests/samplebinding/mixed_mi_test.py | 76 + .../tests/samplebinding/modelindex_test.py | 53 + .../tests/samplebinding/modelview_test.py | 78 + .../tests/samplebinding/modifications_test.py | 224 + .../samplebinding/modified_constructor_test.py | 49 + .../samplebinding/modifiedvirtualmethods_test.py | 248 + .../samplebinding/multi_cpp_inheritance_test.py | 105 + .../tests/samplebinding/multiple_derived_test.py | 221 + .../tests/samplebinding/namespace_test.py | 69 + .../tests/samplebinding/newdivision_test.py | 42 + .../tests/samplebinding/nondefaultctor_test.py | 71 + .../shiboken2/tests/samplebinding/nonzero_test.py | 43 + .../tests/samplebinding/numericaltypedef_test.py | 56 + .../shiboken2/tests/samplebinding/numpy_test.py | 58 + .../tests/samplebinding/objecttype_test.py | 122 + .../objecttype_with_named_args_test.py | 72 + .../tests/samplebinding/objecttypebyvalue_test.py | 42 + .../tests/samplebinding/objecttypelayout_test.py | 302 + .../samplebinding/objecttypeoperators_test.py | 60 + ...ecttypereferenceasvirtualmethodargument_test.py | 49 + .../shiboken2/tests/samplebinding/oddbool_test.py | 78 + .../samplebinding/oldstyleclass_as_number_test.py | 82 + .../tests/samplebinding/onlycopyclass_test.py | 57 + .../shiboken2/tests/samplebinding/overflow_test.py | 87 + .../tests/samplebinding/overload_sorting_test.py | 92 + .../shiboken2/tests/samplebinding/overload_test.py | 209 + .../samplebinding/overloadwithdefault_test.py | 64 + .../ownership_argument_invalidation_test.py | 62 + .../ownership_delete_child_in_cpp_test.py | 54 + .../ownership_delete_child_in_python_test.py | 60 + .../samplebinding/ownership_delete_parent_test.py | 82 + .../ownership_invalidate_after_use_test.py | 110 + .../ownership_invalidate_child_test.py | 69 + .../ownership_invalidate_nonpolymorphic_test.py | 53 + .../ownership_invalidate_parent_test.py | 68 + .../samplebinding/ownership_reparenting_test.py | 130 + .../samplebinding/ownership_transference_test.py | 85 + sources/shiboken2/tests/samplebinding/pair_test.py | 105 + sources/shiboken2/tests/samplebinding/pen_test.py | 63 + .../shiboken2/tests/samplebinding/point_test.py | 109 + .../tests/samplebinding/pointerholder_test.py | 59 + .../shiboken2/tests/samplebinding/pointf_test.py | 69 + .../primitivereferenceargument_test.py | 49 + .../tests/samplebinding/privatector_test.py | 84 + .../tests/samplebinding/privatedtor_test.py | 99 + .../tests/samplebinding/protected_test.py | 357 ++ .../shiboken2/tests/samplebinding/pstrlist_test.py | 50 + .../shiboken2/tests/samplebinding/pystr_test.py | 49 + .../tests/samplebinding/python_thread_test.py | 116 + .../samplebinding/receive_null_cstring_test.py | 54 + .../tests/samplebinding/reference_test.py | 122 + .../tests/samplebinding/referencetopointer_test.py | 97 + .../tests/samplebinding/return_null_test.py | 59 + .../tests/samplebinding/richcompare_test.py | 46 + .../tests/samplebinding/sample-binding.txt.in | 15 + .../shiboken2/tests/samplebinding/sample_test.py | 78 + .../tests/samplebinding/simplefile_glue.cpp | 34 + .../tests/samplebinding/simplefile_test.py | 81 + sources/shiboken2/tests/samplebinding/size_test.py | 119 + .../samplebinding/static_nonstatic_methods_test.py | 109 + sources/shiboken2/tests/samplebinding/str_test.py | 115 + .../shiboken2/tests/samplebinding/strlist_test.py | 112 + .../samplebinding/templateinheritingclass_test.py | 80 + sources/shiboken2/tests/samplebinding/time_test.py | 139 + .../tests/samplebinding/transform_test.py | 56 + .../tests/samplebinding/typeconverters_test.py | 189 + .../tests/samplebinding/typedealloc_test.py | 75 + .../tests/samplebinding/typedtordoublefree_test.py | 54 + .../tests/samplebinding/typesystem_sample.xml | 2426 +++++++++ .../tests/samplebinding/unsafe_parent_test.py | 54 + .../tests/samplebinding/useraddedctor_test.py | 45 + .../tests/samplebinding/virtualdtor_test.py | 76 + .../tests/samplebinding/virtualmethods_test.py | 138 + .../tests/samplebinding/visibilitychange_test.py | 47 + .../tests/samplebinding/voidholder_test.py | 69 + .../shiboken2/tests/samplebinding/weakref_test.py | 65 + .../tests/samplebinding/writableclassdict_test.py | 52 + .../shiboken2/tests/shibokenmodule/module_test.py | 116 + .../shiboken2/tests/smartbinding/CMakeLists.txt | 39 + sources/shiboken2/tests/smartbinding/global.h | 29 + .../tests/smartbinding/smart-binding.txt.in | 15 + .../tests/smartbinding/smart_pointer_test.py | 147 + .../tests/smartbinding/typesystem_smart.xml | 23 + sources/shiboken2/tests/sphinxtabletest.cpp | 332 ++ sources/shiboken2/tests/sphinxtabletest.h | 54 + .../shiboken2/tests/test_generator/CMakeLists.txt | 68 + .../tests/test_generator/dummygenerator.cpp | 70 + .../tests/test_generator/dummygenerator.h | 49 + .../test_generator/dummygentest-project.txt.in | 20 + .../tests/test_generator/dummygentest.cpp | 138 + .../shiboken2/tests/test_generator/dummygentest.h | 56 + .../tests/test_generator/dummygentestconfig.h.in | 15 + sources/shiboken2/tests/test_generator/main.cpp | 39 + .../shiboken2/tests/test_generator/run_test.cmake | 11 + .../shiboken2/tests/test_generator/test_global.h | 1 + .../tests/test_generator/test_typesystem.xml | 3 + 599 files changed, 91828 insertions(+) create mode 100644 sources/shiboken2/.gitattributes create mode 100644 sources/shiboken2/.gitignore create mode 100644 sources/shiboken2/AUTHORS create mode 100644 sources/shiboken2/ApiExtractor/AUTHORS create mode 100644 sources/shiboken2/ApiExtractor/CMakeLists.txt create mode 100644 sources/shiboken2/ApiExtractor/COPYING create mode 100644 sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp create mode 100644 sources/shiboken2/ApiExtractor/abstractmetabuilder.h create mode 100644 sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h create mode 100644 sources/shiboken2/ApiExtractor/abstractmetalang.cpp create mode 100644 sources/shiboken2/ApiExtractor/abstractmetalang.h create mode 100644 sources/shiboken2/ApiExtractor/abstractmetalang_typedefs.h create mode 100644 sources/shiboken2/ApiExtractor/apiextractor.cpp create mode 100644 sources/shiboken2/ApiExtractor/apiextractor.h create mode 100644 sources/shiboken2/ApiExtractor/apiextractormacros.h create mode 100644 sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp create mode 100644 sources/shiboken2/ApiExtractor/clangparser/clangbuilder.h create mode 100644 sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.cpp create mode 100644 sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.h create mode 100644 sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp create mode 100644 sources/shiboken2/ApiExtractor/clangparser/clangparser.h create mode 100644 sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp create mode 100644 sources/shiboken2/ApiExtractor/clangparser/clangutils.h create mode 100644 sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp create mode 100644 sources/shiboken2/ApiExtractor/clangparser/compilersupport.h create mode 100644 sources/shiboken2/ApiExtractor/cmake_uninstall.cmake create mode 100644 sources/shiboken2/ApiExtractor/dependency.h create mode 100644 sources/shiboken2/ApiExtractor/doc/CMakeLists.txt create mode 100644 sources/shiboken2/ApiExtractor/doc/_templates/index.html create mode 100644 sources/shiboken2/ApiExtractor/doc/_templates/layout.html create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/searchbox.html create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_header.png create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_topo.jpg create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/fakebar.png create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_indt.jpg create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_openbossa.png create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_python.jpg create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_qt.png create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidedocs.css create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidelogo.png create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/relbar_bg.png create mode 100644 sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/theme.conf create mode 100644 sources/shiboken2/ApiExtractor/doc/conf.py.in create mode 100644 sources/shiboken2/ApiExtractor/doc/contents.rst create mode 100644 sources/shiboken2/ApiExtractor/doc/dependency-apiextractor.svg create mode 100644 sources/shiboken2/ApiExtractor/doc/overview.rst create mode 100644 sources/shiboken2/ApiExtractor/doc/ownership.rst create mode 100644 sources/shiboken2/ApiExtractor/doc/typesystem.rst create mode 100644 sources/shiboken2/ApiExtractor/doc/typesystem_arguments.rst create mode 100644 sources/shiboken2/ApiExtractor/doc/typesystem_conversionrule.rst create mode 100644 sources/shiboken2/ApiExtractor/doc/typesystem_documentation.rst create mode 100644 sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst create mode 100644 sources/shiboken2/ApiExtractor/doc/typesystem_modify_function.rst create mode 100644 sources/shiboken2/ApiExtractor/doc/typesystem_solving_compilation.rst create mode 100644 sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst create mode 100644 sources/shiboken2/ApiExtractor/doc/typesystem_templates.rst create mode 100644 sources/shiboken2/ApiExtractor/docparser.cpp create mode 100644 sources/shiboken2/ApiExtractor/docparser.h create mode 100644 sources/shiboken2/ApiExtractor/doxygenparser.cpp create mode 100644 sources/shiboken2/ApiExtractor/doxygenparser.h create mode 100644 sources/shiboken2/ApiExtractor/fileout.cpp create mode 100644 sources/shiboken2/ApiExtractor/fileout.h create mode 100644 sources/shiboken2/ApiExtractor/graph.cpp create mode 100644 sources/shiboken2/ApiExtractor/graph.h create mode 100644 sources/shiboken2/ApiExtractor/header_paths.h create mode 100644 sources/shiboken2/ApiExtractor/icecc.cmake create mode 100644 sources/shiboken2/ApiExtractor/include.cpp create mode 100644 sources/shiboken2/ApiExtractor/include.h create mode 100644 sources/shiboken2/ApiExtractor/merge.xsl create mode 100644 sources/shiboken2/ApiExtractor/parser/codemodel.cpp create mode 100644 sources/shiboken2/ApiExtractor/parser/codemodel.h create mode 100644 sources/shiboken2/ApiExtractor/parser/codemodel_enums.h create mode 100644 sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h create mode 100644 sources/shiboken2/ApiExtractor/qtdocparser.cpp create mode 100644 sources/shiboken2/ApiExtractor/qtdocparser.h create mode 100644 sources/shiboken2/ApiExtractor/reporthandler.cpp create mode 100644 sources/shiboken2/ApiExtractor/reporthandler.h create mode 100644 sources/shiboken2/ApiExtractor/symbols.filter create mode 100644 sources/shiboken2/ApiExtractor/tests/CMakeLists.txt create mode 100644 sources/shiboken2/ApiExtractor/tests/a.xml create mode 100644 sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testaddfunction.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testarrayargument.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testarrayargument.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testcodeinjection.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testcontainer.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testcontainer.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testconversionoperator.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testconversionoperator.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testconversionruletag.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testconversionruletag.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testctorinformation.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testctorinformation.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testdroptypeentries.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testdtorinformation.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testenum.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testenum.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testextrainclude.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testextrainclude.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testfunctiontag.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testfunctiontag.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testimplicitconversions.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testimplicitconversions.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testinserttemplate.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testinserttemplate.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testnamespace.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testnamespace.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testnestedtypes.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testnestedtypes.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testrefcounttag.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testreferencetopointer.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testreferencetopointer.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testremovefield.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testremovefield.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testremoveimplconv.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testremoveimplconv.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testresolvetype.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testreverseoperators.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testreverseoperators.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testtemplates.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testtemplates.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testtoposort.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testtoposort.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testtyperevision.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testutil.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.h create mode 100644 sources/shiboken2/ApiExtractor/tests/testvoidarg.cpp create mode 100644 sources/shiboken2/ApiExtractor/tests/testvoidarg.h create mode 100644 sources/shiboken2/ApiExtractor/tests/utf8code.txt create mode 100644 sources/shiboken2/ApiExtractor/typedatabase.cpp create mode 100644 sources/shiboken2/ApiExtractor/typedatabase.h create mode 100644 sources/shiboken2/ApiExtractor/typedatabase_typedefs.h create mode 100644 sources/shiboken2/ApiExtractor/typeparser.cpp create mode 100644 sources/shiboken2/ApiExtractor/typeparser.h create mode 100644 sources/shiboken2/ApiExtractor/typesystem.cpp create mode 100644 sources/shiboken2/ApiExtractor/typesystem.h create mode 100644 sources/shiboken2/ApiExtractor/typesystem_enums.h create mode 100644 sources/shiboken2/ApiExtractor/typesystem_p.h create mode 100644 sources/shiboken2/ApiExtractor/typesystem_typedefs.h create mode 100644 sources/shiboken2/CMakeLists.txt create mode 100644 sources/shiboken2/COPYING create mode 100644 sources/shiboken2/COPYING.libsample create mode 100644 sources/shiboken2/COPYING.libshiboken create mode 100644 sources/shiboken2/Doxyfile create mode 100644 sources/shiboken2/LICENSE.GPLv3 create mode 100644 sources/shiboken2/LICENSE.LGPLv21 create mode 100644 sources/shiboken2/LICENSE.LGPLv3 create mode 100644 sources/shiboken2/LICENSE.PREVIEW.COMMERCIAL create mode 100644 sources/shiboken2/README.md create mode 100644 sources/shiboken2/cmake_uninstall.cmake create mode 100644 sources/shiboken2/data/CMakeLists.txt create mode 100644 sources/shiboken2/data/GeneratorRunnerConfig.cmake.in create mode 100644 sources/shiboken2/data/GeneratorRunnerConfigVersion.cmake.in create mode 100644 sources/shiboken2/data/Shiboken2Config-spec.cmake.in create mode 100644 sources/shiboken2/data/Shiboken2Config.cmake.in create mode 100644 sources/shiboken2/data/Shiboken2ConfigVersion.cmake.in create mode 120000 sources/shiboken2/data/docgenerator.1 create mode 100644 sources/shiboken2/data/generatorrunner.1 create mode 100644 sources/shiboken2/data/generatorrunner.pc.in create mode 100644 sources/shiboken2/data/shiboken2.pc.in create mode 100644 sources/shiboken2/doc/CMakeLists.txt create mode 100644 sources/shiboken2/doc/_templates/index.html create mode 100644 sources/shiboken2/doc/_templates/layout.html create mode 100644 sources/shiboken2/doc/_themes/pysidedocs/searchbox.html create mode 100644 sources/shiboken2/doc/_themes/pysidedocs/static/bg_header.png create mode 100644 sources/shiboken2/doc/_themes/pysidedocs/static/bg_topo.jpg create mode 100644 sources/shiboken2/doc/_themes/pysidedocs/static/fakebar.png create mode 100644 sources/shiboken2/doc/_themes/pysidedocs/static/logo_python.jpg create mode 100644 sources/shiboken2/doc/_themes/pysidedocs/static/logo_qt.png create mode 100644 sources/shiboken2/doc/_themes/pysidedocs/static/pysidedocs.css create mode 100644 sources/shiboken2/doc/_themes/pysidedocs/static/pysidelogo.png create mode 100644 sources/shiboken2/doc/_themes/pysidedocs/static/relbar_bg.png create mode 100644 sources/shiboken2/doc/_themes/pysidedocs/theme.conf create mode 100644 sources/shiboken2/doc/codeinjectionsemantics.rst create mode 100644 sources/shiboken2/doc/commandlineoptions.rst create mode 100644 sources/shiboken2/doc/conf.py.in create mode 100644 sources/shiboken2/doc/contents.rst create mode 100644 sources/shiboken2/doc/dependency-pyqtb.svg create mode 100644 sources/shiboken2/doc/dependency-pyside.svg create mode 100644 sources/shiboken2/doc/faq.rst create mode 100644 sources/shiboken2/doc/images/.directory create mode 100644 sources/shiboken2/doc/images/bindinggen-development.png create mode 100644 sources/shiboken2/doc/images/bindinggen-development.svg create mode 100644 sources/shiboken2/doc/images/boostgen.png create mode 100644 sources/shiboken2/doc/images/boostqtarch.png create mode 100644 sources/shiboken2/doc/images/boostqtarch.svg create mode 100644 sources/shiboken2/doc/images/converter.dot create mode 100644 sources/shiboken2/doc/images/converter.png create mode 100644 sources/shiboken2/doc/images/genrunnerarch.png create mode 100644 sources/shiboken2/doc/images/genrunnerarch.svg create mode 100644 sources/shiboken2/doc/overview.rst create mode 100644 sources/shiboken2/doc/ownership.rst create mode 100644 sources/shiboken2/doc/projectfile.rst create mode 100644 sources/shiboken2/doc/sequenceprotocol.rst create mode 100644 sources/shiboken2/doc/shiboken2.1 create mode 100644 sources/shiboken2/doc/shibokenmodule.rst create mode 100644 sources/shiboken2/doc/typeconverters.rst create mode 100644 sources/shiboken2/doc/typesystemvariables.rst create mode 100644 sources/shiboken2/doc/wordsofadvice.rst create mode 100644 sources/shiboken2/generator/CMakeLists.txt create mode 100644 sources/shiboken2/generator/generator.cpp create mode 100644 sources/shiboken2/generator/generator.h create mode 100644 sources/shiboken2/generator/main.cpp create mode 100644 sources/shiboken2/generator/qtdoc/CMakeLists.txt create mode 100644 sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp create mode 100644 sources/shiboken2/generator/qtdoc/qtdocgenerator.h create mode 100644 sources/shiboken2/generator/shiboken2/CMakeLists.txt create mode 100644 sources/shiboken2/generator/shiboken2/cppgenerator.cpp create mode 100644 sources/shiboken2/generator/shiboken2/cppgenerator.h create mode 100644 sources/shiboken2/generator/shiboken2/headergenerator.cpp create mode 100644 sources/shiboken2/generator/shiboken2/headergenerator.h create mode 100644 sources/shiboken2/generator/shiboken2/overloaddata.cpp create mode 100644 sources/shiboken2/generator/shiboken2/overloaddata.h create mode 100644 sources/shiboken2/generator/shiboken2/shibokengenerator.cpp create mode 100644 sources/shiboken2/generator/shiboken2/shibokengenerator.h create mode 100644 sources/shiboken2/generator/shibokenconfig.h.in create mode 100644 sources/shiboken2/generatorrunnerconfig.h.in create mode 100644 sources/shiboken2/generatorrunnermacros.h create mode 100644 sources/shiboken2/generators/shiboken/shiboken.cpp create mode 100644 sources/shiboken2/header.COMM create mode 100644 sources/shiboken2/header.LGPL-ONLY create mode 100644 sources/shiboken2/header.LGPL21 create mode 100644 sources/shiboken2/header.LGPL3 create mode 100644 sources/shiboken2/header.LGPL3-COMM create mode 100644 sources/shiboken2/icecc.cmake create mode 100644 sources/shiboken2/libshiboken/CMakeLists.txt create mode 100644 sources/shiboken2/libshiboken/autodecref.h create mode 100644 sources/shiboken2/libshiboken/basewrapper.cpp create mode 100644 sources/shiboken2/libshiboken/basewrapper.h create mode 100644 sources/shiboken2/libshiboken/basewrapper_p.h create mode 100644 sources/shiboken2/libshiboken/bindingmanager.cpp create mode 100644 sources/shiboken2/libshiboken/bindingmanager.h create mode 100644 sources/shiboken2/libshiboken/conversions.h create mode 100644 sources/shiboken2/libshiboken/debugfreehook.cpp create mode 100644 sources/shiboken2/libshiboken/debugfreehook.h create mode 100644 sources/shiboken2/libshiboken/gilstate.cpp create mode 100644 sources/shiboken2/libshiboken/gilstate.h create mode 100644 sources/shiboken2/libshiboken/helper.cpp create mode 100644 sources/shiboken2/libshiboken/helper.h create mode 100644 sources/shiboken2/libshiboken/python25compat.h create mode 100644 sources/shiboken2/libshiboken/sbkconverter.cpp create mode 100644 sources/shiboken2/libshiboken/sbkconverter.h create mode 100644 sources/shiboken2/libshiboken/sbkconverter_p.h create mode 100644 sources/shiboken2/libshiboken/sbkdbg.h create mode 100644 sources/shiboken2/libshiboken/sbkenum.cpp create mode 100644 sources/shiboken2/libshiboken/sbkenum.h create mode 100644 sources/shiboken2/libshiboken/sbkmodule.cpp create mode 100644 sources/shiboken2/libshiboken/sbkmodule.h create mode 100644 sources/shiboken2/libshiboken/sbkpython.h create mode 100644 sources/shiboken2/libshiboken/sbkstring.cpp create mode 100644 sources/shiboken2/libshiboken/sbkstring.h create mode 100644 sources/shiboken2/libshiboken/sbkversion.h.in create mode 100644 sources/shiboken2/libshiboken/shiboken.h create mode 100644 sources/shiboken2/libshiboken/shibokenbuffer.cpp create mode 100644 sources/shiboken2/libshiboken/shibokenbuffer.h create mode 100644 sources/shiboken2/libshiboken/shibokenmacros.h create mode 100644 sources/shiboken2/libshiboken/threadstatesaver.cpp create mode 100644 sources/shiboken2/libshiboken/threadstatesaver.h create mode 100644 sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp create mode 100644 sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h create mode 100644 sources/shiboken2/libshiboken/typeresolver.cpp create mode 100644 sources/shiboken2/libshiboken/typeresolver.h create mode 100644 sources/shiboken2/shibokenmodule/CMakeLists.txt create mode 100644 sources/shiboken2/shibokenmodule/nothing.h create mode 100644 sources/shiboken2/shibokenmodule/shibokenmodule.txt.in create mode 100644 sources/shiboken2/shibokenmodule/typesystem_shiboken.xml create mode 100644 sources/shiboken2/tests/CMakeLists.txt create mode 100644 sources/shiboken2/tests/dumpcodemodel/CMakeLists.txt create mode 100644 sources/shiboken2/tests/dumpcodemodel/main.cpp create mode 100644 sources/shiboken2/tests/libminimal/CMakeLists.txt create mode 100644 sources/shiboken2/tests/libminimal/libminimalmacros.h create mode 100644 sources/shiboken2/tests/libminimal/listuser.cpp create mode 100644 sources/shiboken2/tests/libminimal/listuser.h create mode 100644 sources/shiboken2/tests/libminimal/minbool.h create mode 100644 sources/shiboken2/tests/libminimal/obj.cpp create mode 100644 sources/shiboken2/tests/libminimal/obj.h create mode 100644 sources/shiboken2/tests/libminimal/typedef.cpp create mode 100644 sources/shiboken2/tests/libminimal/typedef.h create mode 100644 sources/shiboken2/tests/libminimal/val.h create mode 100644 sources/shiboken2/tests/libother/CMakeLists.txt create mode 100644 sources/shiboken2/tests/libother/extendsnoimplicitconversion.h create mode 100644 sources/shiboken2/tests/libother/libothermacros.h create mode 100644 sources/shiboken2/tests/libother/number.cpp create mode 100644 sources/shiboken2/tests/libother/number.h create mode 100644 sources/shiboken2/tests/libother/otherderived.cpp create mode 100644 sources/shiboken2/tests/libother/otherderived.h create mode 100644 sources/shiboken2/tests/libother/othermultiplederived.cpp create mode 100644 sources/shiboken2/tests/libother/othermultiplederived.h create mode 100644 sources/shiboken2/tests/libother/otherobjecttype.cpp create mode 100644 sources/shiboken2/tests/libother/otherobjecttype.h create mode 100644 sources/shiboken2/tests/libsample/CMakeLists.txt create mode 100644 sources/shiboken2/tests/libsample/abstract.cpp create mode 100644 sources/shiboken2/tests/libsample/abstract.h create mode 100644 sources/shiboken2/tests/libsample/blackbox.cpp create mode 100644 sources/shiboken2/tests/libsample/blackbox.h create mode 100644 sources/shiboken2/tests/libsample/bucket.cpp create mode 100644 sources/shiboken2/tests/libsample/bucket.h create mode 100644 sources/shiboken2/tests/libsample/bytearray.cpp create mode 100644 sources/shiboken2/tests/libsample/bytearray.h create mode 100644 sources/shiboken2/tests/libsample/collector.cpp create mode 100644 sources/shiboken2/tests/libsample/collector.h create mode 100644 sources/shiboken2/tests/libsample/complex.cpp create mode 100644 sources/shiboken2/tests/libsample/complex.h create mode 100644 sources/shiboken2/tests/libsample/ctorconvrule.h create mode 100644 sources/shiboken2/tests/libsample/cvlist.h create mode 100644 sources/shiboken2/tests/libsample/derived.cpp create mode 100644 sources/shiboken2/tests/libsample/derived.h create mode 100644 sources/shiboken2/tests/libsample/echo.cpp create mode 100644 sources/shiboken2/tests/libsample/echo.h create mode 100644 sources/shiboken2/tests/libsample/expression.cpp create mode 100644 sources/shiboken2/tests/libsample/expression.h create mode 100644 sources/shiboken2/tests/libsample/filter.cpp create mode 100644 sources/shiboken2/tests/libsample/filter.h create mode 100644 sources/shiboken2/tests/libsample/functions.cpp create mode 100644 sources/shiboken2/tests/libsample/functions.h create mode 100644 sources/shiboken2/tests/libsample/handle.cpp create mode 100644 sources/shiboken2/tests/libsample/handle.h create mode 100644 sources/shiboken2/tests/libsample/implicitconv.cpp create mode 100644 sources/shiboken2/tests/libsample/implicitconv.h create mode 100644 sources/shiboken2/tests/libsample/injectcode.cpp create mode 100644 sources/shiboken2/tests/libsample/injectcode.h create mode 100644 sources/shiboken2/tests/libsample/libsamplemacros.h create mode 100644 sources/shiboken2/tests/libsample/list.h create mode 100644 sources/shiboken2/tests/libsample/listuser.cpp create mode 100644 sources/shiboken2/tests/libsample/listuser.h create mode 100644 sources/shiboken2/tests/libsample/main.cpp create mode 100644 sources/shiboken2/tests/libsample/mapuser.cpp create mode 100644 sources/shiboken2/tests/libsample/mapuser.h create mode 100644 sources/shiboken2/tests/libsample/modelindex.h create mode 100644 sources/shiboken2/tests/libsample/modifications.cpp create mode 100644 sources/shiboken2/tests/libsample/modifications.h create mode 100644 sources/shiboken2/tests/libsample/modified_constructor.cpp create mode 100644 sources/shiboken2/tests/libsample/modified_constructor.h create mode 100644 sources/shiboken2/tests/libsample/multiple_derived.cpp create mode 100644 sources/shiboken2/tests/libsample/multiple_derived.h create mode 100644 sources/shiboken2/tests/libsample/noimplicitconversion.h create mode 100644 sources/shiboken2/tests/libsample/nondefaultctor.h create mode 100644 sources/shiboken2/tests/libsample/null.h create mode 100644 sources/shiboken2/tests/libsample/objectmodel.cpp create mode 100644 sources/shiboken2/tests/libsample/objectmodel.h create mode 100644 sources/shiboken2/tests/libsample/objecttype.cpp create mode 100644 sources/shiboken2/tests/libsample/objecttype.h create mode 100644 sources/shiboken2/tests/libsample/objecttypebyvalue.h create mode 100644 sources/shiboken2/tests/libsample/objecttypeholder.cpp create mode 100644 sources/shiboken2/tests/libsample/objecttypeholder.h create mode 100644 sources/shiboken2/tests/libsample/objecttypelayout.cpp create mode 100644 sources/shiboken2/tests/libsample/objecttypelayout.h create mode 100644 sources/shiboken2/tests/libsample/objecttypeoperators.cpp create mode 100644 sources/shiboken2/tests/libsample/objecttypeoperators.h create mode 100644 sources/shiboken2/tests/libsample/objectview.cpp create mode 100644 sources/shiboken2/tests/libsample/objectview.h create mode 100644 sources/shiboken2/tests/libsample/oddbool.h create mode 100644 sources/shiboken2/tests/libsample/onlycopy.cpp create mode 100644 sources/shiboken2/tests/libsample/onlycopy.h create mode 100644 sources/shiboken2/tests/libsample/overload.cpp create mode 100644 sources/shiboken2/tests/libsample/overload.h create mode 100644 sources/shiboken2/tests/libsample/overloadsort.cpp create mode 100644 sources/shiboken2/tests/libsample/overloadsort.h create mode 100644 sources/shiboken2/tests/libsample/pairuser.cpp create mode 100644 sources/shiboken2/tests/libsample/pairuser.h create mode 100644 sources/shiboken2/tests/libsample/pen.cpp create mode 100644 sources/shiboken2/tests/libsample/pen.h create mode 100644 sources/shiboken2/tests/libsample/photon.cpp create mode 100644 sources/shiboken2/tests/libsample/photon.h create mode 100644 sources/shiboken2/tests/libsample/point.cpp create mode 100644 sources/shiboken2/tests/libsample/point.h create mode 100644 sources/shiboken2/tests/libsample/pointerholder.h create mode 100644 sources/shiboken2/tests/libsample/pointf.cpp create mode 100644 sources/shiboken2/tests/libsample/pointf.h create mode 100644 sources/shiboken2/tests/libsample/polygon.cpp create mode 100644 sources/shiboken2/tests/libsample/polygon.h create mode 100644 sources/shiboken2/tests/libsample/privatector.h create mode 100644 sources/shiboken2/tests/libsample/privatedtor.h create mode 100644 sources/shiboken2/tests/libsample/protected.cpp create mode 100644 sources/shiboken2/tests/libsample/protected.h create mode 100644 sources/shiboken2/tests/libsample/rect.h create mode 100644 sources/shiboken2/tests/libsample/reference.cpp create mode 100644 sources/shiboken2/tests/libsample/reference.h create mode 100644 sources/shiboken2/tests/libsample/removednamespaces.h create mode 100644 sources/shiboken2/tests/libsample/sample.cpp create mode 100644 sources/shiboken2/tests/libsample/sample.h create mode 100644 sources/shiboken2/tests/libsample/samplenamespace.cpp create mode 100644 sources/shiboken2/tests/libsample/samplenamespace.h create mode 100644 sources/shiboken2/tests/libsample/sbkdate.cpp create mode 100644 sources/shiboken2/tests/libsample/sbkdate.h create mode 100644 sources/shiboken2/tests/libsample/simplefile.cpp create mode 100644 sources/shiboken2/tests/libsample/simplefile.h create mode 100644 sources/shiboken2/tests/libsample/size.cpp create mode 100644 sources/shiboken2/tests/libsample/size.h create mode 100644 sources/shiboken2/tests/libsample/sometime.cpp create mode 100644 sources/shiboken2/tests/libsample/sometime.h create mode 100644 sources/shiboken2/tests/libsample/str.cpp create mode 100644 sources/shiboken2/tests/libsample/str.h create mode 100644 sources/shiboken2/tests/libsample/strlist.cpp create mode 100644 sources/shiboken2/tests/libsample/strlist.h create mode 100644 sources/shiboken2/tests/libsample/templateptr.cpp create mode 100644 sources/shiboken2/tests/libsample/templateptr.h create mode 100644 sources/shiboken2/tests/libsample/transform.cpp create mode 100644 sources/shiboken2/tests/libsample/transform.h create mode 100644 sources/shiboken2/tests/libsample/valueandvirtual.h create mode 100644 sources/shiboken2/tests/libsample/virtualmethods.cpp create mode 100644 sources/shiboken2/tests/libsample/virtualmethods.h create mode 100644 sources/shiboken2/tests/libsample/voidholder.h create mode 100644 sources/shiboken2/tests/libsmart/CMakeLists.txt create mode 100644 sources/shiboken2/tests/libsmart/libsmartmacros.h create mode 100644 sources/shiboken2/tests/libsmart/smart.cpp create mode 100644 sources/shiboken2/tests/libsmart/smart.h create mode 100644 sources/shiboken2/tests/minimalbinding/CMakeLists.txt create mode 100644 sources/shiboken2/tests/minimalbinding/global.h create mode 100644 sources/shiboken2/tests/minimalbinding/listuser_test.py create mode 100644 sources/shiboken2/tests/minimalbinding/minbool_test.py create mode 100644 sources/shiboken2/tests/minimalbinding/minimal-binding.txt.in create mode 100644 sources/shiboken2/tests/minimalbinding/obj_test.py create mode 100644 sources/shiboken2/tests/minimalbinding/typedef_test.py create mode 100644 sources/shiboken2/tests/minimalbinding/typesystem_minimal.xml create mode 100644 sources/shiboken2/tests/minimalbinding/val_test.py create mode 100644 sources/shiboken2/tests/otherbinding/CMakeLists.txt create mode 100644 sources/shiboken2/tests/otherbinding/collector_external_operator_test.py create mode 100755 sources/shiboken2/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py create mode 100755 sources/shiboken2/tests/otherbinding/extended_multiply_operator_test.py create mode 100644 sources/shiboken2/tests/otherbinding/global.h create mode 100644 sources/shiboken2/tests/otherbinding/module_reload_test.py create mode 100755 sources/shiboken2/tests/otherbinding/new_ctor_operator_test.py create mode 100644 sources/shiboken2/tests/otherbinding/objtypehashes_test.py create mode 100644 sources/shiboken2/tests/otherbinding/other-binding.txt.in create mode 100644 sources/shiboken2/tests/otherbinding/otherderived_test.py create mode 100644 sources/shiboken2/tests/otherbinding/test_module_template.py create mode 100644 sources/shiboken2/tests/otherbinding/typediscovery_test.py create mode 100644 sources/shiboken2/tests/otherbinding/typesystem_other.xml create mode 100755 sources/shiboken2/tests/otherbinding/usersprimitivefromothermodule_test.py create mode 100644 sources/shiboken2/tests/otherbinding/wrongctor_test.py create mode 100644 sources/shiboken2/tests/py3k.py create mode 100644 sources/shiboken2/tests/py3kcompat.py create mode 100644 sources/shiboken2/tests/samplebinding/CMakeLists.txt create mode 100644 sources/shiboken2/tests/samplebinding/__del___test.py create mode 100644 sources/shiboken2/tests/samplebinding/abstract_test.py create mode 100644 sources/shiboken2/tests/samplebinding/addedfunction_test.py create mode 100644 sources/shiboken2/tests/samplebinding/addedfunction_with_container_args_test.py create mode 100644 sources/shiboken2/tests/samplebinding/argumentmodifications_test.py create mode 100644 sources/shiboken2/tests/samplebinding/bug_554_test.py create mode 100644 sources/shiboken2/tests/samplebinding/bug_704_test.py create mode 100644 sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp create mode 100644 sources/shiboken2/tests/samplebinding/bytearray_test.py create mode 100644 sources/shiboken2/tests/samplebinding/child_return_test.py create mode 100644 sources/shiboken2/tests/samplebinding/class_fields_test.py create mode 100644 sources/shiboken2/tests/samplebinding/collector_test.py create mode 100644 sources/shiboken2/tests/samplebinding/complex_test.py create mode 100644 sources/shiboken2/tests/samplebinding/conversion_operator_test.py create mode 100644 sources/shiboken2/tests/samplebinding/copy_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ctorconvrule_test.py create mode 100644 sources/shiboken2/tests/samplebinding/cyclic_test.py create mode 100644 sources/shiboken2/tests/samplebinding/date_test.py create mode 100644 sources/shiboken2/tests/samplebinding/decisor_test.py create mode 100644 sources/shiboken2/tests/samplebinding/delete_test.py create mode 100644 sources/shiboken2/tests/samplebinding/deprecated_test.py create mode 100644 sources/shiboken2/tests/samplebinding/derived_test.py create mode 100644 sources/shiboken2/tests/samplebinding/duck_punching_test.py create mode 100644 sources/shiboken2/tests/samplebinding/echo_test.py create mode 100644 sources/shiboken2/tests/samplebinding/enum_test.py create mode 100644 sources/shiboken2/tests/samplebinding/enumfromremovednamespace_test.py create mode 100644 sources/shiboken2/tests/samplebinding/event_loop_call_virtual_test.py create mode 100644 sources/shiboken2/tests/samplebinding/event_loop_thread_test.py create mode 100644 sources/shiboken2/tests/samplebinding/filter_test.py create mode 100644 sources/shiboken2/tests/samplebinding/global.h create mode 100644 sources/shiboken2/tests/samplebinding/handleholder_test.py create mode 100644 sources/shiboken2/tests/samplebinding/hashabletype_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ignorederefop_test.py create mode 100644 sources/shiboken2/tests/samplebinding/implicitconv_numerical_test.py create mode 100644 sources/shiboken2/tests/samplebinding/implicitconv_test.py create mode 100755 sources/shiboken2/tests/samplebinding/inheritanceandscope_test.py create mode 100644 sources/shiboken2/tests/samplebinding/injectcode_test.py create mode 100644 sources/shiboken2/tests/samplebinding/innerclass_test.py create mode 100644 sources/shiboken2/tests/samplebinding/intlist_test.py create mode 100644 sources/shiboken2/tests/samplebinding/invalid_virtual_return_test.py create mode 100644 sources/shiboken2/tests/samplebinding/keep_reference_test.py create mode 100644 sources/shiboken2/tests/samplebinding/list_test.py create mode 100644 sources/shiboken2/tests/samplebinding/lock_test.py create mode 100644 sources/shiboken2/tests/samplebinding/map_test.py create mode 100644 sources/shiboken2/tests/samplebinding/metaclass_test.py create mode 100644 sources/shiboken2/tests/samplebinding/mi_virtual_methods_test.py create mode 100644 sources/shiboken2/tests/samplebinding/mixed_mi_test.py create mode 100644 sources/shiboken2/tests/samplebinding/modelindex_test.py create mode 100644 sources/shiboken2/tests/samplebinding/modelview_test.py create mode 100644 sources/shiboken2/tests/samplebinding/modifications_test.py create mode 100644 sources/shiboken2/tests/samplebinding/modified_constructor_test.py create mode 100644 sources/shiboken2/tests/samplebinding/modifiedvirtualmethods_test.py create mode 100644 sources/shiboken2/tests/samplebinding/multi_cpp_inheritance_test.py create mode 100644 sources/shiboken2/tests/samplebinding/multiple_derived_test.py create mode 100644 sources/shiboken2/tests/samplebinding/namespace_test.py create mode 100644 sources/shiboken2/tests/samplebinding/newdivision_test.py create mode 100644 sources/shiboken2/tests/samplebinding/nondefaultctor_test.py create mode 100644 sources/shiboken2/tests/samplebinding/nonzero_test.py create mode 100644 sources/shiboken2/tests/samplebinding/numericaltypedef_test.py create mode 100644 sources/shiboken2/tests/samplebinding/numpy_test.py create mode 100644 sources/shiboken2/tests/samplebinding/objecttype_test.py create mode 100755 sources/shiboken2/tests/samplebinding/objecttype_with_named_args_test.py create mode 100644 sources/shiboken2/tests/samplebinding/objecttypebyvalue_test.py create mode 100644 sources/shiboken2/tests/samplebinding/objecttypelayout_test.py create mode 100644 sources/shiboken2/tests/samplebinding/objecttypeoperators_test.py create mode 100644 sources/shiboken2/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py create mode 100644 sources/shiboken2/tests/samplebinding/oddbool_test.py create mode 100644 sources/shiboken2/tests/samplebinding/oldstyleclass_as_number_test.py create mode 100644 sources/shiboken2/tests/samplebinding/onlycopyclass_test.py create mode 100644 sources/shiboken2/tests/samplebinding/overflow_test.py create mode 100644 sources/shiboken2/tests/samplebinding/overload_sorting_test.py create mode 100644 sources/shiboken2/tests/samplebinding/overload_test.py create mode 100644 sources/shiboken2/tests/samplebinding/overloadwithdefault_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ownership_argument_invalidation_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ownership_delete_child_in_cpp_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ownership_delete_child_in_python_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ownership_delete_parent_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ownership_invalidate_after_use_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ownership_invalidate_child_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ownership_invalidate_parent_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ownership_reparenting_test.py create mode 100644 sources/shiboken2/tests/samplebinding/ownership_transference_test.py create mode 100644 sources/shiboken2/tests/samplebinding/pair_test.py create mode 100644 sources/shiboken2/tests/samplebinding/pen_test.py create mode 100644 sources/shiboken2/tests/samplebinding/point_test.py create mode 100644 sources/shiboken2/tests/samplebinding/pointerholder_test.py create mode 100644 sources/shiboken2/tests/samplebinding/pointf_test.py create mode 100644 sources/shiboken2/tests/samplebinding/primitivereferenceargument_test.py create mode 100644 sources/shiboken2/tests/samplebinding/privatector_test.py create mode 100644 sources/shiboken2/tests/samplebinding/privatedtor_test.py create mode 100644 sources/shiboken2/tests/samplebinding/protected_test.py create mode 100644 sources/shiboken2/tests/samplebinding/pstrlist_test.py create mode 100644 sources/shiboken2/tests/samplebinding/pystr_test.py create mode 100644 sources/shiboken2/tests/samplebinding/python_thread_test.py create mode 100644 sources/shiboken2/tests/samplebinding/receive_null_cstring_test.py create mode 100644 sources/shiboken2/tests/samplebinding/reference_test.py create mode 100644 sources/shiboken2/tests/samplebinding/referencetopointer_test.py create mode 100644 sources/shiboken2/tests/samplebinding/return_null_test.py create mode 100644 sources/shiboken2/tests/samplebinding/richcompare_test.py create mode 100644 sources/shiboken2/tests/samplebinding/sample-binding.txt.in create mode 100644 sources/shiboken2/tests/samplebinding/sample_test.py create mode 100644 sources/shiboken2/tests/samplebinding/simplefile_glue.cpp create mode 100644 sources/shiboken2/tests/samplebinding/simplefile_test.py create mode 100644 sources/shiboken2/tests/samplebinding/size_test.py create mode 100644 sources/shiboken2/tests/samplebinding/static_nonstatic_methods_test.py create mode 100644 sources/shiboken2/tests/samplebinding/str_test.py create mode 100644 sources/shiboken2/tests/samplebinding/strlist_test.py create mode 100644 sources/shiboken2/tests/samplebinding/templateinheritingclass_test.py create mode 100644 sources/shiboken2/tests/samplebinding/time_test.py create mode 100644 sources/shiboken2/tests/samplebinding/transform_test.py create mode 100644 sources/shiboken2/tests/samplebinding/typeconverters_test.py create mode 100644 sources/shiboken2/tests/samplebinding/typedealloc_test.py create mode 100644 sources/shiboken2/tests/samplebinding/typedtordoublefree_test.py create mode 100644 sources/shiboken2/tests/samplebinding/typesystem_sample.xml create mode 100644 sources/shiboken2/tests/samplebinding/unsafe_parent_test.py create mode 100644 sources/shiboken2/tests/samplebinding/useraddedctor_test.py create mode 100644 sources/shiboken2/tests/samplebinding/virtualdtor_test.py create mode 100644 sources/shiboken2/tests/samplebinding/virtualmethods_test.py create mode 100644 sources/shiboken2/tests/samplebinding/visibilitychange_test.py create mode 100644 sources/shiboken2/tests/samplebinding/voidholder_test.py create mode 100644 sources/shiboken2/tests/samplebinding/weakref_test.py create mode 100644 sources/shiboken2/tests/samplebinding/writableclassdict_test.py create mode 100644 sources/shiboken2/tests/shibokenmodule/module_test.py create mode 100644 sources/shiboken2/tests/smartbinding/CMakeLists.txt create mode 100644 sources/shiboken2/tests/smartbinding/global.h create mode 100644 sources/shiboken2/tests/smartbinding/smart-binding.txt.in create mode 100644 sources/shiboken2/tests/smartbinding/smart_pointer_test.py create mode 100644 sources/shiboken2/tests/smartbinding/typesystem_smart.xml create mode 100644 sources/shiboken2/tests/sphinxtabletest.cpp create mode 100644 sources/shiboken2/tests/sphinxtabletest.h create mode 100644 sources/shiboken2/tests/test_generator/CMakeLists.txt create mode 100644 sources/shiboken2/tests/test_generator/dummygenerator.cpp create mode 100644 sources/shiboken2/tests/test_generator/dummygenerator.h create mode 100644 sources/shiboken2/tests/test_generator/dummygentest-project.txt.in create mode 100644 sources/shiboken2/tests/test_generator/dummygentest.cpp create mode 100644 sources/shiboken2/tests/test_generator/dummygentest.h create mode 100644 sources/shiboken2/tests/test_generator/dummygentestconfig.h.in create mode 100644 sources/shiboken2/tests/test_generator/main.cpp create mode 100644 sources/shiboken2/tests/test_generator/run_test.cmake create mode 100644 sources/shiboken2/tests/test_generator/test_global.h create mode 100644 sources/shiboken2/tests/test_generator/test_typesystem.xml (limited to 'sources') diff --git a/sources/shiboken2/.gitattributes b/sources/shiboken2/.gitattributes new file mode 100644 index 000000000..adbe833c1 --- /dev/null +++ b/sources/shiboken2/.gitattributes @@ -0,0 +1,2 @@ +.gitignore export-ignore +.gitattributes export-ignore diff --git a/sources/shiboken2/.gitignore b/sources/shiboken2/.gitignore new file mode 100644 index 000000000..adb1e4594 --- /dev/null +++ b/sources/shiboken2/.gitignore @@ -0,0 +1,8 @@ +build +.kdev4 +*.log +*.pyc +*.o +*.so +.*.swp +*.kdev4 diff --git a/sources/shiboken2/AUTHORS b/sources/shiboken2/AUTHORS new file mode 100644 index 000000000..4bb16b2dd --- /dev/null +++ b/sources/shiboken2/AUTHORS @@ -0,0 +1,12 @@ +John Cummings +John Ehresman +Roman Lacko +Matthew Woehlke +Anderson Lizardo +Bruno Araujo +Hugo Parente Lima +Lauro Moura +Luciano Wolf +Marcelo Lira +Renato Araujo Oliveira Filho + diff --git a/sources/shiboken2/ApiExtractor/AUTHORS b/sources/shiboken2/ApiExtractor/AUTHORS new file mode 100644 index 000000000..6e802fb53 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/AUTHORS @@ -0,0 +1,8 @@ +Anderson Lizardo +Bruno Araujo +Hugo Parente Lima +Lauro Moura +Luciano Wolf +Marcelo Lira +Renato Araujo Oliveira Filho + diff --git a/sources/shiboken2/ApiExtractor/CMakeLists.txt b/sources/shiboken2/ApiExtractor/CMakeLists.txt new file mode 100644 index 000000000..6cb3e0185 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/CMakeLists.txt @@ -0,0 +1,90 @@ +project(apiextractor) + +find_package(LibXml2 2.6.32) +find_package(LibXslt 1.1.19) + +option(DISABLE_DOCSTRINGS "Disable documentation extraction." FALSE) + +if (NOT DISABLE_DOCSTRINGS) + if (NOT LIBXSLT_FOUND OR NOT LIBXML2_FOUND) + set(DISABLE_DOCSTRINGS TRUE CACHE BOOL "Disable doc strings" PARENT_SCOPE) + set(DISABLE_DOCSTRINGS TRUE) + message(WARNING "libxslt and/or libxml not found, disabling support for doc strings!") + endif() +endif() + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +if(BUILD_TESTS) + set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/tests) +endif () + +set(QT_USE_QTCORE 1) +set(QT_USE_QTXML 1) +add_definitions(-DQT_PLUGIN) +add_definitions(-DQT_SHARED) +add_definitions(-DRXX_ALLOCATOR_INIT_0) + +set(apiextractor_SRC +apiextractor.cpp +abstractmetabuilder.cpp +abstractmetalang.cpp +fileout.cpp +graph.cpp +reporthandler.cpp +typeparser.cpp +typesystem.cpp +include.cpp +typedatabase.cpp +# Clang +clangparser/compilersupport.cpp +clangparser/clangparser.cpp +clangparser/clangbuilder.cpp +clangparser/clangdebugutils.cpp +clangparser/clangutils.cpp +# Old parser +parser/codemodel.cpp +) + +set(APIEXTRACTOR_EXTRA_INCLUDES ${CLANG_EXTRA_INCLUDES}) +set(APIEXTRACTOR_EXTRA_LIBRARIES ${CLANG_EXTRA_LIBRARIES}) + +if (NOT DISABLE_DOCSTRINGS) + set(apiextractor_SRC + ${apiextractor_SRC} + docparser.cpp + doxygenparser.cpp + qtdocparser.cpp + ) + set(APIEXTRACTOR_EXTRA_INCLUDES ${APIEXTRACTOR_EXTRA_INCLUDES} ${LIBXSLT_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) + set(APIEXTRACTOR_EXTRA_LIBRARIES ${APIEXTRACTOR_EXTRA_LIBRARIES} ${LIBXSLT_LIBRARIES} ${LIBXML2_LIBRARIES}) +endif() + +set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE) + +set(CMAKE_AUTOMOC ON) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/parser + ${CMAKE_CURRENT_SOURCE_DIR}/parser/rpp + ${APIEXTRACTOR_EXTRA_INCLUDES} + ${Qt5Core_INCLUDE_DIRS} + ${Qt5Xml_INCLUDE_DIRS} + ) + +add_library(apiextractor STATIC ${apiextractor_SRC} ${apiextractor_RCCS_SRC}) +target_link_libraries(apiextractor + ${Qt5Xml_LIBRARIES} + ${Qt5XmlPatterns_LIBRARIES} + ${APIEXTRACTOR_EXTRA_LIBRARIES} + ) + +set_property(TARGET apiextractor PROPERTY CXX_STANDARD 11) + +if (BUILD_TESTS) + enable_testing() + add_subdirectory(tests) +endif() diff --git a/sources/shiboken2/ApiExtractor/COPYING b/sources/shiboken2/ApiExtractor/COPYING new file mode 100644 index 000000000..4ccd71466 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/COPYING @@ -0,0 +1,342 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +------------------------------------------------------------------------- diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp new file mode 100644 index 000000000..3b2ecf8e1 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -0,0 +1,3459 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "abstractmetabuilder_p.h" +#include "reporthandler.h" +#include "typedatabase.h" + +#include +#include + +#include "parser/codemodel.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "graph.h" +#include + +static inline QString colonColon() { return QStringLiteral("::"); } + +static QString stripTemplateArgs(const QString &name) +{ + int pos = name.indexOf(QLatin1Char('<')); + return pos < 0 ? name : name.left(pos); +} + +static QStringList parseTemplateType(const QString& name) { + int n = name.indexOf(QLatin1Char('<')); + if (n <= 0) { + // If name starts with '<' or contains an unmatched (i.e. any) '>', we + // reject it + if (n == 0 || name.count(QLatin1Char('>'))) + return QStringList(); + // Doesn't look like a template instantiation; just return the name + return QStringList() << name; + } + + // Split the type name into the template name and template arguments; the + // part before the opening '<' is the template name + // + // Example: + // "foo, D>" -> ( "foo", "A", "bar", "D" ) + QStringList result; + result << name.left(n).trimmed(); + + // Extract template arguments + int i, depth = 1; + const int l = name.length(); + for (i = n + 1; i < l; ++i) { + // Consume balanced '<'/'>' within a single argument so that we won't + // split on ',' as part of a single argument which is itself a + // multi-argument template type + if (name[i] == QLatin1Char('<')) { + ++depth; + } else if (name[i] == QLatin1Char('>')) { + if (--depth == 0) + break; + } else if (name[i] == QLatin1Char(',') && depth == 1) { + // Encountered ',' in template argument list that is not within + // another template name; add current argument to result and start + // working on the next argument + result << name.mid(n + 1, i - n - 1).trimmed(); + n = i; + } + } + if (i >= l) // arg list not closed + return QStringList(); + if (i + 1 < l) // arg list closed before end of name + return QStringList(); + + // Add final argument and return result + result << name.mid(n + 1, i - n - 1).trimmed(); + return result; +} + +AbstractMetaBuilderPrivate::AbstractMetaBuilderPrivate() : m_currentClass(0), + m_logDirectory(QLatin1String(".") + QDir::separator()) +{ +} + +AbstractMetaBuilderPrivate::~AbstractMetaBuilderPrivate() +{ + qDeleteAll(m_globalEnums); + qDeleteAll(m_globalFunctions); + qDeleteAll(m_templates); + qDeleteAll(m_smartPointers); + qDeleteAll(m_metaClasses); +} + +AbstractMetaBuilder::AbstractMetaBuilder() : d(new AbstractMetaBuilderPrivate) +{ + d->q = this; +} + +AbstractMetaBuilder::~AbstractMetaBuilder() +{ + delete d; +} + +AbstractMetaClassList AbstractMetaBuilder::classes() const +{ + return d->m_metaClasses; +} + +AbstractMetaClassList AbstractMetaBuilder::templates() const +{ + return d->m_templates; +} + +AbstractMetaClassList AbstractMetaBuilder::smartPointers() const +{ + return d->m_smartPointers; +} + +AbstractMetaFunctionList AbstractMetaBuilder::globalFunctions() const +{ + return d->m_globalFunctions; +} + +AbstractMetaEnumList AbstractMetaBuilder::globalEnums() const +{ + return d->m_globalEnums; +} + +QSet AbstractMetaBuilder::qtMetaTypeDeclaredTypeNames() const +{ + return d->m_qmetatypeDeclaredTypenames; +} + +void AbstractMetaBuilderPrivate::checkFunctionModifications() +{ + TypeDatabase *types = TypeDatabase::instance(); + const SingleTypeEntryHash entryHash = types->entries(); + + for (SingleTypeEntryHash::const_iterator it = entryHash.cbegin(), end = entryHash.cend(); it != end; ++it) { + const TypeEntry *entry = it.value(); + if (!entry) + continue; + if (!entry->isComplex() || entry->codeGeneration() == TypeEntry::GenerateNothing) + continue; + + const ComplexTypeEntry* centry = static_cast(entry); + FunctionModificationList modifications = centry->functionModifications(); + + for (const FunctionModification &modification : qAsConst(modifications)) { + QString signature = modification.signature; + + QString name = signature.trimmed(); + name.truncate(name.indexOf(QLatin1Char('('))); + + AbstractMetaClass *clazz = AbstractMetaClass::findClass(m_metaClasses, centry->qualifiedCppName()); + if (!clazz) + continue; + + const AbstractMetaFunctionList functions = clazz->functions(); + bool found = false; + QStringList possibleSignatures; + for (AbstractMetaFunction *function : functions) { + if (function->minimalSignature() == signature && function->implementingClass() == clazz) { + found = true; + break; + } + + if (function->originalName() == name) { + possibleSignatures.append(function->minimalSignature() + QLatin1String(" in ") + + function->implementingClass()->name()); + } + } + + if (!found) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("signature '%1' for function modification in '%2' not found. Possible candidates: %3") + .arg(signature, clazz->qualifiedCppName(), possibleSignatures.join(QLatin1String(", "))); + } + } + } +} + +AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(ArgumentModelItem argument) +{ + AbstractMetaClass* returned = 0; + bool ok = false; + AbstractMetaType* type = translateType(argument->type(), &ok); + if (ok && type && type->typeEntry() && type->typeEntry()->isComplex()) { + const TypeEntry *entry = type->typeEntry(); + returned = AbstractMetaClass::findClass(m_metaClasses, entry->name()); + } + delete type; + return returned; +} + +AbstractMetaClass *AbstractMetaBuilder::createMetaClass() +{ + return new AbstractMetaClass(); +} + +AbstractMetaEnum *AbstractMetaBuilder::createMetaEnum() +{ + return new AbstractMetaEnum(); +} + +AbstractMetaEnumValue *AbstractMetaBuilder::createMetaEnumValue() +{ + return new AbstractMetaEnumValue(); +} + +AbstractMetaField *AbstractMetaBuilder::createMetaField() +{ + return new AbstractMetaField(); +} + +AbstractMetaFunction *AbstractMetaBuilder::createMetaFunction() +{ + return new AbstractMetaFunction(); +} + +AbstractMetaArgument *AbstractMetaBuilder::createMetaArgument() +{ + return new AbstractMetaArgument(); +} + +AbstractMetaType *AbstractMetaBuilder::createMetaType() +{ + return new AbstractMetaType(); +} + +/** + * Checks the argument of a hash function and flags the type if it is a complex type + */ +void AbstractMetaBuilderPrivate::registerHashFunction(FunctionModelItem function_item) +{ + ArgumentList arguments = function_item->arguments(); + if (arguments.size() == 1) { + if (AbstractMetaClass *cls = argumentToClass(arguments.at(0))) + cls->setHasHashFunction(true); + } +} + +/** + * Check if a class has a debug stream operator that can be used as toString + */ + +void AbstractMetaBuilderPrivate::registerToStringCapability(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); + if (AbstractMetaClass *cls = argumentToClass(arg)) { + if (arg->type().indirections() < 2) + cls->setToStringCapability(true); + } + } + } +} + +void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item) +{ + if (item->accessPolicy() != CodeModel::Public) + return; + + ArgumentList arguments = item->arguments(); + AbstractMetaClass* baseoperandClass; + bool firstArgumentIsSelf = true; + bool unaryOperator = false; + + baseoperandClass = argumentToClass(arguments.at(0)); + + if (arguments.size() == 1) { + unaryOperator = true; + } else if (!baseoperandClass + || !(baseoperandClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)) { + baseoperandClass = argumentToClass(arguments.at(1)); + firstArgumentIsSelf = false; + } else { + bool ok; + AbstractMetaType* type = translateType(item->type(), &ok); + const TypeEntry* retType = ok ? type->typeEntry() : 0; + AbstractMetaClass* otherArgClass = argumentToClass(arguments.at(1)); + if (otherArgClass && retType + && (retType->isValue() || retType->isObject()) + && retType != baseoperandClass->typeEntry() + && retType == otherArgClass->typeEntry()) { + baseoperandClass = AbstractMetaClass::findClass(m_metaClasses, retType); + firstArgumentIsSelf = false; + } + delete type; + } + + if (baseoperandClass) { + AbstractMetaClass* oldCurrentClass = m_currentClass; + m_currentClass = baseoperandClass; + AbstractMetaFunction *metaFunction = traverseFunction(item); + if (metaFunction && !metaFunction->isInvalid()) { + // Strip away first argument, since that is the containing object + AbstractMetaArgumentList arguments = metaFunction->arguments(); + if (firstArgumentIsSelf || unaryOperator) { + AbstractMetaArgument* first = arguments.takeFirst(); + if (!unaryOperator && first->type()->indirections()) + metaFunction->setPointerOperator(true); + delete first; + metaFunction->setArguments(arguments); + } else { + // If the operator method is not unary and the first operator is + // not of the same type of its owning class we suppose that it + // must be an reverse operator (e.g. CLASS::operator(TYPE, CLASS)). + // All operator overloads that operate over a class are already + // being added as member functions of that class by the API Extractor. + AbstractMetaArgument* last = arguments.takeLast(); + if (last->type()->indirections()) + metaFunction->setPointerOperator(true); + delete last; + + metaFunction->setArguments(arguments); + metaFunction->setReverseOperator(true); + } + metaFunction->setFunctionType(AbstractMetaFunction::NormalFunction); + metaFunction->setVisibility(AbstractMetaFunction::Public); + metaFunction->setOriginalAttributes(metaFunction->attributes()); + setupFunctionDefaults(metaFunction, baseoperandClass); + baseoperandClass->addFunction(metaFunction); + Q_ASSERT(!metaFunction->wasPrivate()); + } else if (metaFunction) { + delete metaFunction; + } + + m_currentClass = oldCurrentClass; + } +} + +void AbstractMetaBuilderPrivate::traverseStreamOperator(FunctionModelItem item) +{ + ArgumentList arguments = item->arguments(); + if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) { + AbstractMetaClass* streamClass = argumentToClass(arguments.at(0)); + AbstractMetaClass* streamedClass = argumentToClass(arguments.at(1)); + + if (streamClass && streamedClass && (streamClass->isStream())) { + AbstractMetaClass *oldCurrentClass = m_currentClass; + m_currentClass = streamedClass; + AbstractMetaFunction *streamFunction = traverseFunction(item); + + if (streamFunction && !streamFunction->isInvalid()) { + QString name = item->name(); + streamFunction->setFunctionType(AbstractMetaFunction::GlobalScopeFunction); + // Strip first argument, since that is the containing object + AbstractMetaArgumentList arguments = streamFunction->arguments(); + if (!streamClass->typeEntry()->generateCode()) + delete arguments.takeLast(); + else + delete arguments.takeFirst(); + + streamFunction->setArguments(arguments); + + *streamFunction += AbstractMetaAttributes::Final; + *streamFunction += AbstractMetaAttributes::Public; + streamFunction->setOriginalAttributes(streamFunction->attributes()); + +// streamFunction->setType(0); + + AbstractMetaClass *funcClass; + + if (!streamClass->typeEntry()->generateCode()) { + AbstractMetaArgumentList reverseArgs = reverseList(streamFunction->arguments()); + streamFunction->setArguments(reverseArgs); + streamFunction->setReverseOperator(true); + funcClass = streamedClass; + } else { + funcClass = streamClass; + } + + setupFunctionDefaults(streamFunction, funcClass); + funcClass->addFunction(streamFunction); + if (funcClass == streamClass) + funcClass->typeEntry()->addExtraInclude(streamedClass->typeEntry()->include()); + else + funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include()); + + m_currentClass = oldCurrentClass; + } else if (streamFunction) { + delete streamFunction; + } + + } + } +} + +void AbstractMetaBuilderPrivate::fixQObjectForScope(const FileModelItem &dom, + const TypeDatabase *types, + const NamespaceModelItem &scope) +{ + const ClassList &scopeClasses = scope->classes(); + for (const ClassModelItem &item : scopeClasses) { + QString qualifiedName = item->qualifiedName().join(colonColon()); + TypeEntry* entry = types->findType(qualifiedName); + if (entry) { + if (isQObject(dom, qualifiedName) && entry->isComplex()) + ((ComplexTypeEntry*) entry)->setQObject(true); + } + } + + const NamespaceList &namespaces = scope->namespaces(); + for (const NamespaceModelItem &n : namespaces) { + if (scope != n) + fixQObjectForScope(dom, types, n); + } +} + +void AbstractMetaBuilderPrivate::sortLists() +{ + for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) + cls->sortFunctions(); +} + +FileModelItem AbstractMetaBuilderPrivate::buildDom(const QByteArrayList &arguments, + unsigned clangFlags) +{ + clang::Builder builder; + FileModelItem result = clang::parse(arguments, clangFlags, builder) + ? builder.dom() : FileModelItem(); + const clang::BaseVisitor::Diagnostics &diagnostics = builder.diagnostics(); + if (const int diagnosticsCount = diagnostics.size()) { + QDebug d = qWarning(); + d.nospace(); + d.noquote(); + d << "Clang: " << diagnosticsCount << " diagnostic messages:\n"; + for (int i = 0; i < diagnosticsCount; ++i) + d << " " << diagnostics.at(i) << '\n'; + } + return result; +} + +void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) +{ + const TypeDatabase *types = TypeDatabase::instance(); + + pushScope(dom); + + // fix up QObject's in the type system.. + fixQObjectForScope(dom, types, dom); + + // Start the generation... + 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); + } + + // 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...")); + AbstractMetaEnum *metaEnum = traverseEnum(item, 0, QSet()); + if (metaEnum) { + if (metaEnum->typeEntry()->generateCode()) + m_globalEnums << metaEnum; + } + } + + const QSet &namespaceTypeValues = dom->uniqueNamespaces(); + ReportHandler::setProgressReference(namespaceTypeValues); + for (NamespaceModelItem item : namespaceTypeValues) { + ReportHandler::progress(QLatin1String("Generating namespace model...")); + AbstractMetaClass *metaClass = traverseNamespace(dom, item); + if (metaClass) + m_metaClasses << metaClass; + } + + // Go through all typedefs to see if we have defined any + // specific typedefs to be used as classes. + 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); + } + + figureOutEnumValues(); + + for (const ClassModelItem &item : typeValues) + traverseClassMembers(item); + + for (const NamespaceModelItem &item : namespaceTypeValues) + traverseNamespaceMembers(item); + + // Global functions + const FunctionList &functions = dom->functions(); + for (const FunctionModelItem &func : functions) { + if (func->accessPolicy() != CodeModel::Public || func->name().startsWith(QLatin1String("operator"))) + continue; + + FunctionTypeEntry* funcEntry = types->findFunctionType(func->name()); + if (!funcEntry || !funcEntry->generateCode()) + continue; + + AbstractMetaFunction* metaFunc = traverseFunction(func); + if (!metaFunc) + continue; + + if (!funcEntry->hasSignature(metaFunc->minimalSignature())) { + delete metaFunc; + continue; + } + + applyFunctionModifications(metaFunc); + + setInclude(funcEntry, func->fileName()); + if (metaFunc->typeEntry()) + delete metaFunc->typeEntry(); + + metaFunc->setTypeEntry(funcEntry); + m_globalFunctions << metaFunc; + } + + ReportHandler::setProgressReference(m_metaClasses); + for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { + ReportHandler::progress(QLatin1String("Fixing class inheritance...")); + if (!cls->isInterface() && !cls->isNamespace()) + setupInheritance(cls); + } + + ReportHandler::setProgressReference(m_metaClasses); + for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { + ReportHandler::progress(QLatin1String("Detecting inconsistencies in class model...")); + cls->fixFunctions(); + + if (!cls->typeEntry()) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("class '%1' does not have an entry in the type system") + .arg(cls->name()); + } else { + bool couldAddDefaultCtors = !cls->isFinalInCpp() && !cls->isInterface() && !cls->isNamespace(); + if (couldAddDefaultCtors) { + if (!cls->hasConstructors()) + cls->addDefaultConstructor(); + if (cls->typeEntry()->isValue() && !cls->isAbstract() && !cls->hasCopyConstructor()) + cls->addDefaultCopyConstructor(ancestorHasPrivateCopyConstructor(cls)); + } + } + + 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; + + if ((entry->isValue() || entry->isObject()) + && !entry->isString() + && !entry->isChar() + && !entry->isContainer() + && !entry->isCustom() + && !entry->isVariant() + && !AbstractMetaClass::findClass(m_metaClasses, entry->qualifiedCppName())) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("type '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.") + .arg(entry->qualifiedCppName()); + } else if (entry->generateCode() && entry->type() == TypeEntry::FunctionType) { + const FunctionTypeEntry* fte = static_cast(entry); + const QStringList &signatures = fte->signatures(); + for (const QString &signature : signatures) { + bool ok = false; + for (AbstractMetaFunction* func : qAsConst(m_globalFunctions)) { + if (signature == func->minimalSignature()) { + ok = true; + break; + } + } + if (!ok) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("Global function '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.") + .arg(signature); + } + } + } else if (entry->isEnum()) { + const QString name = ((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; + } + } + } + if (!enumFound) { + entry->setCodeGeneration(TypeEntry::GenerateNothing); + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("enum '%1' is specified in typesystem, but not declared") + .arg(entry->qualifiedCppName()); + } + + } + } + } + + { + const FunctionList &hashFunctions = dom->findFunctions(QLatin1String("qHash")); + for (const FunctionModelItem &item : hashFunctions) + registerHashFunction(item); + } + + { + const FunctionList &streamOps = dom->findFunctions(QLatin1String("operator<<")); + for (const FunctionModelItem &item : streamOps) + registerToStringCapability(item); + } + + { + FunctionList binaryOperators = dom->findFunctions(QStringLiteral("operator==")); + binaryOperators.append(dom->findFunctions(QStringLiteral("operator!="))); + binaryOperators.append(dom->findFunctions(QStringLiteral("operator<="))); + binaryOperators.append(dom->findFunctions(QStringLiteral("operator>="))); + binaryOperators.append(dom->findFunctions(QStringLiteral("operator<"))); + binaryOperators.append(dom->findFunctions(QStringLiteral("operator+"))); + binaryOperators.append(dom->findFunctions(QStringLiteral("operator/"))); + // Filter binary operators, skipping for example + // class Iterator { ... Value *operator*() ... }; + const FunctionList potentiallyBinaryOperators = + dom->findFunctions(QStringLiteral("operator*")) + + dom->findFunctions(QStringLiteral("operator&")); + for (const FunctionModelItem &item : potentiallyBinaryOperators) { + if (!item->arguments().isEmpty()) + binaryOperators.append(item); + } + binaryOperators.append(dom->findFunctions(QStringLiteral("operator-"))); + binaryOperators.append(dom->findFunctions(QStringLiteral("operator&"))); + binaryOperators.append(dom->findFunctions(QStringLiteral("operator|"))); + binaryOperators.append(dom->findFunctions(QStringLiteral("operator^"))); + binaryOperators.append(dom->findFunctions(QStringLiteral("operator~"))); + binaryOperators.append(dom->findFunctions(QStringLiteral("operator>"))); + + for (const FunctionModelItem &item : qAsConst(binaryOperators)) + traverseOperatorFunction(item); + } + + { + const FunctionList streamOperators = dom->findFunctions(QLatin1String("operator<<")) + + dom->findFunctions(QLatin1String("operator>>")); + for (const FunctionModelItem &item : streamOperators) + traverseStreamOperator(item); + } + + figureOutDefaultEnumArguments(); + checkFunctionModifications(); + + // sort all classes topologically + m_metaClasses = classesTopologicalSorted(); + + for (AbstractMetaClass* cls : qAsConst(m_metaClasses)) { +// setupEquals(cls); +// setupComparable(cls); + setupClonable(cls); + setupExternalConversion(cls); + + // sort all inner classes topologically + if (!cls->typeEntry()->codeGeneration() || cls->innerClasses().size() < 2) + continue; + + cls->setInnerClasses(classesTopologicalSorted(cls)); + } + + dumpLog(); + + sortLists(); + + m_currentClass = 0; + + // Functions added to the module on the type system. + const AddedFunctionList &globalUserFunctions = types->globalUserFunctions(); + for (const AddedFunction &addedFunc : globalUserFunctions) { + AbstractMetaFunction* metaFunc = traverseFunction(addedFunc); + metaFunc->setFunctionType(AbstractMetaFunction::NormalFunction); + m_globalFunctions << metaFunc; + } + + std::puts(""); +} + +bool AbstractMetaBuilder::build(const QByteArrayList &arguments, unsigned clangFlags) +{ + const FileModelItem dom = d->buildDom(arguments, clangFlags); + if (dom.isNull()) + return false; + if (ReportHandler::isDebug(ReportHandler::MediumDebug)) + qCDebug(lcShiboken) << dom.data(); + d->traverseDom(dom); + return true; +} + +void AbstractMetaBuilder::setLogDirectory(const QString& logDir) +{ + d->m_logDirectory = logDir; + if (!d->m_logDirectory.endsWith(QDir::separator())) + d->m_logDirectory.append(QDir::separator()); +} + +void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls) +{ + if (!cls) + return; + + cls->setOriginalAttributes(cls->attributes()); + if (cls->typeEntry()->isContainer()) { + m_templates << cls; + } else if (cls->typeEntry()->isSmartPointer()) { + m_smartPointers << cls; + } else { + m_metaClasses << cls; + if (cls->typeEntry()->designatedInterface()) { + AbstractMetaClass* interface = cls->extractInterface(); + m_metaClasses << interface; + if (ReportHandler::isDebug(ReportHandler::SparseDebug)) + qCDebug(lcShiboken) << QStringLiteral(" -> interface '%1'").arg(interface->name()); + } + } +} + +AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModelItem &dom, + const NamespaceModelItem &namespaceItem) +{ + QString namespaceName = + (!m_namespacePrefix.isEmpty() ? m_namespacePrefix + colonColon() : QString()) + + namespaceItem->name(); + NamespaceTypeEntry *type = TypeDatabase::instance()->findNamespaceType(namespaceName); + + if (TypeDatabase::instance()->isClassRejected(namespaceName)) { + m_rejectedClasses.insert(namespaceName, AbstractMetaBuilder::GenerationDisabled); + return 0; + } + + if (!type) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("namespace '%1' does not have a type entry").arg(namespaceName); + return 0; + } + + AbstractMetaClass* metaClass = q->createMetaClass(); + metaClass->setTypeEntry(type); + + *metaClass += AbstractMetaAttributes::Public; + + m_currentClass = metaClass; + + if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { + qCDebug(lcShiboken) + << QStringLiteral("namespace '%1.%2'").arg(metaClass->package(), namespaceItem->name()); + } + + traverseEnums(namespaceItem, metaClass, namespaceItem->enumsDeclarations()); + + pushScope(namespaceItem); + m_namespacePrefix = currentScope()->qualifiedName().join(colonColon()); + + const ClassList &classes = namespaceItem->classes(); + for (const ClassModelItem &cls : classes) { + AbstractMetaClass* mjc = traverseClass(dom, cls); + if (mjc) { + metaClass->addInnerClass(mjc); + mjc->setEnclosingClass(metaClass); + addAbstractMetaClass(mjc); + } + } + + // Go through all typedefs to see if we have defined any + // specific typedefs to be used as classes. + const TypeDefList typeDefs = namespaceItem->typeDefs(); + for (const TypeDefModelItem &typeDef : typeDefs) { + AbstractMetaClass *cls = traverseTypeDef(dom, typeDef); + if (cls) { + metaClass->addInnerClass(cls); + cls->setEnclosingClass(metaClass); + addAbstractMetaClass(cls); + } + } + + // Traverse namespaces recursively + const QSet &innerNamespaces = namespaceItem->uniqueNamespaces(); + for (const NamespaceModelItem &ni : innerNamespaces) { + AbstractMetaClass* mjc = traverseNamespace(dom, ni); + if (mjc) { + metaClass->addInnerClass(mjc); + mjc->setEnclosingClass(metaClass); + addAbstractMetaClass(mjc); + } + } + + m_currentClass = 0; + + popScope(); + m_namespacePrefix = currentScope()->qualifiedName().join(colonColon()); + + if (!type->include().isValid()) + setInclude(type, namespaceItem->fileName()); + + return metaClass; +} + +struct Operator +{ + enum Type { Complement, Plus, ShiftRight, ShiftLeft, None }; + + Operator() : type(None) {} + + int calculate(int x) + { + switch (type) { + case Complement: return ~value; + case Plus: return x + value; + case ShiftRight: return x >> value; + case ShiftLeft: return x << value; + case None: return x; + } + return x; + } + + Type type; + int value; +}; + + + +Operator findOperator(QString* s) +{ + const char *names[] = { + "~", + "+", + ">>", + "<<" + }; + + for (int i = 0; i < Operator::None; ++i) { + QString name = QLatin1String(names[i]); + QString str = *s; + int splitPoint = str.indexOf(name); + if (splitPoint > -1) { + bool ok; + QString right = str.mid(splitPoint + name.length()); + Operator op; + + op.value = right.toInt(&ok); + if (!ok && right.length() > 0 && right.at(right.length() - 1).toLower() == QLatin1Char('u')) + op.value = right.left(right.length() - 1).toUInt(&ok, 0); + + if (ok) { + op.type = Operator::Type(i); + if (splitPoint > 0) + *s = str.left(splitPoint).trimmed(); + else + *s = QString(); + return op; + } + } + } + return Operator(); +} + +int AbstractMetaBuilderPrivate::figureOutEnumValue(const QString &stringValue, + int oldValuevalue, + AbstractMetaEnum *metaEnum, + AbstractMetaFunction *metaFunction) +{ + if (stringValue.isEmpty()) + return oldValuevalue; + + QStringList stringValues = stringValue.split(QLatin1Char('|')); + + int returnValue = 0; + + bool matched = false; + + for (int i = 0; i < stringValues.size(); ++i) { + QString s = stringValues.at(i).trimmed(); + + bool ok; + int v; + + Operator op = findOperator(&s); + + if (s.length() > 0 && s.at(0) == QLatin1Char('0')) + v = s.toUInt(&ok, 0); + else if (s.length() > 0 && s.at(s.length() - 1).toLower() == QLatin1Char('u')) + v = s.left(s.length() - 1).toUInt(&ok, 0); + else + v = s.toInt(&ok); + + if (ok || s.isEmpty()) { + matched = true; + } else if (m_enumValues.contains(s)) { + v = m_enumValues[s]->value(); + matched = true; + } else { + if (metaEnum) { + v = findOutValueFromString(s, matched); + if (!matched) { + QString enclosingClass = QString(metaEnum->enclosingClass() ? metaEnum->enclosingClass()->name() + colonColon() : QString()); + qCWarning(lcShiboken).noquote().nospace() + << "unhandled enum value: " << s << " in " + << enclosingClass << metaEnum->name() << " from header '" + << metaEnum->typeEntry()->include().name() << '\''; + } + } else { + qCWarning(lcShiboken) << "unhandled enum value: Unknown enum"; + } + } + + if (matched) + returnValue |= op.calculate(v); + } + + if (!matched) { + QString warn = QStringLiteral("unmatched enum %1").arg(stringValue); + + if (metaFunction) { + warn += QStringLiteral(" when parsing default value of '%1' in class '%2'") + .arg(metaFunction->name(), metaFunction->implementingClass()->name()); + } + warn += QLatin1String(" from header '") + metaEnum->typeEntry()->include().name() + + QLatin1Char('\''); + + qCWarning(lcShiboken).noquote().nospace() << warn; + returnValue = oldValuevalue; + } + + return returnValue; +} + +void AbstractMetaBuilderPrivate::figureOutEnumValuesForClass(AbstractMetaClass *metaClass, + QSet *classes) +{ + AbstractMetaClass* base = metaClass->baseClass(); + + if (base && !classes->contains(base)) + figureOutEnumValuesForClass(base, classes); + + if (classes->contains(metaClass)) + return; + + const AbstractMetaEnumList &enums = metaClass->enums(); + for (AbstractMetaEnum* e : enums) { + if (!e) { + qCWarning(lcShiboken).noquote().nospace() << "bad enum in class " << metaClass->name(); + continue; + } + AbstractMetaEnumValueList lst = e->values(); + int value = 0; + for (int i = 0; i < lst.size(); ++i) { + value = figureOutEnumValue(lst.at(i)->stringValue(), value, e); + lst.at(i)->setValue(value); + value++; + } + } + + *classes += metaClass; +} + + +void AbstractMetaBuilderPrivate::figureOutEnumValues() +{ + // Keep a set of classes that we already traversed. We use this to + // enforce that we traverse base classes prior to subclasses. + QSet classes; + for (AbstractMetaClass *c : qAsConst(m_metaClasses)) + figureOutEnumValuesForClass(c, &classes); + + for (AbstractMetaEnum* metaEnum : qAsConst(m_globalEnums)) { + AbstractMetaEnumValueList enumValues = metaEnum->values(); + int value = 0; + for (int i = 0; i < enumValues.size(); ++i) { + value = figureOutEnumValue(enumValues.at(i)->stringValue(), value, metaEnum); + enumValues.at(i)->setValue(value); + value++; + } + } +} + +void AbstractMetaBuilderPrivate::figureOutDefaultEnumArguments() +{ + for (AbstractMetaClass* metaClass : qAsConst(m_metaClasses)) { + const AbstractMetaFunctionList &functions = metaClass->functions(); + for (AbstractMetaFunction* metaFunction : functions) { + const AbstractMetaArgumentList &arguments = metaFunction->arguments(); + for (AbstractMetaArgument *arg : arguments) { + QString expr = arg->defaultValueExpression(); + if (expr.isEmpty()) + continue; + + if (!metaFunction->replacedDefaultExpression(metaFunction->implementingClass(), + arg->argumentIndex() + 1).isEmpty()) { + continue; + } + + arg->setDefaultValueExpression(expr); + } + } + } +} + + +AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumItem, + AbstractMetaClass *enclosing, + const QSet &enumsDeclarations) +{ + QString qualifiedName = enumItem->qualifiedName().join(colonColon()); + + TypeEntry* typeEntry = 0; + if (enumItem->accessPolicy() == CodeModel::Private) { + QStringList names = enumItem->qualifiedName(); + QString enumName = names.last(); + QString nspace; + if (names.size() > 1) + nspace = QStringList(names.mid(0, names.size() - 1)).join(colonColon()); + typeEntry = new EnumTypeEntry(nspace, enumName, 0); + TypeDatabase::instance()->addType(typeEntry); + } else if (!enumItem->isAnonymous()) { + typeEntry = TypeDatabase::instance()->findType(qualifiedName); + } else { + QStringList tmpQualifiedName = enumItem->qualifiedName(); + const EnumeratorList &enums = enumItem->enumerators(); + for (const EnumeratorModelItem& enumValue : enums) { + tmpQualifiedName.removeLast(); + tmpQualifiedName << enumValue->name(); + qualifiedName = tmpQualifiedName.join(colonColon()); + typeEntry = TypeDatabase::instance()->findType(qualifiedName); + if (typeEntry) + break; + } + } + + QString enumName = enumItem->name(); + + QString className; + if (m_currentClass) + className = m_currentClass->typeEntry()->qualifiedCppName(); + + QString rejectReason; + if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) { + if (typeEntry) + typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); + m_rejectedEnums.insert(qualifiedName + rejectReason, AbstractMetaBuilder::GenerationDisabled); + return 0; + } + + if (!typeEntry || !typeEntry->isEnum()) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("enum '%1' does not have a type entry or is not an enum") + .arg(qualifiedName); + m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem); + return 0; + } + + AbstractMetaEnum *metaEnum = q->createMetaEnum(); + if (enumsDeclarations.contains(qualifiedName) + || enumsDeclarations.contains(enumName)) { + metaEnum->setHasQEnumsDeclaration(true); + } + + metaEnum->setTypeEntry((EnumTypeEntry*) typeEntry); + switch (enumItem->accessPolicy()) { + case CodeModel::Public: + *metaEnum += AbstractMetaAttributes::Public; + break; + case CodeModel::Protected: + *metaEnum += AbstractMetaAttributes::Protected; + break; + case CodeModel::Private: + *metaEnum += AbstractMetaAttributes::Private; + typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); + break; + default: + break; + } + + if (ReportHandler::isDebug(ReportHandler::MediumDebug)) + qCDebug(lcShiboken) << " - traversing enum " << metaEnum->fullName(); + + const EnumeratorList &enums = enumItem->enumerators(); + for (const EnumeratorModelItem &value : enums) { + + AbstractMetaEnumValue *metaEnumValue = q->createMetaEnumValue(); + metaEnumValue->setName(value->name()); + // Deciding the enum value... + + metaEnumValue->setStringValue(value->value()); + metaEnum->addEnumValue(metaEnumValue); + + if (ReportHandler::isDebug(ReportHandler::FullDebug)) { + 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; + + if (!metaEnum->typeEntry()->include().isValid()) + setInclude(metaEnum->typeEntry(), enumItem->fileName()); + + metaEnum->setOriginalAttributes(metaEnum->attributes()); + + // Register all enum values on Type database + const EnumeratorList &enumerators = enumItem->enumerators(); + for (EnumeratorModelItem e : enumItem->enumerators()) { + QString name; + if (enclosing) { + name += enclosing->name(); + name += colonColon(); + } + name += e->name(); + EnumValueTypeEntry* enumValue = new EnumValueTypeEntry(name, e->value(), static_cast(typeEntry), typeEntry->version()); + TypeDatabase::instance()->addType(enumValue); + } + + return metaEnum; +} + +AbstractMetaClass* AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &dom, + const TypeDefModelItem &typeDef) +{ + TypeDatabase* types = TypeDatabase::instance(); + QString className = stripTemplateArgs(typeDef->name()); + + QString fullClassName = className; + // we have an inner class + if (m_currentClass) { + fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName()) + + colonColon() + fullClassName; + } + + // If this is the alias for a primitive type + // we store the aliased type on the alias + // TypeEntry + PrimitiveTypeEntry* ptype = types->findPrimitiveType(className); + if (ptype) { + QString typeDefName = typeDef->type().qualifiedName()[0]; + ptype->setReferencedTypeEntry(types->findPrimitiveType(typeDefName)); + return 0; + } + + + // If we haven't specified anything for the typedef, then we don't care + ComplexTypeEntry* type = types->findComplexType(fullClassName); + if (!type) + return 0; + + if (type->isObject()) + static_cast(type)->setQObject(isQObject(dom, stripTemplateArgs(typeDef->type().qualifiedName().join(colonColon())))); + + AbstractMetaClass *metaClass = q->createMetaClass(); + metaClass->setTypeDef(true); + metaClass->setTypeEntry(type); + metaClass->setBaseClassNames(QStringList() << typeDef->type().qualifiedName().join(colonColon())); + *metaClass += AbstractMetaAttributes::Public; + + // Set the default include file name + if (!type->include().isValid()) + setInclude(type, typeDef->fileName()); + + fillAddedFunctions(metaClass); + + return metaClass; +} + +AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom, + const ClassModelItem &classItem) +{ + QString className = stripTemplateArgs(classItem->name()); + QString fullClassName = className; + + // we have inner an class + if (m_currentClass) { + fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName()) + + colonColon() + fullClassName; + } + + ComplexTypeEntry* type = TypeDatabase::instance()->findComplexType(fullClassName); + AbstractMetaBuilder::RejectReason reason = AbstractMetaBuilder::NoReason; + + if (fullClassName == QLatin1String("QMetaTypeId")) { + // QtScript: record which types have been declared + int lpos = classItem->name().indexOf(QLatin1Char('<')); + int rpos = classItem->name().lastIndexOf(QLatin1Char('>')); + if ((lpos != -1) && (rpos != -1)) { + QString declaredTypename = classItem->name().mid(lpos + 1, rpos - lpos - 1); + m_qmetatypeDeclaredTypenames.insert(declaredTypename); + } + } + + if (TypeDatabase::instance()->isClassRejected(fullClassName)) { + reason = AbstractMetaBuilder::GenerationDisabled; + } else if (!type) { + TypeEntry *te = TypeDatabase::instance()->findType(fullClassName); + if (te && !te->isComplex()) + reason = AbstractMetaBuilder::RedefinedToNotClass; + else + reason = AbstractMetaBuilder::NotInTypeSystem; + } else if (type->codeGeneration() == TypeEntry::GenerateNothing) { + reason = AbstractMetaBuilder::GenerationDisabled; + } + if (reason != AbstractMetaBuilder::NoReason) { + m_rejectedClasses.insert(fullClassName, reason); + return 0; + } + + if (type->isObject()) + ((ObjectTypeEntry*)type)->setQObject(isQObject(dom, fullClassName)); + + AbstractMetaClass *metaClass = q->createMetaClass(); + metaClass->setTypeEntry(type); + metaClass->setBaseClassNames(classItem->baseClasses()); + *metaClass += AbstractMetaAttributes::Public; + if (type->stream()) + metaClass->setStream(true); + + AbstractMetaClass* oldCurrentClass = m_currentClass; + m_currentClass = metaClass; + + if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { + const QString message = type->isContainer() + ? QStringLiteral("container: '%1'").arg(fullClassName) + : QStringLiteral("class: '%1'").arg(metaClass->fullName()); + qCDebug(lcShiboken) << message; + } + + TemplateParameterList template_parameters = classItem->templateParameters(); + QVector template_args; + template_args.clear(); + for (int i = 0; i < template_parameters.size(); ++i) { + const TemplateParameterModelItem ¶m = template_parameters.at(i); + TemplateArgumentEntry *param_type = new TemplateArgumentEntry(param->name(), type->version()); + param_type->setOrdinal(i); + template_args.append(param_type); + } + metaClass->setTemplateArguments(template_args); + + parseQ_Property(metaClass, classItem->propertyDeclarations()); + + traverseEnums(classItem, metaClass, classItem->enumsDeclarations()); + + // Inner classes + { + const ClassList &innerClasses = classItem->classes(); + for (const ClassModelItem &ci : innerClasses) { + AbstractMetaClass *cl = traverseClass(dom, ci); + if (cl) { + cl->setEnclosingClass(metaClass); + metaClass->addInnerClass(cl); + m_metaClasses << cl; + } + } + + } + + // Go through all typedefs to see if we have defined any + // specific typedefs to be used as classes. + const TypeDefList typeDefs = classItem->typeDefs(); + for (const TypeDefModelItem &typeDef : typeDefs) { + AbstractMetaClass *cls = traverseTypeDef(dom, typeDef); + if (cls) { + cls->setEnclosingClass(metaClass); + addAbstractMetaClass(cls); + } + } + + + m_currentClass = oldCurrentClass; + + // Set the default include file name + if (!type->include().isValid()) + setInclude(type, classItem->fileName()); + + return metaClass; +} + +void AbstractMetaBuilderPrivate::traverseScopeMembers(ScopeModelItem item, + AbstractMetaClass *metaClass) +{ + // Classes/Namespace members + traverseFields(item, metaClass); + traverseFunctions(item, metaClass); + + // Inner classes + const ClassList &innerClasses = item->classes(); + for (const ClassModelItem& ci : innerClasses) + traverseClassMembers(ci); +} + +AbstractMetaClass* AbstractMetaBuilderPrivate::currentTraversedClass(ScopeModelItem item) +{ + QString className = stripTemplateArgs(item->name()); + QString fullClassName = className; + + // This is an inner class + if (m_currentClass) + fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName()) + colonColon() + fullClassName; + + AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, fullClassName); + if (!metaClass) + metaClass = AbstractMetaClass::findClass(m_templates, fullClassName); + + if (!metaClass) + metaClass = AbstractMetaClass::findClass(m_smartPointers, fullClassName); + return metaClass; +} + +void AbstractMetaBuilderPrivate::traverseClassMembers(ClassModelItem item) +{ + AbstractMetaClass* metaClass = currentTraversedClass(item); + if (!metaClass) + return; + + AbstractMetaClass* oldCurrentClass = m_currentClass; + m_currentClass = metaClass; + + // Class members + traverseScopeMembers(item, metaClass); + + m_currentClass = oldCurrentClass; +} + +void AbstractMetaBuilderPrivate::traverseNamespaceMembers(NamespaceModelItem item) +{ + AbstractMetaClass* metaClass = currentTraversedClass(item); + if (!metaClass) + return; + + AbstractMetaClass* oldCurrentClass = m_currentClass; + m_currentClass = metaClass; + + // Namespace members + traverseScopeMembers(item, metaClass); + + // Inner namespaces + const QSet &innerNamespaces = item->uniqueNamespaces(); + for (const NamespaceModelItem &ni : innerNamespaces) + traverseNamespaceMembers(ni); + + m_currentClass = oldCurrentClass; +} + +static inline QString fieldSignatureWithType(VariableModelItem field) +{ + return field->name() + QStringLiteral(" -> ") + field->type().toString(); +} + +static inline QString qualifiedFieldSignatureWithType(const QString &className, + VariableModelItem field) +{ + return className + colonColon() + fieldSignatureWithType(field); +} + +AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(VariableModelItem field, + const AbstractMetaClass *cls) +{ + QString fieldName = field->name(); + QString className = m_currentClass->typeEntry()->qualifiedCppName(); + + // Ignore friend decl. + if (field->isFriend()) + return 0; + + if (field->accessPolicy() == CodeModel::Private) + return 0; + + QString rejectReason; + if (TypeDatabase::instance()->isFieldRejected(className, fieldName, &rejectReason)) { + m_rejectedFields.insert(qualifiedFieldSignatureWithType(className, field) + rejectReason, + AbstractMetaBuilder::GenerationDisabled); + return 0; + } + + + AbstractMetaField *metaField = q->createMetaField(); + metaField->setName(fieldName); + metaField->setEnclosingClass(cls); + + bool ok; + TypeInfo fieldType = field->type(); + AbstractMetaType *metaType = translateType(fieldType, &ok); + + if (!metaType || !ok) { + const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(colonColon()); + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("skipping field '%1::%2' with unmatched type '%3'") + .arg(m_currentClass->name(), fieldName, type); + delete metaField; + return 0; + } + + metaField->setType(metaType); + + AbstractMetaAttributes::Attributes attr = 0; + if (field->isStatic()) + attr |= AbstractMetaAttributes::Static; + + CodeModel::AccessPolicy policy = field->accessPolicy(); + if (policy == CodeModel::Public) + attr |= AbstractMetaAttributes::Public; + else if (policy == CodeModel::Protected) + attr |= AbstractMetaAttributes::Protected; + else + attr |= AbstractMetaAttributes::Private; + metaField->setAttributes(attr); + + return metaField; +} + +void AbstractMetaBuilderPrivate::traverseFields(ScopeModelItem scope_item, + AbstractMetaClass *metaClass) +{ + const VariableList &variables = scope_item->variables(); + for (const VariableModelItem &field : variables) { + AbstractMetaField* metaField = traverseField(field, metaClass); + + if (metaField && !metaField->isModifiedRemoved()) { + metaField->setOriginalAttributes(metaField->attributes()); + metaClass->addField(metaField); + } + } +} + +void AbstractMetaBuilderPrivate::setupFunctionDefaults(AbstractMetaFunction *metaFunction, + AbstractMetaClass *metaClass) +{ + // Set the default value of the declaring class. This may be changed + // in fixFunctions later on + metaFunction->setDeclaringClass(metaClass); + + // Some of the queries below depend on the implementing class being set + // to function properly. Such as function modifications + metaFunction->setImplementingClass(metaClass); + + if (metaFunction->name() == QLatin1String("operator_equal")) + metaClass->setHasEqualsOperator(true); + + if (!metaFunction->isFinalInTargetLang() + && metaFunction->isRemovedFrom(metaClass, TypeSystem::TargetLangCode)) { + *metaFunction += AbstractMetaAttributes::FinalInCpp; + } +} + +void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction) +{ + if (!metaFunction->isConversionOperator()) + return; + + TypeDatabase* types = TypeDatabase::instance(); + static const QRegularExpression operatorRegExp(QStringLiteral("^operator ")); + Q_ASSERT(operatorRegExp.isValid()); + QString castTo = metaFunction->name().remove(operatorRegExp).trimmed(); + + if (castTo.endsWith(QLatin1Char('&'))) + castTo.chop(1); + if (castTo.startsWith(QLatin1String("const "))) + castTo.remove(0, 6); + + TypeEntry* retType = types->findType(castTo); + if (!retType) + return; + + AbstractMetaType* metaType = q->createMetaType(); + metaType->setTypeEntry(retType); + metaFunction->replaceType(metaType); +} + +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(); +} + +static bool _compareAbstractMetaFunctions(const AbstractMetaFunction* func, const AbstractMetaFunction* other) +{ + if (!func && !other) + return true; + if (!func || !other) + return false; + if (func->arguments().count() != other->arguments().count() + || func->isConstant() != other->isConstant() + || func->isStatic() != other->isStatic() + || !_compareAbstractMetaTypes(func->type(), other->type())) { + return false; + } + for (int i = 0; i < func->arguments().count(); ++i) { + if (!_compareAbstractMetaTypes(func->arguments().at(i)->type(), other->arguments().at(i)->type())) + return false; + } + return true; +} + +// Fix the arguments of template classes that take the class itself, for example: +// "QList(const QList &)" to "QList(const QList &)". +static bool _fixFunctionModelItemTypes(FunctionModelItem& function, const AbstractMetaClass* metaClass) +{ + const QVector &templateTypes = metaClass->templateArguments(); + if (templateTypes.isEmpty()) + return false; + + const QStringList classType = metaClass->typeEntry()->qualifiedCppName().split(colonColon()); + QStringList fixedClassType = classType; + fixedClassType.last().append(QLatin1Char('<')); + for (int i = 0, count = templateTypes.size(); i < count; ++i) { + if (i) + fixedClassType.last().append(QLatin1String(", ")); + fixedClassType.last().append(templateTypes.at(i)->qualifiedCppName()); + } + fixedClassType.last().append(QLatin1String(" >")); + + bool templateTypeFixed = false; + TypeInfo functionType = function->type(); + if (functionType.qualifiedName() == classType) { + templateTypeFixed = true; + functionType.setQualifiedName(fixedClassType); + function->setType(functionType); + } + + ArgumentList arguments = function->arguments(); + for (int i = 0; i < arguments.size(); ++i) { + ArgumentModelItem arg = arguments.at(i); + TypeInfo type = arg->type(); + if (type.qualifiedName() == classType) { + type.setQualifiedName(fixedClassType); + arg->setType(type); + templateTypeFixed = true; + } + } + return templateTypeFixed; +} + +AbstractMetaFunctionList AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem) +{ + AbstractMetaFunctionList result; + const FunctionList &scopeFunctionList = scopeItem->functions(); + result.reserve(scopeFunctionList.size()); + for (const FunctionModelItem &function : scopeFunctionList) { + if (AbstractMetaFunction *metaFunction = traverseFunction(function)) + result.append(metaFunction); + } + return result; +} + +// For template classes, entries with more specific types may exist from out-of- +// line definitions. If there is a declaration which matches it after fixing +// the parameters, remove it as duplicate. For example: +// template class Vector { public: +// Vector(const Vector &rhs); +// }; +// template class +// Vector::Vector(const Vector&) {} // More specific, remove declaration. + +class DuplicatingFunctionPredicate : public std::unary_function { +public: + explicit DuplicatingFunctionPredicate(const AbstractMetaFunction *f) : m_function(f) {} + + bool operator()(const AbstractMetaFunction *rhs) const + { + return rhs != m_function && rhs->name() == m_function->name() + && _compareAbstractMetaFunctions(m_function, rhs); + } + +private: + const AbstractMetaFunction *m_function; +}; + +AbstractMetaFunctionList AbstractMetaBuilderPrivate::templateClassFunctionList(const ScopeModelItem &scopeItem, + AbstractMetaClass *metaClass) +{ + AbstractMetaFunctionList result; + AbstractMetaFunctionList unchangedFunctions; + + const FunctionList &scopeFunctionList = scopeItem->functions(); + result.reserve(scopeFunctionList.size()); + unchangedFunctions.reserve(scopeFunctionList.size()); + for (FunctionModelItem function : scopeFunctionList) { + // This fixes method's arguments and return types that are templates + // but the template variable wasn't declared in the C++ header. + const bool templateTypeFixed =_fixFunctionModelItemTypes(function, metaClass); + if (AbstractMetaFunction *metaFunction = traverseFunction(function)) { + result.append(metaFunction); + if (!templateTypeFixed) + unchangedFunctions.append(metaFunction); + } + } + + const AbstractMetaFunctionList::ConstIterator unchangedBegin = unchangedFunctions.begin(); + const AbstractMetaFunctionList::ConstIterator unchangedEnd = unchangedFunctions.end(); + for (int i = result.size() - 1; i >= 0; --i) { + AbstractMetaFunction *function = result.at(i); + if (!unchangedFunctions.contains(function) + && unchangedEnd != std::find_if(unchangedBegin, unchangedEnd, DuplicatingFunctionPredicate(function))) { + delete result.takeAt(i); + } + } + return result; +} + +void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, + AbstractMetaClass *metaClass) +{ + + const AbstractMetaFunctionList functions = metaClass->templateArguments().isEmpty() + ? classFunctionList(scopeItem) + : templateClassFunctionList(scopeItem, metaClass); + + for (AbstractMetaFunction *metaFunction : functions){ + metaFunction->setOriginalAttributes(metaFunction->attributes()); + if (metaClass->isNamespace()) + *metaFunction += AbstractMetaAttributes::Static; + + QPropertySpec *read = 0; + if (!metaFunction->isSignal() && (read = metaClass->propertySpecForRead(metaFunction->name()))) { + // Property reader must be in the form " name()" + if (metaFunction->type() && (read->type() == metaFunction->type()->typeEntry()) && (metaFunction->arguments().size() == 0)) { + *metaFunction += AbstractMetaAttributes::PropertyReader; + metaFunction->setPropertySpec(read); + } + } else if (QPropertySpec* write = metaClass->propertySpecForWrite(metaFunction->name())) { + // Property setter must be in the form "void name()" + // make sure the function was created with all aguments, some argument can be missing during the pareser because of errors on typesystem + if ((!metaFunction->type()) && (metaFunction->arguments().size() == 1) && (write->type() == metaFunction->arguments().at(0)->type()->typeEntry())) { + *metaFunction += AbstractMetaAttributes::PropertyWriter; + metaFunction->setPropertySpec(write); + } + } else if (QPropertySpec* reset = metaClass->propertySpecForReset(metaFunction->name())) { + // Property resetter must be in the form "void name()" + if ((!metaFunction->type()) && (metaFunction->arguments().size() == 0)) { + *metaFunction += AbstractMetaAttributes::PropertyResetter; + metaFunction->setPropertySpec(reset); + } + } + + const bool isInvalidDestructor = metaFunction->isDestructor() && metaFunction->isPrivate(); + const bool isInvalidConstructor = metaFunction->isConstructor() + && ((metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction) + || metaFunction->isInvalid()); + if ((isInvalidDestructor || isInvalidConstructor) + && !metaClass->hasNonPrivateConstructor()) { + *metaClass += AbstractMetaAttributes::Final; + } else if (metaFunction->isConstructor() && !metaFunction->isPrivate()) { + *metaClass -= AbstractMetaAttributes::Final; + metaClass->setHasNonPrivateConstructor(true); + } + + // Classes with virtual destructors should always have a shell class + // (since we aren't registering the destructors, we need this extra check) + if (metaFunction->isDestructor() && !metaFunction->isFinal()) + metaClass->setForceShellClass(true); + + if (!metaFunction->isDestructor() + && !metaFunction->isInvalid() + && !(metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)) { + + setupFunctionDefaults(metaFunction, metaClass); + + if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction)) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("signal '%1' in class '%2' is overloaded.") + .arg(metaFunction->name(), metaClass->name()); + } + + if (metaFunction->isSignal() && !metaClass->isQObject()) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("signal '%1' in non-QObject class '%2'") + .arg(metaFunction->name(), metaClass->name()); + } + + if (metaFunction->isConversionOperator()) + fixReturnTypeOfConversionOperator(metaFunction); + + metaClass->addFunction(metaFunction); + applyFunctionModifications(metaFunction); + } else if (metaFunction->isDestructor()) { + metaClass->setHasPrivateDestructor(metaFunction->isPrivate()); + metaClass->setHasProtectedDestructor(metaFunction->isProtected()); + metaClass->setHasVirtualDestructor(metaFunction->isVirtual()); + } + if (!metaFunction->ownerClass()) { + delete metaFunction; + metaFunction = 0; + } + } + + fillAddedFunctions(metaClass); +} + +void AbstractMetaBuilderPrivate::fillAddedFunctions(AbstractMetaClass *metaClass) +{ + // Add the functions added by the typesystem + const AddedFunctionList &addedFunctions = metaClass->typeEntry()->addedFunctions(); + for (const AddedFunction &addedFunc : addedFunctions) + traverseFunction(addedFunc, metaClass); +} + +void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction *func) +{ + const FunctionModificationList &mods = func->modifications(func->implementingClass()); + AbstractMetaFunction& funcRef = *func; + for (const FunctionModification &mod : mods) { + if (mod.isRenameModifier()) { + func->setOriginalName(func->name()); + func->setName(mod.renamedTo()); + } else if (mod.isAccessModifier()) { + funcRef -= AbstractMetaAttributes::Public; + funcRef -= AbstractMetaAttributes::Protected; + funcRef -= AbstractMetaAttributes::Private; + funcRef -= AbstractMetaAttributes::Friendly; + + if (mod.isPublic()) + funcRef += AbstractMetaAttributes::Public; + else if (mod.isProtected()) + funcRef += AbstractMetaAttributes::Protected; + else if (mod.isPrivate()) + funcRef += AbstractMetaAttributes::Private; + else if (mod.isFriendly()) + funcRef += AbstractMetaAttributes::Friendly; + } + + if (mod.isFinal()) + funcRef += AbstractMetaAttributes::FinalInTargetLang; + else if (mod.isNonFinal()) + funcRef -= AbstractMetaAttributes::FinalInTargetLang; + } +} + +bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) +{ + Q_ASSERT(!metaClass->isInterface()); + + if (m_setupInheritanceDone.contains(metaClass)) + return true; + + m_setupInheritanceDone.insert(metaClass); + + QStringList baseClasses = metaClass->baseClassNames(); + + // we only support our own containers and ONLY if there is only one baseclass + if (baseClasses.size() == 1 && baseClasses.first().contains(QLatin1Char('<'))) { + TypeParser::Info info; + ComplexTypeEntry* baseContainerType; + AbstractMetaClass* templ = findTemplateClass(baseClasses.first(), metaClass, &info, &baseContainerType); + if (templ) { + setupInheritance(templ); + inheritTemplate(metaClass, templ, info); + metaClass->typeEntry()->setBaseContainerType(templ->typeEntry()); + return true; + } + + if (baseContainerType) { + // Container types are not necessarily wrapped as 'real' classes, + // but there may still be classes derived from them. In such case, + // we still need to set the base container type in order to + // generate correct code for type conversion checking. + // + // Additionally, we consider this case as successfully setting up + // inheritance. + metaClass->typeEntry()->setBaseContainerType(baseContainerType); + return true; + } + + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("template baseclass '%1' of '%2' is not known") + .arg(baseClasses.first(), metaClass->name()); + return false; + } + + TypeDatabase* types = TypeDatabase::instance(); + + int primary = -1; + int primaries = 0; + for (int i = 0; i < baseClasses.size(); ++i) { + + if (types->isClassRejected(baseClasses.at(i))) + continue; + + TypeEntry* baseClassEntry = types->findType(baseClasses.at(i)); + if (!baseClassEntry) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("class '%1' inherits from unknown base class '%2'") + .arg(metaClass->name(), baseClasses.at(i)); + } else if (!baseClassEntry->designatedInterface()) { // true for primary base class + primaries++; + primary = i; + } + } + + if (primary >= 0) { + AbstractMetaClass *baseClass = AbstractMetaClass::findClass(m_metaClasses, baseClasses.at(primary)); + if (!baseClass) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("unknown baseclass for '%1': '%2'") + .arg(metaClass->name(), baseClasses.at(primary)); + return false; + } + metaClass->setBaseClass(baseClass); + } + + for (int i = 0; i < baseClasses.size(); ++i) { + if (types->isClassRejected(baseClasses.at(i))) + continue; + + if (i != primary) { + AbstractMetaClass *baseClass = AbstractMetaClass::findClass(m_metaClasses, baseClasses.at(i)); + if (!baseClass) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("class not found for setup inheritance '%1'").arg(baseClasses.at(i)); + return false; + } + + setupInheritance(baseClass); + + QString interfaceName = baseClass->isInterface() ? InterfaceTypeEntry::interfaceName(baseClass->name()) : baseClass->name(); + AbstractMetaClass *iface = AbstractMetaClass::findClass(m_metaClasses, interfaceName); + if (!iface) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("unknown interface for '%1': '%2'").arg(metaClass->name(), interfaceName); + return false; + } + metaClass->addInterface(iface); + + const AbstractMetaClassList &interfaces = iface->interfaces(); + for (AbstractMetaClass* iface : interfaces) + metaClass->addInterface(iface); + } + } + + return true; +} + +void AbstractMetaBuilderPrivate::traverseEnums(ScopeModelItem scopeItem, + AbstractMetaClass *metaClass, + const QStringList &enumsDeclarations) +{ + const EnumList &enums = scopeItem->enums(); + for (const EnumModelItem &enumItem : enums) { + AbstractMetaEnum* metaEnum = traverseEnum(enumItem, metaClass, QSet::fromList(enumsDeclarations)); + if (metaEnum) { + metaClass->addEnum(metaEnum); + metaEnum->setEnclosingClass(metaClass); + } + } +} + +AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunction& addedFunc) +{ + return traverseFunction(addedFunc, 0); +} + +AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunction& addedFunc, + AbstractMetaClass *metaClass) +{ + AbstractMetaFunction *metaFunction = q->createMetaFunction(); + metaFunction->setConstant(addedFunc.isConstant()); + metaFunction->setName(addedFunc.name()); + metaFunction->setOriginalName(addedFunc.name()); + AbstractMetaClass::Attributes visibility = + addedFunc.access() == AddedFunction::Public + ? AbstractMetaAttributes::Public : AbstractMetaAttributes::Protected; + metaFunction->setVisibility(visibility); + metaFunction->setUserAdded(true); + AbstractMetaAttributes::Attribute isStatic = addedFunc.isStatic() ? AbstractMetaFunction::Static : AbstractMetaFunction::None; + metaFunction->setAttributes(metaFunction->attributes() | AbstractMetaAttributes::Final | isStatic); + metaFunction->setType(translateType(addedFunc.version(), addedFunc.returnType())); + + + QVector args = addedFunc.arguments(); + AbstractMetaArgumentList metaArguments; + + for (int i = 0; i < args.count(); ++i) { + AddedFunction::TypeInfo& typeInfo = args[i]; + AbstractMetaArgument *metaArg = q->createMetaArgument(); + AbstractMetaType* type = translateType(addedFunc.version(), typeInfo); + decideUsagePattern(type); + metaArg->setType(type); + metaArg->setArgumentIndex(i); + metaArg->setDefaultValueExpression(typeInfo.defaultValue); + metaArg->setOriginalDefaultValueExpression(typeInfo.defaultValue); + metaArguments.append(metaArg); + } + + metaFunction->setArguments(metaArguments); + if (metaFunction->isOperatorOverload() && !metaFunction->isCallOperator()) { + if (metaArguments.size() > 2) { + qCWarning(lcShiboken) << "An operator overload need to have 0, 1 or 2 arguments if it's reverse."; + } else if (metaArguments.size() == 2) { + // Check if it's a reverse operator + if (metaArguments[1]->type()->typeEntry() == metaClass->typeEntry()) { + metaFunction->setReverseOperator(true); + // we need to call these two function to cache the old signature (with two args) + // we do this buggy behaviour to comply with the original apiextractor buggy behaviour. + metaFunction->signature(); + metaFunction->minimalSignature(); + metaArguments.removeLast(); + metaFunction->setArguments(metaArguments); + } else { + qCWarning(lcShiboken) << "Operator overload can have two arguments only if it's a reverse operator!"; + } + } + } + + + // Find the correct default values + for (int i = 0; i < metaArguments.size(); ++i) { + AbstractMetaArgument* metaArg = metaArguments.at(i); + + //use relace-default-expression for set default value + QString replacedExpression; + if (m_currentClass) + 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(metaArg, metaFunction); + } + } + } + + metaFunction->setOriginalAttributes(metaFunction->attributes()); + fixArgumentNames(metaFunction); + + if (metaClass) { + const AbstractMetaArgumentList fargs = metaFunction->arguments(); + if (metaClass->isNamespace()) + *metaFunction += AbstractMetaFunction::Static; + if (metaFunction->name() == metaClass->name()) { + metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction); + if (fargs.size() == 1) { + const TypeEntry *te = fargs.first()->type()->typeEntry(); + if (te->isCustom()) + metaFunction->setExplicit(true); + if (te->name() == metaFunction->name()) + metaFunction->setFunctionType(AbstractMetaFunction::CopyConstructorFunction); + } + } else { + metaFunction->setFunctionType(AbstractMetaFunction::NormalFunction); + } + + metaFunction->setDeclaringClass(metaClass); + metaFunction->setImplementingClass(metaClass); + metaClass->addFunction(metaFunction); + metaClass->setHasNonPrivateConstructor(true); + } + + return metaFunction; +} + +void AbstractMetaBuilderPrivate::fixArgumentNames(AbstractMetaFunction *func) +{ + if (func->arguments().isEmpty()) + return; + const FunctionModificationList &mods = func->modifications(m_currentClass); + for (const FunctionModification &mod : mods) { + for (const ArgumentModification &argMod : mod.argument_mods) { + if (!argMod.renamed_to.isEmpty()) { + AbstractMetaArgument* arg = func->arguments().at(argMod.index - 1); + arg->setOriginalName(arg->name()); + arg->setName(argMod.renamed_to, false); + } + } + } + + AbstractMetaArgumentList arguments = func->arguments(); + for (int i = 0, size = arguments.size(); i < size; ++i) { + if (arguments.at(i)->name().isEmpty()) + arguments[i]->setName(QLatin1String("arg__") + QString::number(i + 1), false); + } +} + +static QString functionSignature(FunctionModelItem functionItem) +{ + QStringList args; + const ArgumentList &arguments = functionItem->arguments(); + for (const ArgumentModelItem &arg : arguments) + args << arg->type().toString(); + return functionItem->name() + QLatin1Char('(') + args.join(QLatin1Char(',')) + QLatin1Char(')'); +} + +static inline QString qualifiedFunctionSignatureWithType(const FunctionModelItem &functionItem, + const QString &className = QString()) +{ + QString result = functionItem->type().toString() + QLatin1Char(' '); + if (!className.isEmpty()) + result += className + colonColon(); + 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 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; +} + +AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModelItem functionItem) +{ + if (!functionItem->templateParameters().isEmpty()) + return nullptr; + QString functionName = functionItem->name(); + QString className; + if (m_currentClass) { + // Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT + // and overridden metaObject(), QGADGET helpers + if (functionName == QLatin1String("qt_check_for_QGADGET_macro") + || functionName.startsWith(QLatin1String("qt_meta"))) { + return nullptr; + } + className = m_currentClass->typeEntry()->qualifiedCppName(); + if (functionName == QLatin1String("metaObject") && className != QLatin1String("QObject")) + return nullptr; + } + + // Store original signature with unresolved typedefs for message/log purposes + const QString originalQualifiedSignatureWithReturn = + qualifiedFunctionSignatureWithType(functionItem, className); + + 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; + } + + Q_ASSERT(functionItem->functionType() == CodeModel::Normal + || functionItem->functionType() == CodeModel::Signal + || functionItem->functionType() == CodeModel::Slot); + + if (functionItem->isFriend()) + return 0; + + AbstractMetaFunction *metaFunction = q->createMetaFunction(); + metaFunction->setConstant(functionItem->isConstant()); + + if (ReportHandler::isDebug(ReportHandler::MediumDebug)) + qCDebug(lcShiboken).noquote().nospace() << " - " << functionName << "()"; + + metaFunction->setName(functionName); + metaFunction->setOriginalName(functionItem->name()); + + if (functionItem->isAbstract()) + *metaFunction += AbstractMetaAttributes::Abstract; + + if (!metaFunction->isAbstract()) + *metaFunction += AbstractMetaAttributes::Native; + + if (!functionItem->isVirtual()) + *metaFunction += AbstractMetaAttributes::Final; + + if (functionItem->isInvokable()) + *metaFunction += AbstractMetaAttributes::Invokable; + + if (functionItem->isStatic()) { + *metaFunction += AbstractMetaAttributes::Static; + *metaFunction += AbstractMetaAttributes::Final; + } + + // Access rights + if (functionItem->accessPolicy() == CodeModel::Public) + *metaFunction += AbstractMetaAttributes::Public; + else if (functionItem->accessPolicy() == CodeModel::Private) + *metaFunction += AbstractMetaAttributes::Private; + else + *metaFunction += AbstractMetaAttributes::Protected; + + + QString strippedClassName = className; + int cc_pos = strippedClassName.lastIndexOf(colonColon()); + if (cc_pos > 0) + strippedClassName = strippedClassName.mid(cc_pos + 2); + + TypeInfo functionType = functionItem->type(); + + if (TypeDatabase::instance()->isReturnTypeRejected(className, functionType.toString(), &rejectReason)) { + m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); + delete metaFunction; + return nullptr; + } + + if (functionName.startsWith(QLatin1Char('~'))) { + metaFunction->setFunctionType(AbstractMetaFunction::DestructorFunction); + metaFunction->setInvalid(true); + } else if (stripTemplateArgs(functionName) == strippedClassName) { + metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction); + // Check for Copy/Move down below + metaFunction->setExplicit(functionItem->isExplicit()); + metaFunction->setName(m_currentClass->name()); + } else { + bool ok; + AbstractMetaType* type = translateType(functionType, &ok); + + if (!ok) { + Q_ASSERT(type == 0); + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("skipping function '%1', unmatched return type '%2'") + .arg(originalQualifiedSignatureWithReturn, + functionItem->type().toString()); + m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType); + metaFunction->setInvalid(true); + return metaFunction; + } + + metaFunction->setType(type); + + if (functionItem->functionType() == CodeModel::Signal) + metaFunction->setFunctionType(AbstractMetaFunction::SignalFunction); + else if (functionItem->functionType() == CodeModel::Slot) + metaFunction->setFunctionType(AbstractMetaFunction::SlotFunction); + } + + ArgumentList arguments = functionItem->arguments(); + + if (arguments.size() == 1) { + ArgumentModelItem arg = arguments.at(0); + TypeInfo type = arg->type(); + if (type.qualifiedName().first() == QLatin1String("void") && type.indirections() == 0) + arguments.pop_front(); + } + + AbstractMetaArgumentList metaArguments; + + for (int i = 0; i < arguments.size(); ++i) { + ArgumentModelItem arg = arguments.at(i); + + if (TypeDatabase::instance()->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) { + m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); + delete metaFunction; + return nullptr; + } + + bool ok; + AbstractMetaType* metaType = translateType(arg->type(), &ok); + if (!ok) { + Q_ASSERT(metaType == 0); + const QString reason = msgUnmatchedParameterType(arg, i); + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("skipping function '%1', %2") + .arg(originalQualifiedSignatureWithReturn, reason); + const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn + + QLatin1String(": ") + reason; + m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType); + metaFunction->setInvalid(true); + return metaFunction; + } + + if (metaType == Q_NULLPTR) { + const QString reason = msgVoidParameterType(arg, i); + qCWarning(lcShiboken).noquote().nospace() + << QString::fromLatin1("skipping function '%1': %2") + .arg(originalQualifiedSignatureWithReturn, reason); + const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn + + QLatin1String(": ") + reason; + m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType); + metaFunction->setInvalid(true); + return metaFunction; + } + + AbstractMetaArgument *metaArgument = q->createMetaArgument(); + + metaArgument->setType(metaType); + metaArgument->setName(arg->name()); + metaArgument->setArgumentIndex(i); + metaArguments << metaArgument; + } + + metaFunction->setArguments(metaArguments); + + // Find the correct default values + for (int i = 0; i < arguments.size(); ++i) { + ArgumentModelItem arg = arguments.at(i); + AbstractMetaArgument* metaArg = metaArguments.at(i); + + //use relace-default-expression for set default value + QString replacedExpression; + if (m_currentClass) { + replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1); + } else { + FunctionModificationList mods = TypeDatabase::instance()->functionModifications(metaFunction->minimalSignature()); + if (!mods.isEmpty()) { + QVector argMods = mods.first().argument_mods; + if (!argMods.isEmpty()) + replacedExpression = argMods.first().replacedDefaultExpression; + } + } + + bool hasDefaultValue = false; + if (arg->defaultValue() || !replacedExpression.isEmpty()) { + QString expr = arg->defaultValueExpression(); + expr = fixDefaultValue(arg, metaArg->type(), metaFunction, m_currentClass, i); + metaArg->setOriginalDefaultValueExpression(expr); + + if (metaFunction->removedDefaultExpression(m_currentClass, i + 1)) { + expr.clear(); + } else if (!replacedExpression.isEmpty()) { + expr = replacedExpression; + } + metaArg->setDefaultValueExpression(expr); + + if (metaArg->type()->isEnum() || metaArg->type()->isFlags()) + m_enumDefaultArguments << QPair(metaArg, metaFunction); + + hasDefaultValue = !expr.isEmpty(); + } + + //Check for missing argument name + if (hasDefaultValue + && !metaArg->hasName() + && !metaFunction->isOperatorOverload() + && !metaFunction->isSignal() + && metaFunction->argumentName(i+1, false, m_currentClass).isEmpty()) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("Argument %1 on function '%2::%3' has default expression but does not have name.") + .arg(i+1).arg(className, metaFunction->minimalSignature()); + } + + } + + fixArgumentNames(metaFunction); + + // Determine class special functions + if (m_currentClass && metaFunction->arguments().size() == 1) { + const AbstractMetaType *argType = metaFunction->arguments().first()->type(); + if (argType->typeEntry() == m_currentClass->typeEntry() && argType->indirections() == 0) { + if (metaFunction->isConstructor()) { + switch (argType->referenceType()) { + case NoReference: + metaFunction->setFunctionType(AbstractMetaFunction::CopyConstructorFunction); + break; + case LValueReference: + if (argType->isConstant()) + metaFunction->setFunctionType(AbstractMetaFunction::CopyConstructorFunction); + break; + case RValueReference: + metaFunction->setFunctionType(AbstractMetaFunction::MoveConstructorFunction); + break; + } + } else if (metaFunction->name() == QLatin1String("operator=")) { + switch (argType->referenceType()) { + case NoReference: + metaFunction->setFunctionType(AbstractMetaFunction::AssignmentOperatorFunction); + break; + case LValueReference: + if (argType->isConstant()) + metaFunction->setFunctionType(AbstractMetaFunction::AssignmentOperatorFunction); + break; + case RValueReference: + metaFunction->setFunctionType(AbstractMetaFunction::MoveAssignmentOperatorFunction); + break; + } + } + } + } + return metaFunction; +} + +AbstractMetaType *AbstractMetaBuilderPrivate::translateType(double vr, + const AddedFunction::TypeInfo &typeInfo) +{ + Q_ASSERT(!typeInfo.name.isEmpty()); + TypeDatabase* typeDb = TypeDatabase::instance(); + TypeEntry* type; + + QString typeName = typeInfo.name; + + if (typeName == QLatin1String("void")) + return 0; + + type = typeDb->findType(typeName); + + // test if the type is a template, like a container + bool isTemplate = false; + QStringList templateArgs; + if (!type && typeInfo.name.contains(QLatin1Char('<'))) { + const QStringList& parsedType = parseTemplateType(typeInfo.name); + if (parsedType.isEmpty()) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("Template type parsing failed for '%1'").arg(typeInfo.name); + } else { + templateArgs = parsedType.mid(1); + isTemplate = (type = typeDb->findContainerType(parsedType[0])); + } + } + + if (!type) { + QStringList candidates; + SingleTypeEntryHash entries = typeDb->entries(); + for (SingleTypeEntryHash::const_iterator 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()); + } + + 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); + + 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); + } + + AbstractMetaType *metaType = q->createMetaType(); + metaType->setTypeEntry(type); + metaType->setIndirections(typeInfo.indirections); + if (typeInfo.isReference) + metaType->setReferenceType(LValueReference); + metaType->setConstant(typeInfo.isConstant); + if (isTemplate) { + for (const QString& templateArg : qAsConst(templateArgs)) { + AbstractMetaType* metaArgType = translateType(vr, AddedFunction::TypeInfo::fromSignature(templateArg)); + metaType->addInstantiation(metaArgType); + } + metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern); + } + + return metaType; +} + +static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaClass, const QString& qualifiedName) +{ + const TypeEntry* type = 0; + QStringList context = metaClass->qualifiedCppName().split(colonColon()); + while(!type && (context.size() > 0) ) { + type = TypeDatabase::instance()->findType(context.join(colonColon()) + colonColon() + qualifiedName); + context.removeLast(); + } + return type; +} + +AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei, + bool *ok, bool resolveType, + bool resolveScope) +{ + Q_ASSERT(ok); + *ok = true; + + // 1. Test the type info without resolving typedefs in case this is present in the + // type system + TypeInfo typei; + if (resolveType) { + bool ok; + AbstractMetaType* t = translateType(_typei, &ok, false, resolveScope); + if (t && ok) + return t; + Q_ASSERT(t == 0); + } + + if (!resolveType) { + typei = _typei; + } else { + // 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; + while (i >= 0) { + typei = TypeInfo::resolveType(_typei, m_scopes.at(i--)); + if (typei.qualifiedName().join(colonColon()) != _typei.qualifiedName().join(colonColon())) + break; + } + + } + + if (typei.isFunctionPointer()) { + *ok = false; + return 0; + } + + QString errorMessage; + TypeParser::Info typeInfo = TypeParser::parse(typei.toString(), &errorMessage); + if (typeInfo.is_busted) { + qWarning().noquote().nospace() << "Unable to translate type \"" << _typei.toString() + << "\": " << errorMessage; + *ok = false; + return 0; + } + + // 2. Handle pointers specified as arrays with unspecified size + bool arrayOfUnspecifiedSize = false; + if (typeInfo.arrays.size() > 0) { + arrayOfUnspecifiedSize = true; + for (int i = 0; i < typeInfo.arrays.size(); ++i) + arrayOfUnspecifiedSize = arrayOfUnspecifiedSize && typeInfo.arrays.at(i).isEmpty(); + + if (!arrayOfUnspecifiedSize) { + TypeInfo newInfo; + //newInfo.setArguments(typei.arguments()); + newInfo.setIndirections(typei.indirections()); + newInfo.setConstant(typei.isConstant()); + newInfo.setFunctionPointer(typei.isFunctionPointer()); + newInfo.setQualifiedName(typei.qualifiedName()); + newInfo.setReferenceType(typei.referenceType()); + newInfo.setVolatile(typei.isVolatile()); + + AbstractMetaType* elementType = translateType(newInfo, ok); + if (!(*ok)) + return 0; + + for (int i = typeInfo.arrays.size() - 1; i >= 0; --i) { + QString s = typeInfo.arrays.at(i); + bool _ok; + int elems = findOutValueFromString(s, _ok); + + AbstractMetaType *arrayType = q->createMetaType(); + arrayType->setArrayElementCount(elems); + arrayType->setArrayElementType(elementType); + arrayType->setTypeEntry(new ArrayTypeEntry(elementType->typeEntry() , elementType->typeEntry()->version())); + decideUsagePattern(arrayType); + + elementType = arrayType; + } + + return elementType; + } else { + typeInfo.indirections += typeInfo.arrays.size(); + } + } + + QStringList qualifierList = typeInfo.qualified_name; + if (qualifierList.isEmpty()) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("horribly broken type '%1'").arg(_typei.toString()); + *ok = false; + return 0; + } + + QString qualifiedName = qualifierList.join(colonColon()); + QString name = qualifierList.takeLast(); + + // 3. Special case 'void' type + if (name == QLatin1String("void") && !typeInfo.indirections) + return 0; + + // 4. Special case QFlags (include instantiation in name) + if (qualifiedName == QLatin1String("QFlags")) + qualifiedName = typeInfo.toString(); + + 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); + + // 5.1.1 - Try using the class parents' scopes + if (!type && !m_currentClass->baseClassNames().isEmpty()) { + const AbstractMetaClassList &baseClasses = getBaseClasses(m_currentClass); + for (const AbstractMetaClass *cls : baseClasses) { + type = findTypeEntryUsingContext(cls, qualifiedName); + if (type) + break; + } + } + } + + // 5.2 - Try without scope + if (!type) + type = TypeDatabase::instance()->findType(qualifiedName); + + // 6. No? Try looking it up as a flags type + if (!type) + type = TypeDatabase::instance()->findFlagsType(qualifiedName); + + // 7. No? Try looking it up as a container type + if (!type) + type = TypeDatabase::instance()->findContainerType(name); + + // 8. No? Check if the current class is a template and this type is one + // of the parameters. + if (!type && m_currentClass) { + const QVector &template_args = m_currentClass->templateArguments(); + for (TypeEntry *te : template_args) { + if (te->name() == qualifiedName) + type = te; + } + } + + // 9. Try finding the type by prefixing it with the current + // context and all baseclasses of the current context + if (!type && !TypeDatabase::instance()->isClassRejected(qualifiedName) && m_currentClass && resolveScope) { + QStringList contexts; + contexts.append(m_currentClass->qualifiedCppName()); + contexts.append(currentScope()->qualifiedName().join(colonColon())); + + + TypeInfo info = typei; + bool subclassesDone = false; + while (!contexts.isEmpty() && !type) { + type = TypeDatabase::instance()->findType(contexts.at(0) + colonColon() + qualifiedName); + contexts.pop_front(); + + // 10. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so + // enum types from there may be addressed without any scope resolution in properties. + if (!contexts.size() && !subclassesDone) { + contexts << QLatin1String("Qt"); + subclassesDone = true; + } + } + + } + + if (!type) { + *ok = false; + return 0; + } + + // Used to for diagnostics later... + m_usedTypes << type; + + // These are only implicit and should not appear in code... + Q_ASSERT(!type->isInterface()); + + AbstractMetaType *metaType = q->createMetaType(); + metaType->setTypeEntry(type); + metaType->setIndirections(typeInfo.indirections); + metaType->setReferenceType(typeInfo.referenceType); + metaType->setConstant(typeInfo.is_constant); + metaType->setOriginalTypeDescription(_typei.toString()); + + for (const TypeParser::Info &ta : qAsConst(typeInfo.template_instantiations)) { + TypeInfo info; + info.setConstant(ta.is_constant); + info.setReferenceType(ta.referenceType); + info.setIndirections(ta.indirections); + + info.setFunctionPointer(false); + info.setQualifiedName(ta.instantiationName().split(colonColon())); + + AbstractMetaType* targType = translateType(info, ok); + if (!(*ok)) { + delete metaType; + return 0; + } + + metaType->addInstantiation(targType, true); + } + + // The usage pattern *must* be decided *after* the possible template + // instantiations have been determined, or else the absence of + // such instantiations will break the caching scheme of + // AbstractMetaType::cppSignature(). + decideUsagePattern(metaType); + + return metaType; +} + + +int AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringValue, bool &ok) +{ + int value = stringValue.toInt(&ok); + if (ok) + return value; + + if (stringValue == QLatin1String("true") || stringValue == QLatin1String("false")) { + ok = true; + return (stringValue == QLatin1String("true")); + } + + // This is a very lame way to handle expression evaluation, + // but it is not critical and will do for the time being. + static const QRegularExpression variableNameRegExp(QStringLiteral("^[a-zA-Z_][a-zA-Z0-9_]*$")); + Q_ASSERT(variableNameRegExp.isValid()); + if (!variableNameRegExp.match(stringValue).hasMatch()) { + ok = true; + return 0; + } + + AbstractMetaEnumValue *enumValue = AbstractMetaClass::findEnumValue(m_metaClasses, stringValue); + if (enumValue) { + ok = true; + return enumValue->value(); + } + + for (AbstractMetaEnum *metaEnum : qAsConst(m_globalEnums)) { + const AbstractMetaEnumValueList &values = metaEnum->values(); + for (const AbstractMetaEnumValue *ev : values) { + if (ev->name() == stringValue) { + ok = true; + return ev->value(); + } + } + } + + ok = false; + return 0; +} + +void AbstractMetaBuilderPrivate::decideUsagePattern(AbstractMetaType *metaType) +{ + metaType->decideUsagePattern(); +} + +QString AbstractMetaBuilderPrivate::fixDefaultValue(ArgumentModelItem item, + AbstractMetaType *type, + AbstractMetaFunction *fnc, + AbstractMetaClass *implementingClass, + int /* argumentIndex */) +{ + QString functionName = fnc->name(); + QString className = implementingClass ? implementingClass->qualifiedCppName() : QString(); + + QString expr = item->defaultValueExpression(); + if (type) { + if (type->isPrimitive()) { + if (type->name() == QLatin1String("boolean")) { + if (expr != QLatin1String("false") && expr != QLatin1String("true")) { + bool ok = false; + int number = expr.toInt(&ok); + if (ok && number) + expr = QLatin1String("true"); + else + expr = QLatin1String("false"); + } + } else { + // This can be an enum or flag so I need to delay the + // translation untill all namespaces are completly + // processed. This is done in figureOutEnumValues() + } + } else if (type->isFlags() || type->isEnum()) { + bool isNumber; + expr.toInt(&isNumber); + if (!isNumber && expr.indexOf(colonColon()) < 0) { + // Add the enum/flag scope to default value, making it usable + // from other contexts beside its owner class hierarchy + static const QRegularExpression typeRegEx(QStringLiteral("[^<]*[<]([^:]*::).*")); + Q_ASSERT(typeRegEx.isValid()); + const QRegularExpressionMatch match = typeRegEx.match(type->minimalSignature()); + if (match.hasMatch()) + expr.prepend(match.captured(1)); + } + } else if (type->isContainer() && expr.contains(QLatin1Char('<'))) { + static const QRegularExpression typeRegEx(QStringLiteral("[^<]*<(.*)>")); + Q_ASSERT(typeRegEx.isValid()); + const QRegularExpressionMatch typeMatch = typeRegEx.match(type->minimalSignature()); + static const QRegularExpression defaultRegEx(QLatin1String("([^<]*<).*(>[^>]*)")); + Q_ASSERT(defaultRegEx.isValid()); + const QRegularExpressionMatch defaultMatch = defaultRegEx.match(expr); + if (typeMatch.hasMatch() && defaultMatch.hasMatch()) + expr = defaultMatch.captured(1) + typeMatch.captured(1) + defaultMatch.captured(2); + } else { + // Here the default value is supposed to be a constructor, + // a class field, or a constructor receiving a class field + static const QRegularExpression defaultRegEx(QStringLiteral("([^\\(]*\\(|)([^\\)]*)(\\)|)")); + Q_ASSERT(defaultRegEx.isValid()); + const QRegularExpressionMatch defaultMatch = defaultRegEx.match(expr); + QString defaultValueCtorName = defaultMatch.hasMatch() ? defaultMatch.captured(1) : QString(); + if (defaultValueCtorName.endsWith(QLatin1Char('('))) + defaultValueCtorName.chop(1); + + // Fix the scope for constructor using the already + // resolved argument type as a reference. + // The following regular expression extracts any + // use of namespaces/scopes from the type string. + static const QRegularExpression typeRegEx(QLatin1String("^(?:const[\\s]+|)([\\w:]*::|)([A-Za-z_]\\w*)\\s*[&\\*]?$")); + Q_ASSERT(typeRegEx.isValid()); + const QRegularExpressionMatch typeMatch = typeRegEx.match(type->minimalSignature()); + + QString typeNamespace = typeMatch.hasMatch() ? typeMatch.captured(1) : QString(); + QString typeCtorName = typeMatch.hasMatch() ? typeMatch.captured(2) : QString(); + if (!typeNamespace.isEmpty() && defaultValueCtorName == typeCtorName) + expr.prepend(typeNamespace); + + // Fix scope if the parameter is a field of the current class + if (implementingClass) { + const AbstractMetaFieldList &fields = implementingClass->fields(); + for (const AbstractMetaField *field : fields) { + if (defaultMatch.hasMatch() && defaultMatch.captured(2) == field->name()) { + expr = defaultMatch.captured(1) + implementingClass->name() + + colonColon() + defaultMatch.captured(2) + defaultMatch.captured(3); + break; + } + } + } + } + } else { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("undefined type for default value '%3' of argument in function '%1', class '%2'") + .arg(functionName, className, item->defaultValueExpression()); + + expr = QString(); + } + + return expr; +} + +bool AbstractMetaBuilderPrivate::isQObject(const FileModelItem &dom, const QString &qualifiedName) +{ + if (qualifiedName == QLatin1String("QObject")) + return true; + + ClassModelItem classItem = dom->findClass(qualifiedName); + + if (!classItem) { + QStringList names = qualifiedName.split(colonColon()); + NamespaceModelItem ns = dom; + for (int i = 0; i < names.size() - 1 && ns; ++i) + ns = ns->findNamespace(names.at(i)); + if (ns && names.size() >= 2) + classItem = ns->findClass(names.at(names.size() - 1)); + } + + bool isqobject = classItem && classItem->extendsClass(QLatin1String("QObject")); + + if (classItem && !isqobject) { + QStringList baseClasses = classItem->baseClasses(); + for (int i = 0; i < baseClasses.count(); ++i) { + + isqobject = isQObject(dom, baseClasses.at(i)); + if (isqobject) + break; + } + } + + return isqobject; +} + + +bool AbstractMetaBuilderPrivate::isEnum(const FileModelItem &dom, const QStringList& qualified_name) +{ + CodeModelItem item = dom->model()->findItem(qualified_name, dom); + return item && item->kind() == _EnumModelItem::__node_kind; +} + +AbstractMetaClass* AbstractMetaBuilderPrivate::findTemplateClass(const QString &name, + const AbstractMetaClass *context, + TypeParser::Info *info, + ComplexTypeEntry **baseContainerType) const +{ + TypeParser::Info localInfo; + if (!info) + info = &localInfo; + + TypeDatabase* types = TypeDatabase::instance(); + + QStringList scope = context->typeEntry()->qualifiedCppName().split(colonColon()); + QString errorMessage; + scope.removeLast(); + for (int i = scope.size(); i >= 0; --i) { + QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join(colonColon()) + colonColon() : QString(); + QString completeName = prefix + name; + const TypeParser::Info parsed = TypeParser::parse(completeName, &errorMessage); + if (parsed.is_busted) { + qWarning().noquote().nospace() << "Unable to parse type \"" << completeName + << "\" while looking for template \"" << name << "\": " << errorMessage; + continue; + } + *info = parsed; + QString qualifiedName = info->qualified_name.join(colonColon()); + + AbstractMetaClass* templ = 0; + for (AbstractMetaClass *c : qAsConst(m_templates)) { + if (c->typeEntry()->name() == qualifiedName) { + templ = c; + break; + } + } + + if (!templ) + templ = AbstractMetaClass::findClass(m_metaClasses, qualifiedName); + + if (templ) + return templ; + + if (baseContainerType) + *baseContainerType = types->findContainerType(qualifiedName); + } + + return 0; +} + +AbstractMetaClassList AbstractMetaBuilderPrivate::getBaseClasses(const AbstractMetaClass *metaClass) const +{ + AbstractMetaClassList baseClasses; + const QStringList &baseClassNames = metaClass->baseClassNames(); + for (const QString& parent : baseClassNames) { + AbstractMetaClass* cls = 0; + if (parent.contains(QLatin1Char('<'))) + cls = findTemplateClass(parent, metaClass); + else + cls = AbstractMetaClass::findClass(m_metaClasses, parent); + + if (cls) + baseClasses << cls; + } + return baseClasses; +} + +bool AbstractMetaBuilderPrivate::ancestorHasPrivateCopyConstructor(const AbstractMetaClass *metaClass) const +{ + if (metaClass->hasPrivateCopyConstructor()) + return true; + const AbstractMetaClassList &baseClasses = getBaseClasses(metaClass); + for (const AbstractMetaClass *cls : baseClasses) { + if (ancestorHasPrivateCopyConstructor(cls)) + return true; + } + return false; +} + +AbstractMetaType* AbstractMetaBuilderPrivate::inheritTemplateType(const QVector &templateTypes, + const AbstractMetaType *metaType, + bool *ok) +{ + if (ok) + *ok = true; + if (!metaType || (!metaType->typeEntry()->isTemplateArgument() && !metaType->hasInstantiations())) + return metaType ? metaType->copy() : 0; + + AbstractMetaType *returned = metaType->copy(); + returned->setOriginalTemplateType(metaType->copy()); + + if (returned->typeEntry()->isTemplateArgument()) { + const TemplateArgumentEntry* tae = static_cast(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; + } + + AbstractMetaType* t = returned->copy(); + t->setTypeEntry(templateTypes.at(tae->ordinal())->typeEntry()); + t->setIndirections(templateTypes.at(tae->ordinal())->indirections() + t->indirections() ? 1 : 0); + decideUsagePattern(t); + + delete returned; + returned = inheritTemplateType(templateTypes, t, ok); + if (ok && !(*ok)) + return 0; + } + + 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; + } + returned->setInstantiations(instantiations, true); + } + + return returned; +} + +bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, + const AbstractMetaClass *templateClass, + const TypeParser::Info &info) +{ + QVector targs = info.template_instantiations; + QVector templateTypes; + + if (subclass->isTypeDef()) { + subclass->setHasCloneOperator(templateClass->hasCloneOperator()); + subclass->setHasEqualsOperator(templateClass->hasEqualsOperator()); + subclass->setHasHashFunction(templateClass->hasHashFunction()); + subclass->setHasNonPrivateConstructor(templateClass->hasNonPrivateConstructor()); + subclass->setHasPrivateDestructor(templateClass->hasPrivateDestructor()); + subclass->setHasProtectedDestructor(templateClass->hasProtectedDestructor()); + subclass->setHasVirtualDestructor(templateClass->hasVirtualDestructor()); + } + + for (const TypeParser::Info &i : qAsConst(targs)) { + QString typeName = i.qualified_name.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) { + QString templateParamName = possibleName; + break; + } + } + + if (t) { + AbstractMetaType *temporaryType = q->createMetaType(); + temporaryType->setTypeEntry(t); + temporaryType->setConstant(i.is_constant); + temporaryType->setReferenceType(i.referenceType); + temporaryType->setIndirections(i.indirections); + temporaryType->decideUsagePattern(); + templateTypes << temporaryType; + } else { + qCWarning(lcShiboken).noquote().nospace() + << "Ignoring template parameter " << templateParamName << " from " + << info.instantiationName() << ", because I don't know what it is."; + } + } + + AbstractMetaFunctionList funcs = subclass->functions(); + const AbstractMetaFunctionList &templateClassFunctions = templateClass->functions(); + for (const AbstractMetaFunction *function : templateClassFunctions) { + if (function->isModifiedRemoved(TypeSystem::All)) + continue; + + 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; + } + + 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) + break; + f->addArgument(arg); + } + + if (!ok) { + delete f; + 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. + f->setImplementingClass(subclass); + + // We also set it as the declaring class, since the superclass is + // supposed to disappear. This allows us to make certain function modifications + // on the inherited functions. + f->setDeclaringClass(subclass); + + + if (f->isConstructor() && subclass->isTypeDef()) { + 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(); + FunctionModificationList mods = function->modifications(templateClass); + for (int i = 0; i < mods.size(); ++i) { + FunctionModification mod = mods.at(i); + mod.signature = f->minimalSignature(); + + // If we ever need it... Below is the code to do + // substitution of the template instantation type inside + // injected code.. +#if 0 + if (mod.modifiers & Modification::CodeInjection) { + for (int j = 0; j < template_types.size(); ++j) { + CodeSnip &snip = mod.snips.last(); + QString code = snip.code(); + code.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j), + template_types.at(j)->typeEntry()->qualifiedCppName()); + snip.codeList.clear(); + snip.addCode(code); + } + } +#endif + te->addFunctionModification(mod); + } + + subclass->addFunction(f); + } + + subclass->setTemplateBaseClass(templateClass); + subclass->setTemplateBaseClassInstantiations(templateTypes); + subclass->setInterfaces(templateClass->interfaces()); + subclass->setBaseClass(templateClass->baseClass()); + + return true; +} + +void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass, + const QStringList &declarations) +{ + for (int i = 0; i < declarations.size(); ++i) { + QString p = declarations.at(i); + + QStringList l = p.split(QLatin1String(" ")); + + + QStringList qualifiedScopeName = currentScope()->qualifiedName(); + bool ok = false; + AbstractMetaType* type = 0; + QString scope; + for (int j = qualifiedScopeName.size(); j >= 0; --j) { + scope = j > 0 ? QStringList(qualifiedScopeName.mid(0, j)).join(colonColon()) + colonColon() : QString(); + TypeInfo info; + info.setQualifiedName((scope + l.at(0)).split(colonColon())); + + type = translateType(info, &ok); + if (type && ok) + break; + } + + if (!type || !ok) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("Unable to decide type of property: '%1' in class '%2'") + .arg(l.at(0), metaClass->name()); + continue; + } + + QString typeName = scope + l.at(0); + + QPropertySpec* spec = new QPropertySpec(type->typeEntry()); + spec->setName(l.at(1)); + spec->setIndex(i); + + for (int pos = 2; pos + 1 < l.size(); pos += 2) { + if (l.at(pos) == QLatin1String("READ")) + spec->setRead(l.at(pos + 1)); + else if (l.at(pos) == QLatin1String("WRITE")) + spec->setWrite(l.at(pos + 1)); + else if (l.at(pos) == QLatin1String("DESIGNABLE")) + spec->setDesignable(l.at(pos + 1)); + else if (l.at(pos) == QLatin1String("RESET")) + spec->setReset(l.at(pos + 1)); + } + + metaClass->addPropertySpec(spec); + delete type; + } +} + +static AbstractMetaFunction* findCopyCtor(AbstractMetaClass* cls) +{ + AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::Invisible); + functions << cls->queryFunctions(AbstractMetaClass::Visible); + + for (AbstractMetaFunction *f : qAsConst(functions)) { + const AbstractMetaFunction::FunctionType t = f->functionType(); + if (t == AbstractMetaFunction::CopyConstructorFunction || t == AbstractMetaFunction::AssignmentOperatorFunction) + return f; + } + return 0; +} + +void AbstractMetaBuilderPrivate::setupClonable(AbstractMetaClass *cls) +{ + bool result = true; + + // find copy ctor for the current class + AbstractMetaFunction* copyCtor = findCopyCtor(cls); + if (copyCtor) { // if exists a copy ctor in this class + result = copyCtor->isPublic(); + } else { // else... lets find one in the parent class + QQueue baseClasses; + if (cls->baseClass()) + baseClasses.enqueue(cls->baseClass()); + baseClasses << cls->interfaces().toList(); + + while (!baseClasses.isEmpty()) { + AbstractMetaClass* currentClass = baseClasses.dequeue(); + baseClasses << currentClass->interfaces().toList(); + if (currentClass->baseClass()) + baseClasses.enqueue(currentClass->baseClass()); + + copyCtor = findCopyCtor(currentClass); + if (copyCtor) { + result = copyCtor->isPublic(); + break; + } + } + } + cls->setHasCloneOperator(result); +} + +void AbstractMetaBuilderPrivate::setupExternalConversion(AbstractMetaClass *cls) +{ + const AbstractMetaFunctionList &convOps = cls->operatorOverloads(AbstractMetaClass::ConversionOp); + for (AbstractMetaFunction *func : convOps) { + if (func->isModifiedRemoved()) + continue; + AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, func->type()->typeEntry()); + if (!metaClass) + continue; + metaClass->addExternalConversionOperator(func); + } + const AbstractMetaClassList &innerClasses = cls->innerClasses(); + for (AbstractMetaClass *innerClass : innerClasses) + setupExternalConversion(innerClass); +} + +static void writeRejectLogFile(const QString &name, + const QMap &rejects) +{ + QFile f(name); + if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("failed to write log file: '%1'") + .arg(QDir::toNativeSeparators(f.fileName())); + return; + } + + QTextStream s(&f); + + + for (int reason = 0; reason < AbstractMetaBuilder::NoReason; ++reason) { + s << QString(72, QLatin1Char('*')) << endl; + switch (reason) { + case AbstractMetaBuilder::NotInTypeSystem: + s << "Not in type system"; + break; + case AbstractMetaBuilder::GenerationDisabled: + s << "Generation disabled by type system"; + break; + case AbstractMetaBuilder::RedefinedToNotClass: + s << "Type redefined to not be a class"; + break; + + case AbstractMetaBuilder::UnmatchedReturnType: + s << "Unmatched return type"; + break; + + case AbstractMetaBuilder::UnmatchedArgumentType: + s << "Unmatched argument type"; + break; + + case AbstractMetaBuilder::ApiIncompatible: + s << "Incompatible API"; + break; + + default: + s << "unknown reason"; + break; + } + + s << endl; + + for (QMap::const_iterator it = rejects.constBegin(); + it != rejects.constEnd(); ++it) { + if (it.value() != reason) + continue; + s << " - " << it.key() << endl; + } + + s << QString(72, QLatin1Char('*')) << endl << endl; + } + +} + +void AbstractMetaBuilderPrivate::dumpLog() const +{ + writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_classes.log"), m_rejectedClasses); + writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_enums.log"), m_rejectedEnums); + writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_functions.log"), m_rejectedFunctions); + writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_fields.log"), m_rejectedFields); +} + +AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClass *cppClass, + const Dependencies &additionalDependencies) const +{ + QLinkedList unmappedResult; + QHash map; + QHash reverseMap; + + const AbstractMetaClassList& classList = cppClass ? cppClass->innerClasses() : m_metaClasses; + + int i = 0; + for (AbstractMetaClass *clazz : classList) { + if (map.contains(clazz->qualifiedCppName())) + continue; + map[clazz->qualifiedCppName()] = i; + reverseMap[i] = clazz; + i++; + } + + Graph graph(map.count()); + + for (const Dependency &dep : additionalDependencies) { + const int parentIndex = map.value(dep.parent, -1); + const int childIndex = map.value(dep.child, -1); + if (parentIndex >= 0 && childIndex >= 0) { + graph.addEdge(parentIndex, childIndex); + } else { + qCWarning(lcShiboken).noquote().nospace() + << "AbstractMetaBuilder::classesTopologicalSorted(): Invalid additional dependency: " + << dep.child << " -> " << dep.parent << '.'; + } + } + + // TODO choose a better name to these regexs + static const QRegularExpression regex1(QStringLiteral("\\(.*\\)")); + Q_ASSERT(regex1.isValid()); + static const QRegularExpression regex2(QStringLiteral("::.*")); + Q_ASSERT(regex2.isValid()); + for (AbstractMetaClass *clazz : classList) { + if (clazz->enclosingClass() && map.contains(clazz->enclosingClass()->qualifiedCppName())) + graph.addEdge(map[clazz->enclosingClass()->qualifiedCppName()], map[clazz->qualifiedCppName()]); + + const AbstractMetaClassList &bases = getBaseClasses(clazz); + for (AbstractMetaClass *baseClass : bases) { + // Fix polymorphic expression + if (clazz->baseClass() == baseClass) + clazz->setBaseClass(baseClass); + + if (map.contains(baseClass->qualifiedCppName())) + graph.addEdge(map[baseClass->qualifiedCppName()], map[clazz->qualifiedCppName()]); + } + + const AbstractMetaFunctionList &functions = clazz->functions(); + for (AbstractMetaFunction *func : functions) { + const AbstractMetaArgumentList &arguments = func->arguments(); + for (AbstractMetaArgument *arg : arguments) { + // check methods with default args + QString defaultExpression = arg->originalDefaultValueExpression(); + if (!defaultExpression.isEmpty()) { + if (defaultExpression == QLatin1String("0") && arg->type()->isValue()) + defaultExpression = arg->type()->name(); + + defaultExpression.remove(regex1); + defaultExpression.remove(regex2); + } + if (!defaultExpression.isEmpty()) { + QString exprClassName = clazz->qualifiedCppName() + colonColon() + defaultExpression; + if (!map.contains(exprClassName)) { + bool found = false; + for (AbstractMetaClass *baseClass : bases) { + exprClassName = baseClass->qualifiedCppName() + colonColon() + defaultExpression; + if (map.contains(exprClassName)) { + found = true; + break; + } + } + if (!found) { + if (map.contains(defaultExpression)) + exprClassName = defaultExpression; + else + exprClassName.clear(); + } + } + if (!exprClassName.isEmpty() && exprClassName != clazz->qualifiedCppName()) + graph.addEdge(map[exprClassName], map[clazz->qualifiedCppName()]); + } + } + } + } + + AbstractMetaClassList result; + unmappedResult = graph.topologicalSort(); + if (unmappedResult.isEmpty() && graph.nodeCount()) { + QTemporaryFile tempFile; + tempFile.setAutoRemove(false); + tempFile.open(); + QHash hash; + QHash::iterator it = map.begin(); + for (; it != map.end(); ++it) + hash[it.value()] = it.key(); + graph.dumpDot(hash, tempFile.fileName()); + qCWarning(lcShiboken).noquote().nospace() + << "Cyclic dependency found! Graph can be found at " + << QDir::toNativeSeparators(tempFile.fileName()); + } else { + for (int i : qAsConst(unmappedResult)) { + Q_ASSERT(reverseMap.contains(i)); + if (!reverseMap[i]->isInterface()) + result << reverseMap[i]; + } + } + + return result; +} + +AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted(const AbstractMetaClass *cppClass, + const Dependencies &additionalDependencies) const +{ + return d->classesTopologicalSorted(cppClass, additionalDependencies); +} + +AbstractMetaArgumentList AbstractMetaBuilderPrivate::reverseList(const AbstractMetaArgumentList &list) +{ + AbstractMetaArgumentList ret; + + int index = list.size(); + for (AbstractMetaArgument *arg : list) { + arg->setArgumentIndex(index); + ret.prepend(arg); + index--; + } + + return ret; +} + +void AbstractMetaBuilder::setGlobalHeader(const QString& globalHeader) +{ + d->m_globalHeader = QFileInfo(globalHeader); +} + +void AbstractMetaBuilderPrivate::setInclude(TypeEntry *te, const QString &fileName) const +{ + QFileInfo info(fileName); + if (m_globalHeader.fileName() != info.fileName()) + te->setInclude(Include(Include::IncludePath, info.fileName())); +} + +#ifndef QT_NO_DEBUG_STREAM +template +static void debugFormatSequence(QDebug &d, const char *key, const Container& c, + const char *separator = ", ") +{ + typedef typename Container::const_iterator ConstIt; + if (c.isEmpty()) + return; + const ConstIt begin = c.begin(); + const ConstIt end = c.end(); + d << "\n " << key << '[' << c.size() << "]=("; + for (ConstIt it = begin; it != end; ++it) { + if (it != begin) + d << separator; + d << *it; + } + d << ')'; +} + +void AbstractMetaBuilder::formatDebug(QDebug &debug) const +{ + debug << "m_globalHeader=" << d->m_globalHeader.absoluteFilePath(); + debugFormatSequence(debug, "qtMetaTypeDeclaredTypeNames", d->m_qmetatypeDeclaredTypenames); + debugFormatSequence(debug, "globalEnums", d->m_globalEnums, "\n"); + debugFormatSequence(debug, "globalFunctions", d->m_globalFunctions, "\n"); + if (const int scopeCount = d->m_scopes.size()) { + debug << "\n scopes[" << scopeCount << "]=("; + for (int i = 0; i < scopeCount; ++i) { + if (i) + debug << ", "; + _CodeModelItem::formatKind(debug, d->m_scopes.at(i)->kind()); + debug << " \"" << d->m_scopes.at(i)->name() << '"'; + } + debug << ')'; + } + debugFormatSequence(debug, "classes", d->m_metaClasses, "\n"); + debugFormatSequence(debug, "templates", d->m_templates, "\n"); +} + +QDebug operator<<(QDebug d, const AbstractMetaBuilder &ab) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AbstractMetaBuilder("; + ab.formatDebug(d); + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h new file mode 100644 index 000000000..f7427d488 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 ABSTRACTMETABUILDER_H +#define ABSTRACTMETABUILDER_H + +#include "abstractmetalang_typedefs.h" +#include "dependency.h" + +QT_FORWARD_DECLARE_CLASS(QIODevice) + +class AbstractMetaBuilderPrivate; +class AbstractMetaClass; +class AbstractMetaEnumValue; + +class AbstractMetaBuilder +{ +public: + enum RejectReason { + NotInTypeSystem, + GenerationDisabled, + RedefinedToNotClass, + UnmatchedArgumentType, + UnmatchedReturnType, + ApiIncompatible, + NoReason + }; + + AbstractMetaBuilder(); + virtual ~AbstractMetaBuilder(); + + AbstractMetaClassList classes() const; + AbstractMetaClassList templates() const; + AbstractMetaClassList smartPointers() const; + AbstractMetaFunctionList globalFunctions() const; + AbstractMetaEnumList globalEnums() const; + // QtScript + QSet qtMetaTypeDeclaredTypeNames() const; + + /** + * Sorts a list of classes topologically, if an AbstractMetaClass object + * is passed the list of classes will be its inner classes, otherwise + * the list will be the module global classes. + * \return a list of classes sorted topologically + */ + AbstractMetaClassList classesTopologicalSorted(const AbstractMetaClass *cppClass = Q_NULLPTR, + const Dependencies &additionalDependencies = Dependencies()) const; + + bool build(const QByteArrayList &arguments, unsigned clangFlags = 0); + void setLogDirectory(const QString& logDir); + + /** + * AbstractMetaBuilder should know what's the global header being used, + * so any class declared under this header wont have the include file + * filled. + */ + void setGlobalHeader(const QString& globalHeader); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const; +#endif + +protected: + virtual AbstractMetaClass *createMetaClass(); + virtual AbstractMetaEnum *createMetaEnum(); + virtual AbstractMetaEnumValue *createMetaEnumValue(); + virtual AbstractMetaField *createMetaField(); + virtual AbstractMetaFunction *createMetaFunction(); + virtual AbstractMetaArgument *createMetaArgument(); + virtual AbstractMetaType *createMetaType(); + +private: + friend class AbstractMetaBuilderPrivate; + AbstractMetaBuilderPrivate *d; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaBuilder &ab); +#endif + +#endif // ABSTRACTMETBUILDER_H diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h new file mode 100644 index 000000000..96a6fdbfd --- /dev/null +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 ABSTRACTMETABUILDER_P_H +#define ABSTRACTMETABUILDER_P_H + +#include "abstractmetabuilder.h" +#include "parser/codemodel_fwd.h" +#include "abstractmetalang.h" +#include "typesystem.h" +#include "typeparser.h" + +#include +#include + +class TypeDatabase; + +class AbstractMetaBuilderPrivate +{ +public: + AbstractMetaBuilderPrivate(); + ~AbstractMetaBuilderPrivate(); + + static FileModelItem buildDom(const QByteArrayList &arguments, unsigned clangFlags); + void traverseDom(const FileModelItem &dom); + + void dumpLog() const; + AbstractMetaClassList classesTopologicalSorted(const AbstractMetaClass *cppClass = Q_NULLPTR, + const Dependencies &additionalDependencies = Dependencies()) const; + ScopeModelItem popScope() { return m_scopes.takeLast(); } + + void pushScope(ScopeModelItem item) { m_scopes << item; } + + ScopeModelItem currentScope() const { return m_scopes.last(); } + + AbstractMetaClass *argumentToClass(ArgumentModelItem); + + void figureOutEnumValuesForClass(AbstractMetaClass *metaClass, QSet *classes); + int figureOutEnumValue(const QString &name, int value, AbstractMetaEnum *meta_enum, AbstractMetaFunction *metaFunction = 0); + void figureOutEnumValues(); + void figureOutDefaultEnumArguments(); + + void addAbstractMetaClass(AbstractMetaClass *cls); + AbstractMetaClass *traverseTypeDef(const FileModelItem &dom, + const TypeDefModelItem &typeDef); + AbstractMetaClass *traverseClass(const FileModelItem &dom, + const ClassModelItem &item); + AbstractMetaClass *currentTraversedClass(ScopeModelItem item); + void traverseScopeMembers(ScopeModelItem item, AbstractMetaClass *metaClass); + void traverseClassMembers(ClassModelItem scopeItem); + void traverseNamespaceMembers(NamespaceModelItem scopeItem); + bool setupInheritance(AbstractMetaClass *metaClass); + AbstractMetaClass *traverseNamespace(const FileModelItem &dom, + const NamespaceModelItem &item); + AbstractMetaEnum *traverseEnum(EnumModelItem item, AbstractMetaClass *enclosing, + const QSet &enumsDeclarations); + void traverseEnums(ScopeModelItem item, AbstractMetaClass *parent, + const QStringList &enumsDeclarations); + AbstractMetaFunctionList classFunctionList(const ScopeModelItem &scopeItem); + AbstractMetaFunctionList templateClassFunctionList(const ScopeModelItem &scopeItem, + AbstractMetaClass *metaClass); + void traverseFunctions(ScopeModelItem item, AbstractMetaClass *parent); + void applyFunctionModifications(AbstractMetaFunction* func); + void traverseFields(ScopeModelItem item, AbstractMetaClass *parent); + void traverseStreamOperator(FunctionModelItem functionItem); + void traverseOperatorFunction(FunctionModelItem item); + AbstractMetaFunction* traverseFunction(const AddedFunction &addedFunc); + AbstractMetaFunction* traverseFunction(const AddedFunction &addedFunc, + AbstractMetaClass *metaClass); + AbstractMetaFunction *traverseFunction(FunctionModelItem function); + AbstractMetaField *traverseField(VariableModelItem field, + const AbstractMetaClass *cls); + void checkFunctionModifications(); + void registerHashFunction(FunctionModelItem functionItem); + void registerToStringCapability(FunctionModelItem functionItem); + + /** + * A conversion operator function should not have its owner class as + * its return type, but unfortunately it does. This function fixes the + * return type of operator functions of this kind making the return type + * be the same as it is supposed to generate when used in C++. + * If the returned type is a wrapped C++ class, this method also adds the + * conversion operator to the collection of external conversions of the + * said class. + * \param metaFunction conversion operator function to be fixed. + */ + void fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction); + + void parseQ_Property(AbstractMetaClass *metaClass, const QStringList &declarations); + void setupEquals(AbstractMetaClass *metaClass); + void setupComparable(AbstractMetaClass *metaClass); + void setupClonable(AbstractMetaClass *cls); + void setupExternalConversion(AbstractMetaClass *cls); + void setupFunctionDefaults(AbstractMetaFunction *metaFunction, + AbstractMetaClass *metaClass); + + QString fixDefaultValue(ArgumentModelItem item, AbstractMetaType *type, + AbstractMetaFunction *fnc, AbstractMetaClass *, + int argumentIndex); + AbstractMetaType* translateType(double vr, const AddedFunction::TypeInfo &typeInfo); + AbstractMetaType *translateType(const TypeInfo &type, bool *ok, + bool resolveType = true, + bool resolveScope = true); + + int findOutValueFromString(const QString &stringValue, bool &ok); + + void decideUsagePattern(AbstractMetaType *type); + + AbstractMetaClass *findTemplateClass(const QString& name, const AbstractMetaClass *context, + TypeParser::Info *info = Q_NULLPTR, + ComplexTypeEntry **baseContainerType = Q_NULLPTR) const; + AbstractMetaClassList getBaseClasses(const AbstractMetaClass *metaClass) const; + bool ancestorHasPrivateCopyConstructor(const AbstractMetaClass *metaClass) const; + + bool inheritTemplate(AbstractMetaClass *subclass, + const AbstractMetaClass *templateClass, + const TypeParser::Info &info); + AbstractMetaType *inheritTemplateType(const QVector &templateTypes, + const AbstractMetaType *metaType, + bool *ok = Q_NULLPTR); + + bool isQObject(const FileModelItem &dom, const QString &qualifiedName); + bool isEnum(const FileModelItem &dom, const QStringList &qualifiedName); + + void fixQObjectForScope(const FileModelItem &dom, const TypeDatabase *types, + const NamespaceModelItem &item); + + void sortLists(); + AbstractMetaArgumentList reverseList(const AbstractMetaArgumentList &list); + void setInclude(TypeEntry *te, const QString &fileName) const; + void fixArgumentNames(AbstractMetaFunction *func); + void fillAddedFunctions(AbstractMetaClass *metaClass); + + AbstractMetaBuilder *q; + AbstractMetaClassList m_metaClasses; + AbstractMetaClassList m_templates; + AbstractMetaClassList m_smartPointers; + AbstractMetaFunctionList m_globalFunctions; + AbstractMetaEnumList m_globalEnums; + + QSet m_usedTypes; + + typedef QMap RejectMap; + + RejectMap m_rejectedClasses; + RejectMap m_rejectedEnums; + RejectMap m_rejectedFunctions; + RejectMap m_rejectedFields; + + QList m_enums; + + QList > m_enumDefaultArguments; + + QHash m_enumValues; + + AbstractMetaClass *m_currentClass; + QList m_scopes; + QString m_namespacePrefix; + + QSet m_setupInheritanceDone; + + // QtScript + QSet m_qmetatypeDeclaredTypenames; + + QString m_logDirectory; + QFileInfo m_globalHeader; +}; + +#endif // ABSTRACTMETBUILDER_P_H diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp new file mode 100644 index 000000000..4fa009fd2 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -0,0 +1,2784 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "abstractmetalang.h" +#include "reporthandler.h" +#include "typedatabase.h" +#include "typesystem.h" + +#ifndef QT_NO_DEBUG_STREAM +# include +# include +#endif + +#include +#include + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaAttributes *aa) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AbstractMetaAttributes("; + if (aa) + d << aa->attributes(); + else + d << '0'; + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +/******************************************************************************* + * AbstractMetaVariable + */ + +AbstractMetaVariable::AbstractMetaVariable(const AbstractMetaVariable &other) +{ + m_originalName = other.m_originalName; + m_name = other.m_name; + m_type = other.m_type->copy(); + m_hasName = other.m_hasName; + m_doc = other.m_doc; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaVariable *av) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AbstractMetaVariable("; + if (av) { + d << av->type()->name() << ' ' << av->name(); + } else { + d << '0'; + } + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +/******************************************************************************* + * AbstractMetaType + */ + +AbstractMetaType::AbstractMetaType() + :m_typeEntry(0), + m_arrayElementCount(0), + m_arrayElementType(0), + m_originalTemplateType(0), + m_pattern(InvalidPattern), + m_constant(false), + m_cppInstantiation(true), + m_indirections(0), + m_reserved(0), + m_referenceType(NoReference) +{ +} + +AbstractMetaType::~AbstractMetaType() +{ + qDeleteAll(m_children); + m_instantiations.clear(); +} + +QString AbstractMetaType::package() const +{ + return m_typeEntry->targetLangPackage(); +} + +QString AbstractMetaType::name() const +{ + if (m_name.isNull()) + // avoid constLast to stay Qt 5.5 compatible + m_name = m_typeEntry->targetLangName().split(QLatin1String("::")).last(); + return m_name; +} + +QString AbstractMetaType::fullName() const +{ + return m_typeEntry->qualifiedTargetLangName(); +} + +AbstractMetaType *AbstractMetaType::copy() const +{ + AbstractMetaType *cpy = new AbstractMetaType; + + cpy->setTypeUsagePattern(typeUsagePattern()); + cpy->setConstant(isConstant()); + cpy->setReferenceType(referenceType()); + cpy->setIndirections(indirections()); + cpy->setInstantiations(instantiations()); + cpy->setArrayElementCount(arrayElementCount()); + cpy->setOriginalTypeDescription(originalTypeDescription()); + cpy->setOriginalTemplateType(originalTemplateType() ? originalTemplateType()->copy() : 0); + + cpy->setArrayElementType(arrayElementType() ? arrayElementType()->copy() : 0); + + cpy->setTypeEntry(typeEntry()); + + return cpy; +} + +QString AbstractMetaType::cppSignature() const +{ + if (m_cachedCppSignature.isEmpty()) { + if (isConstant()) + m_cachedCppSignature += QLatin1String("const "); + + m_cachedCppSignature += typeEntry()->qualifiedCppName(); + + if (hasInstantiationInCpp()) { + AbstractMetaTypeList types = instantiations(); + m_cachedCppSignature += QLatin1Char('<'); + for (int i = 0; i < types.count(); ++i) { + if (i > 0) + m_cachedCppSignature += QLatin1String(", "); + m_cachedCppSignature += types[i]->cppSignature(); + } + m_cachedCppSignature += QLatin1String(" >"); + } + + if (indirections() || m_referenceType != NoReference) { + m_cachedCppSignature += QLatin1Char(' '); + if (indirections()) + m_cachedCppSignature += QString(indirections(), QLatin1Char('*')); + switch (referenceType()) { + case NoReference: + break; + case LValueReference: + m_cachedCppSignature += QLatin1Char('&'); + break; + case RValueReference: + m_cachedCppSignature += QLatin1String("&&"); + break; + } + } + } + return m_cachedCppSignature; +} + +AbstractMetaType::TypeUsagePattern AbstractMetaType::determineUsagePattern() const +{ + if (m_typeEntry->isTemplateArgument() || m_referenceType == RValueReference) + return InvalidPattern; + + if (m_typeEntry->isPrimitive() && (!actualIndirections() + || (isConstant() && m_referenceType == LValueReference && !indirections()))) { + return PrimitivePattern; + } + + if (m_typeEntry->isVoid()) + return NativePointerPattern; + + if (m_typeEntry->isVarargs()) + return VarargsPattern; + + if (m_typeEntry->isString() && indirections() == 0 + && (isConstant() == (m_referenceType == LValueReference) + || isConstant())) { + return StringPattern; + } + + if (m_typeEntry->isChar() + && indirections() == 0 + && isConstant() == (m_referenceType == LValueReference)) { + return CharPattern; + } + + if (m_typeEntry->isJObjectWrapper() + && indirections() == 0 + && isConstant() == (m_referenceType == LValueReference)) { + return JObjectWrapperPattern; + } + + if (m_typeEntry->isVariant() + && indirections() == 0 + && isConstant() == (m_referenceType == LValueReference)) { + return VariantPattern; + } + + if (m_typeEntry->isEnum() && actualIndirections() == 0) + return EnumPattern; + + if (m_typeEntry->isObject()) { + if (indirections() == 0 && m_referenceType == NoReference) + return ValuePattern; + return static_cast(m_typeEntry)->isQObject() + ? QObjectPattern : ObjectPattern; + } + + if (m_typeEntry->isContainer() && indirections() == 0) + return ContainerPattern; + + if (m_typeEntry->isSmartPointer() && indirections() == 0) + return SmartPointerPattern; + + if (m_typeEntry->isFlags() && indirections() == 0 + && (isConstant() == (m_referenceType == LValueReference))) + return FlagsPattern; + + if (m_typeEntry->isArray()) + return ArrayPattern; + + if (m_typeEntry->isThread()) { + Q_ASSERT(indirections() == 1); + return ThreadPattern; + } + + if (m_typeEntry->isValue()) + return indirections() == 1 ? ValuePointerPattern : ValuePattern; + + if (ReportHandler::isDebug(ReportHandler::FullDebug)) { + qCDebug(lcShiboken) + << QStringLiteral("native pointer pattern for '%1'").arg(cppSignature()); + } + return NativePointerPattern; +} + +void AbstractMetaType::decideUsagePattern() +{ + TypeUsagePattern pattern = determineUsagePattern(); + if (m_typeEntry->isObject() && indirections() == 1 + && m_referenceType == LValueReference && isConstant()) { + // const-references to pointers can be passed as pointers + setReferenceType(NoReference); + setConstant(false); + pattern = static_cast(m_typeEntry)->isQObject() + ? QObjectPattern : ObjectPattern; + } + setTypeUsagePattern(pattern); +} + +bool AbstractMetaType::hasTemplateChildren() const +{ + QStack children; + children << m_children; + + // Recursively iterate over the children / descendants of the type, to check if any of them + // corresponds to a template argument type. + while (!children.isEmpty()) { + AbstractMetaType *child = children.pop(); + if (child->typeEntry()->isTemplateArgument()) + return true; + children << child->m_children; + } + + return false; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaType *at) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AbstractMetaType("; + if (at) + d << at->name(); + else + d << '0'; + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +/******************************************************************************* + * AbstractMetaArgument + */ +AbstractMetaArgument *AbstractMetaArgument::copy() const +{ + return new AbstractMetaArgument(*this); +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaArgument *aa) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AbstractMetaArgument("; + if (aa) + d << aa->toString(); + else + d << '0'; + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +/******************************************************************************* + * AbstractMetaFunction + */ +AbstractMetaFunction::~AbstractMetaFunction() +{ + qDeleteAll(m_arguments); + delete m_type; +} + +/******************************************************************************* + * Indicates that this function has a modification that removes it + */ +bool AbstractMetaFunction::isModifiedRemoved(int types) const +{ + const FunctionModificationList &mods = modifications(implementingClass()); + for (const FunctionModification &mod : mods) { + if (!mod.isRemoveModifier()) + continue; + + if ((mod.removal & types) == types) + return true; + } + + return false; +} + +bool AbstractMetaFunction::needsCallThrough() const +{ + if (ownerClass()->isInterface()) + return false; + if (referenceCounts(implementingClass()).size() > 0) + return true; + if (argumentsHaveNativeId() || !isStatic()) + return true; + + for (const AbstractMetaArgument *arg : m_arguments) { + if (arg->type()->isArray() || arg->type()->isTargetLangEnum() || arg->type()->isTargetLangFlags()) + return true; + } + + if (type() && (type()->isArray() || type()->isTargetLangEnum() || type()->isTargetLangFlags())) + return true; + + for (int i = -1; i <= arguments().size(); ++i) { + TypeSystem::Ownership owner = this->ownership(implementingClass(), TypeSystem::TargetLangCode, i); + if (owner != TypeSystem::InvalidOwnership) + return true; + } + + return false; +} + +bool AbstractMetaFunction::needsSuppressUncheckedWarning() const +{ + for (int i = -1; i <= arguments().size(); ++i) { + const QVector &referenceCounts = this->referenceCounts(implementingClass(), i); + for (const ReferenceCount &referenceCount : referenceCounts) { + if (referenceCount.action != ReferenceCount::Set) + return true; + } + } + return false; +} + +QString AbstractMetaFunction::marshalledName() const +{ + QString returned = QLatin1String("__qt_") + name(); + for (const AbstractMetaArgument *arg : m_arguments) { + returned += QLatin1Char('_'); + if (arg->type()->isNativePointer()) { + returned += QLatin1String("nativepointer"); + } else if (arg->type()->isIntegerEnum() || arg->type()->isIntegerFlags()) { + returned += QLatin1String("int"); + } else { + QString a = arg->type()->name(); + a.replace(QLatin1String("[]"), QLatin1String("_3")); + a.replace(QLatin1Char('.'), QLatin1Char('_')); + returned += a; + } + } + return returned; +} + +bool AbstractMetaFunction::operator<(const AbstractMetaFunction &other) const +{ + return compareTo(&other) & NameLessThan; +} + + +/*! + Returns a mask of CompareResult describing how this function is + compares to another function +*/ +AbstractMetaFunction::CompareResult AbstractMetaFunction::compareTo(const AbstractMetaFunction *other) const +{ + CompareResult result = 0; + + // Enclosing class... + if (ownerClass() == other->ownerClass()) + result |= EqualImplementor; + + // Attributes + if (attributes() == other->attributes()) + result |= EqualAttributes; + + // Compare types + AbstractMetaType *t = type(); + AbstractMetaType *ot = other->type(); + if ((!t && !ot) || ((t && ot && t->name() == ot->name()))) + result |= EqualReturnType; + + // Compare names + int cmp = originalName().compare(other->originalName()); + + if (cmp < 0) + result |= NameLessThan; + else if (!cmp) + result |= EqualName; + + // compare name after modification... + cmp = modifiedName().compare(other->modifiedName()); + if (!cmp) + result |= EqualModifiedName; + + // Compare arguments... + AbstractMetaArgumentList minArguments; + AbstractMetaArgumentList maxArguments; + if (arguments().size() < other->arguments().size()) { + minArguments = arguments(); + maxArguments = other->arguments(); + } else { + minArguments = other->arguments(); + maxArguments = arguments(); + } + + int minCount = minArguments.size(); + int maxCount = maxArguments.size(); + bool same = true; + for (int i = 0; i < maxCount; ++i) { + if (i < minCount) { + const AbstractMetaArgument *min_arg = minArguments.at(i); + const AbstractMetaArgument *max_arg = maxArguments.at(i); + if (min_arg->type()->name() != max_arg->type()->name() + && (min_arg->defaultValueExpression().isEmpty() || max_arg->defaultValueExpression().isEmpty())) { + same = false; + break; + } + } else { + if (maxArguments.at(i)->defaultValueExpression().isEmpty()) { + same = false; + break; + } + } + } + + if (same) + result |= minCount == maxCount ? EqualArguments : EqualDefaultValueOverload; + + return result; +} + +AbstractMetaFunction *AbstractMetaFunction::copy() const +{ + AbstractMetaFunction *cpy = new AbstractMetaFunction; + cpy->setName(name()); + cpy->setOriginalName(originalName()); + cpy->setOwnerClass(ownerClass()); + cpy->setImplementingClass(implementingClass()); + cpy->setFunctionType(functionType()); + cpy->setAttributes(attributes()); + cpy->setDeclaringClass(declaringClass()); + if (type()) + cpy->setType(type()->copy()); + cpy->setConstant(isConstant()); + cpy->setOriginalAttributes(originalAttributes()); + + for (AbstractMetaArgument *arg : m_arguments) + cpy->addArgument(arg->copy()); + + Q_ASSERT((!type() && !cpy->type()) + || (type()->instantiations() == cpy->type()->instantiations())); + + return cpy; +} + +bool AbstractMetaFunction::usesRValueReferences() const +{ + if (m_functionType == MoveConstructorFunction || m_functionType == MoveAssignmentOperatorFunction) + return true; + if (m_type && m_type->referenceType() == RValueReference) + return true; + for (const AbstractMetaArgument *a : m_arguments) { + if (a->type()->referenceType() == RValueReference) + return true; + } + return false; +} + +QStringList AbstractMetaFunction::introspectionCompatibleSignatures(const QStringList &resolvedArguments) const +{ + AbstractMetaArgumentList arguments = this->arguments(); + 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("::"))); + } + + return returned; + } +} + +QString AbstractMetaFunction::signature() const +{ + if (m_cachedSignature.isEmpty()) { + m_cachedSignature = m_originalName; + + m_cachedSignature += QLatin1Char('('); + + for (int i = 0; i < m_arguments.count(); ++i) { + AbstractMetaArgument *a = m_arguments.at(i); + AbstractMetaType *t = a->type(); + if (t) { + if (i > 0) + m_cachedSignature += QLatin1String(", "); + m_cachedSignature += t->cppSignature(); + // We need to have the argument names in the qdoc files + m_cachedSignature += QLatin1Char(' '); + m_cachedSignature += a->name(); + } else { + qCWarning(lcShiboken).noquote().nospace() + << QString::fromLatin1("No abstract meta type found for argument '%1' while" + "constructing signature for function '%2'.") + .arg(a->name(), name()); + } + } + m_cachedSignature += QLatin1Char(')'); + + if (isConstant()) + m_cachedSignature += QLatin1String(" const"); + } + return m_cachedSignature; +} + +int AbstractMetaFunction::actualMinimumArgumentCount() const +{ + AbstractMetaArgumentList arguments = this->arguments(); + + int count = 0; + for (int i = 0; i < arguments.size(); ++i && ++count) { + if (argumentRemoved(i + 1)) + --count; + else if (!arguments.at(i)->defaultValueExpression().isEmpty()) + break; + } + + return count; +} + +// Returns reference counts for argument at idx, or all arguments if idx == -2 +QVector AbstractMetaFunction::referenceCounts(const AbstractMetaClass *cls, int idx) const +{ + QVector returned; + + const FunctionModificationList &mods = this->modifications(cls); + for (const FunctionModification &mod : mods) { + for (const ArgumentModification &argumentMod : mod.argument_mods) { + if (argumentMod.index != idx && idx != -2) + continue; + returned += argumentMod.referenceCounts; + } + } + + return returned; +} + + +ArgumentOwner AbstractMetaFunction::argumentOwner(const AbstractMetaClass *cls, int idx) const +{ + const FunctionModificationList &mods = this->modifications(cls); + for (const FunctionModification &mod : mods) { + for (const ArgumentModification &argumentMod : mod.argument_mods) { + if (argumentMod.index != idx) + continue; + return argumentMod.owner; + } + } + return ArgumentOwner(); +} + + +QString AbstractMetaFunction::replacedDefaultExpression(const AbstractMetaClass *cls, int key) const +{ + const FunctionModificationList &modifications = this->modifications(cls); + for (const FunctionModification &modification : modifications) { + for (const ArgumentModification &argumentModification : modification.argument_mods) { + if (argumentModification.index == key + && !argumentModification.replacedDefaultExpression.isEmpty()) { + return argumentModification.replacedDefaultExpression; + } + } + } + + return QString(); +} + +bool AbstractMetaFunction::removedDefaultExpression(const AbstractMetaClass *cls, int key) const +{ + const FunctionModificationList &modifications = this->modifications(cls); + for (const FunctionModification &modification : modifications) { + for (const ArgumentModification &argumentModification : modification.argument_mods) { + if (argumentModification.index == key + && argumentModification.removedDefaultExpression) { + return true; + } + } + } + + return false; +} + +bool AbstractMetaFunction::resetObjectAfterUse(int argumentIdx) const +{ + const AbstractMetaClass *cls = declaringClass(); + const FunctionModificationList &modifications = this->modifications(cls); + for (const FunctionModification &modification : modifications) { + for (const ArgumentModification &argumentModification : modification.argument_mods) { + if (argumentModification.index == argumentIdx && argumentModification.resetAfterUse) + return true; + } + } + + return false; +} + +QString AbstractMetaFunction::nullPointerDefaultValue(const AbstractMetaClass *mainClass, int argumentIdx) const +{ + Q_ASSERT(nullPointersDisabled(mainClass, argumentIdx)); + + const AbstractMetaClass *cls = mainClass; + if (!cls) + cls = implementingClass(); + + do { + const FunctionModificationList &modifications = this->modifications(cls); + for (const FunctionModification &modification : modifications) { + for (const ArgumentModification &argumentModification : modification.argument_mods) { + if (argumentModification.index == argumentIdx + && argumentModification.noNullPointers) { + return argumentModification.nullPointerDefaultValue; + } + } + } + cls = cls->baseClass(); + } while (cls && !mainClass); // Once when mainClass, or once for all base classes of implementing class + + return QString(); + +} + +bool AbstractMetaFunction::nullPointersDisabled(const AbstractMetaClass *mainClass, int argumentIdx) const +{ + const AbstractMetaClass *cls = mainClass; + if (!cls) + cls = implementingClass(); + + do { + const FunctionModificationList &modifications = this->modifications(cls); + for (const FunctionModification &modification : modifications) { + for (const ArgumentModification &argumentModification : modification.argument_mods) { + if (argumentModification.index == argumentIdx + && argumentModification.noNullPointers) { + return true; + } + } + } + + cls = cls->baseClass(); + } while (cls && !mainClass); // Once when mainClass, or once for all base classes of implementing class + + return false; +} + +QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int key) const +{ + const FunctionModificationList &modifications = this->modifications(declaringClass()); + for (const FunctionModification &modification : modifications) { + for (const ArgumentModification &argumentModification : modification.argument_mods) { + if (argumentModification.index != key) + continue; + + for (const CodeSnip &snip : argumentModification.conversion_rules) { + if (snip.language == language && !snip.code().isEmpty()) + return snip.code(); + } + } + } + + return QString(); +} + +QString AbstractMetaFunction::argumentReplaced(int key) const +{ + const FunctionModificationList &modifications = this->modifications(declaringClass()); + for (const FunctionModification &modification : modifications) { + for (const ArgumentModification &argumentModification : modification.argument_mods) { + if (argumentModification.index == key && !argumentModification.replace_value.isEmpty()) + return argumentModification.replace_value; + } + } + + return QString(); +} + +// FIXME If we remove a arg. in the method at the base class, it will not reflect here. +bool AbstractMetaFunction::argumentRemoved(int key) const +{ + const FunctionModificationList &modifications = this->modifications(declaringClass()); + for (const FunctionModification &modification : modifications) { + for (const ArgumentModification &argumentModification : modification.argument_mods) { + if (argumentModification.index == key) { + if (argumentModification.removed) + return true; + } + } + } + + return false; +} + +bool AbstractMetaFunction::isVirtualSlot() const +{ + const FunctionModificationList &modifications = this->modifications(declaringClass()); + for (const FunctionModification &modification : modifications) { + if (modification.isVirtualSlot()) + return true; + } + + return false; +} + +bool AbstractMetaFunction::disabledGarbageCollection(const AbstractMetaClass *cls, int key) const +{ + typedef QHash::const_iterator OwnershipMapIt; + + const FunctionModificationList &modifications = this->modifications(cls); + for (const FunctionModification &modification : modifications) { + for (const ArgumentModification &argumentModification : modification.argument_mods) { + if (argumentModification.index != key) + continue; + + for (OwnershipMapIt it = argumentModification.ownerships.cbegin(), end = argumentModification.ownerships.cend(); it != end; ++it) { + if (it.value() == TypeSystem::CppOwnership) + return true; + } + + } + } + + return false; +} + +bool AbstractMetaFunction::isDeprecated() const +{ + const FunctionModificationList &modifications = this->modifications(declaringClass()); + for (const FunctionModification &modification : modifications) { + if (modification.isDeprecated()) + return true; + } + return false; +} + +bool AbstractMetaFunction::isThread() const +{ + const FunctionModificationList &modifications = this->modifications(declaringClass()); + for (const FunctionModification &modification : modifications) { + if (modification.isThread()) + return true; + } + return false; +} + +bool AbstractMetaFunction::allowThread() const +{ + const FunctionModificationList &modifications = this->modifications(declaringClass()); + for (const FunctionModification &modification : modifications) { + if (modification.allowThread()) + return true; + } + return false; +} + + +TypeSystem::Ownership AbstractMetaFunction::ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int key) const +{ + const FunctionModificationList &modifications = this->modifications(cls); + for (const FunctionModification &modification : modifications) { + for (const ArgumentModification &argumentModification : modification.argument_mods) { + if (argumentModification.index == key) + return argumentModification.ownerships.value(language, TypeSystem::InvalidOwnership); + } + } + + return TypeSystem::InvalidOwnership; +} + +bool AbstractMetaFunction::isRemovedFromAllLanguages(const AbstractMetaClass *cls) const +{ + return isRemovedFrom(cls, TypeSystem::All); +} + +bool AbstractMetaFunction::isRemovedFrom(const AbstractMetaClass *cls, TypeSystem::Language language) const +{ + const FunctionModificationList &modifications = this->modifications(cls); + for (const FunctionModification &modification : modifications) { + if ((modification.removal & language) == language) + return true; + } + + return false; + +} + +QString AbstractMetaFunction::typeReplaced(int key) const +{ + const FunctionModificationList &modifications = this->modifications(declaringClass()); + for (const FunctionModification &modification : modifications) { + for (const ArgumentModification &argumentModification : modification.argument_mods) { + if (argumentModification.index == key + && !argumentModification.modified_type.isEmpty()) { + return argumentModification.modified_type; + } + } + } + + return QString(); +} + +QString AbstractMetaFunction::minimalSignature() const +{ + if (!m_cachedMinimalSignature.isEmpty()) + return m_cachedMinimalSignature; + + QString minimalSignature = originalName() + QLatin1Char('('); + AbstractMetaArgumentList arguments = this->arguments(); + + for (int i = 0; i < arguments.count(); ++i) { + AbstractMetaType *t = arguments.at(i)->type(); + if (t) { + if (i > 0) + minimalSignature += QLatin1Char(','); + minimalSignature += t->minimalSignature(); + } else { + qCWarning(lcShiboken).noquote().nospace() + << QString::fromLatin1("No abstract meta type found for argument '%1' while constructing" + " minimal signature for function '%2'.") + .arg(arguments.at(i)->name(), name()); + } + } + minimalSignature += QLatin1Char(')'); + if (isConstant()) + minimalSignature += QLatin1String("const"); + + minimalSignature = TypeDatabase::normalizedSignature(minimalSignature); + m_cachedMinimalSignature = minimalSignature; + + return minimalSignature; +} + +FunctionModificationList AbstractMetaFunction::modifications(const AbstractMetaClass* implementor) const +{ + if (!implementor) + implementor = ownerClass(); + + if (!implementor) + return TypeDatabase::instance()->functionModifications(minimalSignature()); + + FunctionModificationList mods; + while (implementor) { + mods += implementor->typeEntry()->functionModifications(minimalSignature()); + if ((implementor == implementor->baseClass()) || + (implementor == implementingClass() && (mods.size() > 0))) + break; + const AbstractMetaClassList &interfaces = implementor->interfaces(); + for (const AbstractMetaClass *interface : interfaces) + mods += this->modifications(interface); + implementor = implementor->baseClass(); + } + return mods; +} + +bool AbstractMetaFunction::hasModifications(const AbstractMetaClass *implementor) const +{ + return !modifications(implementor).isEmpty(); +} + +QString AbstractMetaFunction::argumentName(int index, + bool /* create */, + const AbstractMetaClass * /* implementor */) const +{ + return m_arguments[--index]->name(); +} + +bool AbstractMetaFunction::isCallOperator() const +{ + return m_name == QLatin1String("operator()"); +} + +bool AbstractMetaFunction::hasInjectedCode() const +{ + const FunctionModificationList &mods = modifications(ownerClass()); + for (const FunctionModification &mod : mods) { + if (mod.isCodeInjection()) + return true; + } + return false; +} + +CodeSnipList AbstractMetaFunction::injectedCodeSnips(TypeSystem::CodeSnipPosition position, TypeSystem::Language language) const +{ + CodeSnipList result; + const FunctionModificationList &mods = modifications(ownerClass()); + for (const FunctionModification &mod : mods) { + if (mod.isCodeInjection()) { + for (const CodeSnip &snip : mod.snips) { + if ((snip.language & language) && (snip.position == position || position == TypeSystem::CodeSnipPositionAny)) + result << snip; + } + } + } + return result; +} + +bool AbstractMetaFunction::hasSignatureModifications() const +{ + const FunctionModificationList &mods = modifications(); + for (const FunctionModification &mod : mods) { + if (mod.isRenameModifier()) + return true; + for (const ArgumentModification &argmod : mod.argument_mods) { + // since zero represents the return type and we're + // interested only in checking the function arguments, + // it will be ignored. + if (argmod.index > 0) + return true; + } + } + return false; +} + +bool AbstractMetaFunction::isConversionOperator(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) +{ + if (isConversionOperator(funcName)) + return true; + + static const QRegularExpression opRegEx(QLatin1String("^operator([+\\-\\*/%=&\\|\\^\\<>!][=]?" + "|\\+\\+|\\-\\-|&&|\\|\\||<<[=]?|>>[=]?|~" + "|\\[\\]|\\s+delete\\[?\\]?" + "|\\(\\)" + "|\\s+new\\[?\\]?)$")); + Q_ASSERT(opRegEx.isValid()); + return opRegEx.match(funcName).hasMatch(); +} + +bool AbstractMetaFunction::isCastOperator() const +{ + return originalName().startsWith(QLatin1String("operator ")); +} + +bool AbstractMetaFunction::isArithmeticOperator() const +{ + if (!isOperatorOverload()) + return false; + + QString name = originalName(); + + // It's a dereference operator! + if (name == QLatin1String("operator*") && m_arguments.isEmpty()) + return false; + + return name == QLatin1String("operator+") || name == QLatin1String("operator+=") + || name == QLatin1String("operator-") || name == QLatin1String("operator-=") + || name == QLatin1String("operator*") || name == QLatin1String("operator*=") + || name == QLatin1String("operator/") || name == QLatin1String("operator/=") + || name == QLatin1String("operator%") || name == QLatin1String("operator%=") + || name == QLatin1String("operator++") || name == QLatin1String("operator--"); +} + +bool AbstractMetaFunction::isBitwiseOperator() const +{ + if (!isOperatorOverload()) + return false; + + QString name = originalName(); + return name == QLatin1String("operator<<") || name == QLatin1String("operator<<=") + || name == QLatin1String("operator>>") || name == QLatin1String("operator>>=") + || name == QLatin1String("operator&") || name == QLatin1String("operator&=") + || name == QLatin1String("operator|") || name == QLatin1String("operator|=") + || name == QLatin1String("operator^") || name == QLatin1String("operator^=") + || name == QLatin1String("operator~"); +} + +bool AbstractMetaFunction::isComparisonOperator() const +{ + if (!isOperatorOverload()) + return false; + + QString name = originalName(); + return name == QLatin1String("operator<") || name == QLatin1String("operator<=") + || name == QLatin1String("operator>") || name == QLatin1String("operator>=") + || name == QLatin1String("operator==") || name == QLatin1String("operator!="); +} + +bool AbstractMetaFunction::isLogicalOperator() const +{ + if (!isOperatorOverload()) + return false; + + QString name = originalName(); + return name == QLatin1String("operator!") + || name == QLatin1String("operator&&") + || name == QLatin1String("operator||"); +} + +bool AbstractMetaFunction::isSubscriptOperator() const +{ + if (!isOperatorOverload()) + return false; + + return originalName() == QLatin1String("operator[]"); +} + +bool AbstractMetaFunction::isAssignmentOperator() const +{ + return m_functionType == AssignmentOperatorFunction + || m_functionType == MoveAssignmentOperatorFunction; +} + +bool AbstractMetaFunction::isOtherOperator() const +{ + if (!isOperatorOverload()) + return false; + + return !isArithmeticOperator() + && !isBitwiseOperator() + && !isComparisonOperator() + && !isLogicalOperator() + && !isConversionOperator() + && !isSubscriptOperator() + && !isAssignmentOperator(); +} + +int AbstractMetaFunction::arityOfOperator() const +{ + if (!isOperatorOverload() || isCallOperator()) + return -1; + + int arity = m_arguments.size(); + + // Operator overloads that are class members + // implicitly includes the instance and have + // one parameter less than their arity, + // so we increment it. + if (ownerClass() && arity < 2) + arity++; + + return arity; +} + +bool AbstractMetaFunction::isInplaceOperator() const +{ + if (!isOperatorOverload()) + return false; + + QString name = originalName(); + return name == QLatin1String("operator+=") || name == QLatin1String("operator&=") + || name == QLatin1String("operator-=") || name == QLatin1String("operator|=") + || name == QLatin1String("operator*=") || name == QLatin1String("operator^=") + || name == QLatin1String("operator/=") || name == QLatin1String("operator<<=") + || name == QLatin1String("operator%=") || name == QLatin1String("operator>>="); +} + +bool AbstractMetaFunction::isVirtual() const +{ + return !isFinal() && !isSignal() && !isStatic() && !isFinalInCpp() && !isConstructor(); +} + +QString AbstractMetaFunction::modifiedName() const +{ + if (m_cachedModifiedName.isEmpty()) { + const FunctionModificationList &mods = modifications(implementingClass()); + for (const FunctionModification &mod : mods) { + if (mod.isRenameModifier()) { + m_cachedModifiedName = mod.renamedToName; + break; + } + } + if (m_cachedModifiedName.isEmpty()) + m_cachedModifiedName = name(); + } + return m_cachedModifiedName; +} + +QString AbstractMetaFunction::targetLangSignature(bool minimal) const +{ + QString s; + + // Attributes... + if (!minimal) { + // Return type + if (type()) + s += type()->name() + QLatin1Char(' '); + else + s += QLatin1String("void "); + } + + s += modifiedName(); + s += QLatin1Char('('); + + int j = 0; + for (int i = 0; i < m_arguments.size(); ++i) { + if (argumentRemoved(i + 1)) + continue; + if (j) { + s += QLatin1Char(','); + if (!minimal) + s += QLatin1Char(' '); + } + s += m_arguments.at(i)->type()->name(); + + if (!minimal) { + s += QLatin1Char(' '); + s += m_arguments.at(i)->name(); + } + ++j; + } + + s += QLatin1Char(')'); + + return s; +} + + +bool function_sorter(AbstractMetaFunction *a, AbstractMetaFunction *b) +{ + return a->signature() < b->signature(); +} + +#ifndef QT_NO_DEBUG_STREAM +static inline void formatMetaFunctionBrief(QDebug &d, const AbstractMetaFunction *af) +{ + d << '"' << af->minimalSignature() << '"'; +} + +void AbstractMetaFunction::formatDebugVerbose(QDebug &d) const +{ + d << m_functionType << ' ' << m_type << ' ' << m_name << '('; + for (int i = 0, count = m_arguments.size(); i < count; ++i) { + if (i) + d << ", "; + d << m_arguments.at(i); + } + d << "), signature=\"" << minimalSignature() << '"'; + if (m_constant) + d << " [const]"; + if (m_invalid) + d << " [invalid]"; + if (m_reverse) + d << " [reverse]"; + if (m_userAdded) + d << " [userAdded]"; + if (m_explicit) + d << " [explicit]"; + if (m_pointerOperator) + d << " [operator->]"; + if (m_isCallOperator) + d << " [operator()]"; + if (m_class) + d << " class: " << m_class->name(); + if (m_implementingClass) + d << " implementing class: " << m_implementingClass->name(); + if (m_declaringClass) + d << " declaring class: " << m_declaringClass->name(); +} + +QDebug operator<<(QDebug d, const AbstractMetaFunction *af) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AbstractMetaFunction("; + if (af) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) + if (d.verbosity() > 2) { + af->formatDebugVerbose(d); + } else { +#endif + d << "signature="; + formatMetaFunctionBrief(d, af); +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) + } +#endif + } else { + d << '0'; + } + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +/******************************************************************************* + * AbstractMetaClass + */ +AbstractMetaClass::~AbstractMetaClass() +{ + qDeleteAll(m_functions); + qDeleteAll(m_fields); + qDeleteAll(m_enums); + if (hasTemplateBaseClassInstantiations()) + qDeleteAll(templateBaseClassInstantiations()); +} + +/******************************************************************************* + * Returns true if this class is a subclass of the given class + */ +bool AbstractMetaClass::inheritsFrom(const AbstractMetaClass *cls) const +{ + Q_ASSERT(cls); + + const AbstractMetaClass *clazz = this; + while (clazz) { + if (clazz == cls) + return true; + + clazz = clazz->baseClass(); + } + + return false; +} + +/******************************************************************************* + * Constructs an interface based on the functions and enums in this + * class and returns it... + */ +AbstractMetaClass *AbstractMetaClass::extractInterface() +{ + Q_ASSERT(typeEntry()->designatedInterface()); + + if (!m_extractedInterface) { + AbstractMetaClass *iface = new AbstractMetaClass; + iface->setAttributes(attributes()); + iface->setBaseClass(0); + + iface->setTypeEntry(typeEntry()->designatedInterface()); + + for (AbstractMetaFunction *function : qAsConst(m_functions)) { + if (!function->isConstructor()) + iface->addFunction(function->copy()); + } + +// iface->setEnums(enums()); +// setEnums(AbstractMetaEnumList()); + + for (const AbstractMetaField *field : qAsConst(m_fields)) { + if (field->isPublic()) { + AbstractMetaField *new_field = field->copy(); + new_field->setEnclosingClass(iface); + iface->addField(new_field); + } + } + + m_extractedInterface = iface; + addInterface(iface); + } + + return m_extractedInterface; +} + +/******************************************************************************* + * Returns a list of all the functions with a given name + */ +AbstractMetaFunctionList AbstractMetaClass::queryFunctionsByName(const QString &name) const +{ + AbstractMetaFunctionList returned; + for (AbstractMetaFunction *function : m_functions) { + if (function->name() == name) + returned.append(function); + } + + return returned; +} + +/******************************************************************************* + * Returns a list of all the functions retrieved during parsing which should + * be added to the API. + */ +AbstractMetaFunctionList AbstractMetaClass::functionsInTargetLang() const +{ + FunctionQueryOptions default_flags = NormalFunctions | Visible | NotRemovedFromTargetLang; + + // Interfaces don't implement functions + if (isInterface()) + default_flags |= ClassImplements; + + // Only public functions in final classes + // default_flags |= isFinal() ? WasPublic : 0; + FunctionQueryOptions public_flags; + if (isFinal()) + public_flags |= WasPublic; + + // Constructors + AbstractMetaFunctionList returned = queryFunctions(Constructors | default_flags | public_flags); + + // Final functions + returned += queryFunctions(FinalInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags); + + // Virtual functions + returned += queryFunctions(VirtualInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags); + + // Static functions + returned += queryFunctions(StaticFunctions | default_flags | public_flags); + + // Empty, private functions, since they aren't caught by the other ones + returned += queryFunctions(Empty | Invisible); + + return returned; +} + +AbstractMetaFunctionList AbstractMetaClass::virtualFunctions() const +{ + const AbstractMetaFunctionList &list = functionsInShellClass(); + + AbstractMetaFunctionList returned; + for (AbstractMetaFunction *f : list) { + if (!f->isFinalInCpp() || f->isVirtualSlot()) + returned += f; + } + + return returned; +} + +AbstractMetaFunctionList AbstractMetaClass::implicitConversions() const +{ + if (!hasCloneOperator() && !hasExternalConversionOperators()) + return AbstractMetaFunctionList(); + + AbstractMetaFunctionList returned; + const AbstractMetaFunctionList list = queryFunctions(Constructors) + externalConversionOperators(); + + // Exclude anything that uses rvalue references, be it a move + // constructor "QPolygon(QPolygon &&)" or something else like + // "QPolygon(QVector &&)". + for (AbstractMetaFunction *f : list) { + if ((f->actualMinimumArgumentCount() == 1 || f->arguments().size() == 1 || f->isConversionOperator()) + && !f->isExplicit() + && f->functionType() != AbstractMetaFunction::CopyConstructorFunction + && !f->usesRValueReferences() + && !f->isModifiedRemoved() + && (f->originalAttributes() & Public)) { + returned += f; + } + } + return returned; +} + +AbstractMetaFunctionList AbstractMetaClass::operatorOverloads(OperatorQueryOptions query) const +{ + const AbstractMetaFunctionList &list = queryFunctions(OperatorOverloads | Visible); + AbstractMetaFunctionList returned; + for (AbstractMetaFunction *f : list) { + if (((query & ArithmeticOp) && f->isArithmeticOperator()) + || ((query & BitwiseOp) && f->isBitwiseOperator()) + || ((query & ComparisonOp) && f->isComparisonOperator()) + || ((query & LogicalOp) && f->isLogicalOperator()) + || ((query & SubscriptionOp) && f->isSubscriptOperator()) + || ((query & AssignmentOp) && f->isAssignmentOperator()) + || ((query & ConversionOp) && f->isConversionOperator()) + || ((query & OtherOp) && f->isOtherOperator())) + returned += f; + } + + return returned; +} + +bool AbstractMetaClass::hasOperatorOverload() const +{ + for (const AbstractMetaFunction *f : m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isOperatorOverload() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasArithmeticOperatorOverload() const +{ + for (const AbstractMetaFunction *f : m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isArithmeticOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasBitwiseOperatorOverload() const +{ + for (const AbstractMetaFunction *f : m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isBitwiseOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasComparisonOperatorOverload() const +{ + for (const AbstractMetaFunction *f : m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isComparisonOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasLogicalOperatorOverload() const +{ + for (const AbstractMetaFunction *f : m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isLogicalOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasSubscriptOperatorOverload() const +{ + for (const AbstractMetaFunction *f : m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isSubscriptOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasAssignmentOperatorOverload() const +{ + for (const AbstractMetaFunction *f : m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isAssignmentOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasConversionOperatorOverload() const +{ + for (const AbstractMetaFunction *f : m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isConversionOperator() && !f->isPrivate()) + return true; + } + return false; +} + +/******************************************************************************* + * Returns a list of all functions that should be declared and implemented in + * the shell class which is generated as a wrapper on top of the actual C++ class + */ +AbstractMetaFunctionList AbstractMetaClass::functionsInShellClass() const +{ + // Only functions and only protected and public functions + FunctionQueryOptions default_flags = NormalFunctions | Visible | WasVisible | NotRemovedFromShell; + + // All virtual functions + AbstractMetaFunctionList returned = queryFunctions(VirtualFunctions | default_flags); + + // All functions explicitly set to be implemented by the shell class + // (mainly superclass functions that are hidden by other declarations) + returned += queryFunctions(ForcedShellFunctions | default_flags); + + // All functions explicitly set to be virtual slots + returned += queryFunctions(VirtualSlots | default_flags); + + return returned; +} + +/******************************************************************************* + * Returns a list of all functions that require a public override function to + * be generated in the shell class. This includes all functions that were originally + * protected in the superclass. + */ +AbstractMetaFunctionList AbstractMetaClass::publicOverrideFunctions() const +{ + return queryFunctions(NormalFunctions | WasProtected | FinalInCppFunctions | NotRemovedFromTargetLang) + + queryFunctions(Signals | WasProtected | FinalInCppFunctions | NotRemovedFromTargetLang); +} + +AbstractMetaFunctionList AbstractMetaClass::virtualOverrideFunctions() const +{ + return queryFunctions(NormalFunctions | NonEmptyFunctions | Visible | VirtualInCppFunctions | NotRemovedFromShell) + + queryFunctions(Signals | NonEmptyFunctions | Visible | VirtualInCppFunctions | NotRemovedFromShell); +} + +void AbstractMetaClass::sortFunctions() +{ + qSort(m_functions.begin(), m_functions.end(), function_sorter); +} + +void AbstractMetaClass::setFunctions(const AbstractMetaFunctionList &functions) +{ + m_functions = functions; + + // Functions must be sorted by name before next loop + sortFunctions(); + + QString currentName; + bool hasVirtuals = false; + AbstractMetaFunctionList finalFunctions; + 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 we have non-virtual overloads of a virtual function, we have to implement + // all the overloads in the shell class to override the hiding rule + if (currentName == f->name()) { + hasVirtuals = hasVirtuals || !f->isFinal(); + if (f->isFinal()) + finalFunctions += f; + } else { + if (hasVirtuals && finalFunctions.size() > 0) { + for (AbstractMetaFunction *final_function : qAsConst(finalFunctions)) { + *final_function += AbstractMetaAttributes::ForceShellImplementation; + + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("hiding of function '%1' in class '%2'") + .arg(final_function->name(), name()); + } + } + + hasVirtuals = !f->isFinal(); + finalFunctions.clear(); + if (f->isFinal()) + finalFunctions += f; + currentName = f->name(); + } + } +} + +bool AbstractMetaClass::hasFieldAccessors() const +{ + for (const AbstractMetaField *field : m_fields) { + if (field->getter() || field->setter()) + return true; + } + + return false; +} + +bool AbstractMetaClass::hasDefaultToStringFunction() const +{ + const AbstractMetaFunctionList &funcs = queryFunctionsByName(QLatin1String("toString")); + for (const AbstractMetaFunction *f : funcs) { + if (!f->actualMinimumArgumentCount()) + return true; + } + return false; +} + +void AbstractMetaClass::addFunction(AbstractMetaFunction *function) +{ + Q_ASSERT(!function->signature().startsWith(QLatin1Char('('))); + function->setOwnerClass(this); + + if (!function->isDestructor()) + m_functions << function; + else + Q_ASSERT(false); //memory leak + + m_hasVirtualSlots |= function->isVirtualSlot(); + m_hasVirtuals |= !function->isFinal() || function->isVirtualSlot() || hasVirtualDestructor(); + m_isPolymorphic |= m_hasVirtuals; + m_hasNonpublic |= !function->isPublic(); +} + +bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const +{ + if (!other->isSignal()) + return false; + + for (const AbstractMetaFunction *f : m_functions) { + if (f->isSignal() && f->compareTo(other) & AbstractMetaFunction::EqualName) + return other->modifiedName() == f->modifiedName(); + } + + return false; +} + + +QString AbstractMetaClass::name() const +{ + return QString(m_typeEntry->targetLangName()).split(QLatin1String("::")).last(); +} + +void AbstractMetaClass::setBaseClass(AbstractMetaClass *baseClass) +{ + m_baseClass = baseClass; + if (baseClass) + m_isPolymorphic |= baseClass->isPolymorphic(); +} + +QString AbstractMetaClass::package() const +{ + return m_typeEntry->targetLangPackage(); +} + +bool AbstractMetaClass::isInterface() const +{ + return m_typeEntry->isInterface(); +} + +bool AbstractMetaClass::isNamespace() const +{ + return m_typeEntry->isNamespace(); +} + +bool AbstractMetaClass::isQObject() const +{ + return m_typeEntry->isQObject(); +} + +QString AbstractMetaClass::qualifiedCppName() const +{ + return m_typeEntry->qualifiedCppName(); +} + +bool AbstractMetaClass::hasFunction(const QString &str) const +{ + return findFunction(str); +} + +const AbstractMetaFunction* AbstractMetaClass::findFunction(const QString& functionName) const +{ + for (const AbstractMetaFunction *f : m_functions) { + if (f->name() == functionName) + return f; + } + return 0; +} + +bool AbstractMetaClass::hasProtectedFunctions() const +{ + for (AbstractMetaFunction *func : m_functions) { + if (func->isProtected()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasProtectedFields() const +{ + for (const AbstractMetaField *field : m_fields) { + if (field->isProtected()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasProtectedMembers() const +{ + return hasProtectedFields() || hasProtectedFunctions(); +} + +bool AbstractMetaClass::generateShellClass() const +{ + return m_forceShellClass || + (!isFinal() + && (hasVirtualFunctions() + || hasProtectedFunctions() + || hasFieldAccessors())); +} + +QPropertySpec *AbstractMetaClass::propertySpecForRead(const QString &name) const +{ + for (int i = 0; i < m_propertySpecs.size(); ++i) + if (name == m_propertySpecs.at(i)->read()) + return m_propertySpecs.at(i); + return 0; +} + +QPropertySpec *AbstractMetaClass::propertySpecForWrite(const QString &name) const +{ + for (int i = 0; i < m_propertySpecs.size(); ++i) + if (name == m_propertySpecs.at(i)->write()) + return m_propertySpecs.at(i); + return 0; +} + +QPropertySpec *AbstractMetaClass::propertySpecForReset(const QString &name) const +{ + for (int i = 0; i < m_propertySpecs.size(); ++i) { + if (name == m_propertySpecs.at(i)->reset()) + return m_propertySpecs.at(i); + } + return 0; +} + +typedef QHash AbstractMetaClassBaseTemplateInstantiationsMap; +Q_GLOBAL_STATIC(AbstractMetaClassBaseTemplateInstantiationsMap, metaClassBaseTemplateInstantiations); + +bool AbstractMetaClass::hasTemplateBaseClassInstantiations() const +{ + if (!templateBaseClass()) + return false; + return metaClassBaseTemplateInstantiations()->contains(this); +} + +AbstractMetaTypeList AbstractMetaClass::templateBaseClassInstantiations() const +{ + if (!templateBaseClass()) + return AbstractMetaTypeList(); + return metaClassBaseTemplateInstantiations()->value(this); +} + +void AbstractMetaClass::setTemplateBaseClassInstantiations(AbstractMetaTypeList& instantiations) +{ + if (!templateBaseClass()) + return; + metaClassBaseTemplateInstantiations()->insert(this, instantiations); +} + +static bool functions_contains(const AbstractMetaFunctionList &l, const AbstractMetaFunction *func) +{ + for (const AbstractMetaFunction *f : l) { + if ((f->compareTo(func) & AbstractMetaFunction::PrettySimilar) == AbstractMetaFunction::PrettySimilar) + return true; + } + return false; +} + +AbstractMetaField::AbstractMetaField() : m_getter(0), m_setter(0), m_class(0) +{ +} + +AbstractMetaField::~AbstractMetaField() +{ + delete m_setter; + delete m_getter; +} + +AbstractMetaField *AbstractMetaField::copy() const +{ + AbstractMetaField *returned = new AbstractMetaField; + returned->setEnclosingClass(0); + returned->setAttributes(attributes()); + returned->setName(name()); + returned->setType(type()->copy()); + returned->setOriginalAttributes(originalAttributes()); + + return returned; +} + +/******************************************************************************* + * Indicates that this field has a modification that removes it + */ +bool AbstractMetaField::isModifiedRemoved(int types) const +{ + const FieldModificationList &mods = modifications(); + for (const FieldModification &mod : mods) { + if (!mod.isRemoveModifier()) + continue; + + if ((mod.removal & types) == types) + return true; + } + + return false; +} + +static QString upCaseFirst(const QString &str) +{ + Q_ASSERT(!str.isEmpty()); + QString s = str; + s[0] = s.at(0).toUpper(); + return s; +} + +static AbstractMetaFunction *createXetter(const AbstractMetaField *g, const QString &name, + AbstractMetaAttributes::Attributes type) +{ + AbstractMetaFunction *f = new AbstractMetaFunction; + + f->setName(name); + f->setOriginalName(name); + f->setOwnerClass(g->enclosingClass()); + f->setImplementingClass(g->enclosingClass()); + f->setDeclaringClass(g->enclosingClass()); + + AbstractMetaAttributes::Attributes attr = AbstractMetaAttributes::Native + | AbstractMetaAttributes::Final + | type; + if (g->isStatic()) + attr |= AbstractMetaAttributes::Static; + if (g->isPublic()) + attr |= AbstractMetaAttributes::Public; + else if (g->isProtected()) + attr |= AbstractMetaAttributes::Protected; + else + attr |= AbstractMetaAttributes::Private; + f->setAttributes(attr); + f->setOriginalAttributes(attr); + + const FieldModificationList &mods = g->modifications(); + for (const FieldModification &mod : mods) { + if (mod.isRenameModifier()) + f->setName(mod.renamedTo()); + if (mod.isAccessModifier()) { + if (mod.isPrivate()) + f->setVisibility(AbstractMetaAttributes::Private); + else if (mod.isProtected()) + f->setVisibility(AbstractMetaAttributes::Protected); + else if (mod.isPublic()) + f->setVisibility(AbstractMetaAttributes::Public); + else if (mod.isFriendly()) + f->setVisibility(AbstractMetaAttributes::Friendly); + } + } + return f; +} + +FieldModificationList AbstractMetaField::modifications() const +{ + const FieldModificationList &mods = enclosingClass()->typeEntry()->fieldModifications(); + FieldModificationList returned; + + for (const FieldModification &mod : mods) { + if (mod.name == name()) + returned += mod; + } + + return returned; +} + +const AbstractMetaFunction *AbstractMetaField::setter() const +{ + if (!m_setter) { + m_setter = createXetter(this, + QLatin1String("set") + upCaseFirst(name()), + AbstractMetaAttributes::SetterFunction); + AbstractMetaArgumentList arguments; + AbstractMetaArgument *argument = new AbstractMetaArgument; + argument->setType(type()->copy()); + argument->setName(name()); + arguments.append(argument); + m_setter->setArguments(arguments); + } + return m_setter; +} + +const AbstractMetaFunction *AbstractMetaField::getter() const +{ + if (!m_getter) { + m_getter = createXetter(this, + name(), + AbstractMetaAttributes::GetterFunction); + m_getter->setType(type()); + } + + return m_getter; +} + +#ifndef QT_NO_DEBUG_STREAM +static void formatMetaAttributes(QDebug &d, AbstractMetaAttributes::Attributes value) +{ + static const int meIndex = AbstractMetaAttributes::staticMetaObject.indexOfEnumerator("Attribute"); + Q_ASSERT(meIndex >= 0); + const QMetaEnum me = AbstractMetaAttributes::staticMetaObject.enumerator(meIndex); + d << me.valueToKeys(value); +} + +static void formatMetaField(QDebug &d, const AbstractMetaField *af) +{ + formatMetaAttributes(d, af->attributes()); + d << ' ' << af->type()->name() << " \"" << af->name() << '"'; +} + +QDebug operator<<(QDebug d, const AbstractMetaField *af) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AbstractMetaField("; + if (af) + formatMetaField(d, af); + else + d << '0'; + d << ')'; + return d; +} + +static void formatMetaEnumValue(QDebug &d, const AbstractMetaEnumValue *v) +{ + const QString &name = v->stringValue(); + if (!name.isEmpty()) + d << name << '='; + d << v->value(); +} + +QDebug operator<<(QDebug d, const AbstractMetaEnumValue *v) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AbstractMetaEnumValue("; + if (v) + formatMetaEnumValue(d, v); + else + d << '0'; + d << ')'; + return d; +} + +QDebug operator<<(QDebug d, const AbstractMetaEnum *ae) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AbstractMetaEnum("; + if (ae) { + d << ae->fullName() << '['; + const AbstractMetaEnumValueList &values = ae->values(); + for (int i = 0, count = values.size(); i < count; ++i) { + if (i) + d << ' '; + formatMetaEnumValue(d, values.at(i)); + } + d << ']'; + } else { + d << '0'; + } + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +bool AbstractMetaClass::hasConstructors() const +{ + return queryFunctions(Constructors).size(); +} + +bool AbstractMetaClass::hasCopyConstructor() const +{ + const AbstractMetaFunctionList &ctors = queryFunctions(Constructors); + for (const AbstractMetaFunction* ctor : ctors) { + if (ctor->functionType() == AbstractMetaFunction::CopyConstructorFunction) + return true; + } + return false; +} + +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; +} + +void AbstractMetaClass::addDefaultConstructor() +{ + AbstractMetaFunction *f = new AbstractMetaFunction; + f->setOriginalName(name()); + f->setName(name()); + f->setOwnerClass(this); + f->setFunctionType(AbstractMetaFunction::ConstructorFunction); + f->setArguments(AbstractMetaArgumentList()); + f->setDeclaringClass(this); + + AbstractMetaAttributes::Attributes attr = AbstractMetaAttributes::Native; + attr |= AbstractMetaAttributes::Public; + attr |= AbstractMetaAttributes::Final; + f->setAttributes(attr); + f->setImplementingClass(this); + f->setOriginalAttributes(f->attributes()); + + addFunction(f); + this->setHasNonPrivateConstructor(true); +} + +void AbstractMetaClass::addDefaultCopyConstructor(bool isPrivate) +{ + AbstractMetaFunction* f = new AbstractMetaFunction; + f->setOriginalName(name()); + f->setName(name()); + f->setOwnerClass(this); + f->setFunctionType(AbstractMetaFunction::CopyConstructorFunction); + f->setDeclaringClass(this); + + AbstractMetaType* argType = new AbstractMetaType; + argType->setTypeEntry(typeEntry()); + argType->setReferenceType(LValueReference); + argType->setConstant(true); + argType->setTypeUsagePattern(AbstractMetaType::ValuePattern); + + AbstractMetaArgument* arg = new AbstractMetaArgument; + arg->setType(argType); + arg->setName(name()); + f->addArgument(arg); + + AbstractMetaAttributes::Attributes attr = AbstractMetaAttributes::Native; + attr |= AbstractMetaAttributes::Final; + if (isPrivate) + attr |= AbstractMetaAttributes::Private; + else + attr |= AbstractMetaAttributes::Public; + f->setAttributes(attr); + f->setImplementingClass(this); + f->setOriginalAttributes(f->attributes()); + + addFunction(f); +} + +bool AbstractMetaClass::hasFunction(const AbstractMetaFunction *f) const +{ + return functions_contains(m_functions, f); +} + +/* 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 +{ + AbstractMetaFunctionList functions; + + for (AbstractMetaFunction *f : m_functions) { + + if ((query & VirtualSlots) && !f->isVirtualSlot()) + continue; + + if ((query & NotRemovedFromTargetLang) && f->isRemovedFrom(f->implementingClass(), TypeSystem::TargetLangCode)) + continue; + + if ((query & NotRemovedFromTargetLang) && !f->isFinal() && f->isRemovedFrom(f->declaringClass(), TypeSystem::TargetLangCode)) + continue; + + if ((query & NotRemovedFromShell) && f->isRemovedFrom(f->implementingClass(), TypeSystem::ShellCode)) + continue; + + if ((query & NotRemovedFromShell) && !f->isFinal() && f->isRemovedFrom(f->declaringClass(), TypeSystem::ShellCode)) + continue; + + if ((query & Visible) && f->isPrivate()) + continue; + + if ((query & VirtualInTargetLangFunctions) && f->isFinalInTargetLang()) + continue; + + if ((query & Invisible) && !f->isPrivate()) + continue; + + if ((query & Empty) && !f->isEmptyFunction()) + continue; + + if ((query & WasPublic) && !f->wasPublic()) + continue; + + if ((query & WasVisible) && f->wasPrivate()) + continue; + + if ((query & WasProtected) && !f->wasProtected()) + continue; + + if ((query & ClassImplements) && f->ownerClass() != f->implementingClass()) + continue; + + if ((query & Inconsistent) && (f->isFinalInTargetLang() || !f->isFinalInCpp() || f->isStatic())) + continue; + + if ((query & FinalInTargetLangFunctions) && !f->isFinalInTargetLang()) + continue; + + if ((query & FinalInCppFunctions) && !f->isFinalInCpp()) + continue; + + if ((query & VirtualInCppFunctions) && f->isFinalInCpp()) + continue; + + if ((query & Signals) && (!f->isSignal())) + continue; + + if ((query & ForcedShellFunctions) && + (!f->isForcedShellImplementation() || !f->isFinal())) { + continue; + } + + if ((query & Constructors) && (!f->isConstructor() || f->ownerClass() != f->implementingClass())) + continue; + + if (!(query & Constructors) && f->isConstructor()) + continue; + + // 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; + }*/ + + if ((query & VirtualFunctions) && (f->isFinal() || f->isSignal() || f->isStatic())) + continue; + + if ((query & StaticFunctions) && (!f->isStatic() || f->isSignal())) + continue; + + if ((query & NonStaticFunctions) && (f->isStatic())) + continue; + + if ((query & NonEmptyFunctions) && (f->isEmptyFunction())) + continue; + + if ((query & NormalFunctions) && (f->isSignal())) + continue; + + if ((query & AbstractFunctions) && !f->isAbstract()) + continue; + + if ((query & OperatorOverloads) && !f->isOperatorOverload()) + continue; + + functions << f; + } + + return functions; +} + +bool AbstractMetaClass::hasSignals() const +{ + return cppSignalFunctions().size() > 0; +} + + +/** + * Adds the specified interface to this class by adding all the + * functions in the interface to this class. + */ +void AbstractMetaClass::addInterface(AbstractMetaClass *interface) +{ + Q_ASSERT(!m_interfaces.contains(interface)); + m_interfaces << interface; + + m_isPolymorphic |= interface->isPolymorphic(); + + if (m_extractedInterface && m_extractedInterface != interface) + m_extractedInterface->addInterface(interface); + + +#if 0 + const AbstractMetaFunctionList &funcs = interface->functions(); + for (AbstractMetaFunction *function : funcs) + if (!hasFunction(function) && !function->isConstructor()) { + AbstractMetaFunction *cpy = function->copy(); + cpy->setImplementingClass(this); + + // Setup that this function is an interface class. + cpy->setInterfaceClass(interface); + *cpy += AbstractMetaAttributes::InterfaceFunction; + + // Copy the modifications in interface into the implementing classes. + const FunctionModificationList &mods = function->modifications(interface); + for (const FunctionModification &mod : mods) + m_typeEntry->addFunctionModification(mod); + + // It should be mostly safe to assume that when we implement an interface + // we don't "pass on" pure virtual functions to our sublcasses... +// *cpy -= AbstractMetaAttributes::Abstract; + + addFunction(cpy); + } +#endif + +} + + +void AbstractMetaClass::setInterfaces(const AbstractMetaClassList &interfaces) +{ + m_interfaces = interfaces; + for (const AbstractMetaClass *interface : interfaces) { + if (interface) + m_isPolymorphic |= interface->isPolymorphic(); + } +} + + +AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName) +{ + for (AbstractMetaEnum *e : qAsConst(m_enums)) { + if (e->name() == enumName) + return e; + } + + if (typeEntry()->designatedInterface()) + return extractInterface()->findEnum(enumName); + + return 0; +} + + + + +/*! Recursivly searches for the enum value named \a enumValueName in + this class and its superclasses and interfaces. Values belonging to + \a meta_enum are excluded from the search. +*/ +AbstractMetaEnumValue *AbstractMetaClass::findEnumValue(const QString &enumValueName, AbstractMetaEnum *meta_enum) +{ + for (AbstractMetaEnum *e : qAsConst(m_enums)) { + if (e != meta_enum) + continue; + const AbstractMetaEnumValueList &values = e->values(); + for (AbstractMetaEnumValue *v : values) { + if (v->name() == enumValueName) + return v; + } + } + + if (typeEntry()->designatedInterface()) + return extractInterface()->findEnumValue(enumValueName, meta_enum); + + if (baseClass()) + return baseClass()->findEnumValue(enumValueName, meta_enum); + + return 0; +} + + +/*! + * Searches through all of this class' enums for a value matching the + * name \a enumValueName. The name is excluding the class/namespace + * prefix. The function recursivly searches interfaces and baseclasses + * of this class. + */ +AbstractMetaEnum *AbstractMetaClass::findEnumForValue(const QString &enumValueName) +{ + for (AbstractMetaEnum *e : qAsConst(m_enums)) { + const AbstractMetaEnumValueList &values = e->values(); + for (AbstractMetaEnumValue *v : values) { + if (v->name() == enumValueName) + return e; + } + } + + if (typeEntry()->designatedInterface()) + return extractInterface()->findEnumForValue(enumValueName); + + if (baseClass()) + return baseClass()->findEnumForValue(enumValueName); + + return 0; +} + + +static void addExtraIncludeForType(AbstractMetaClass *metaClass, const AbstractMetaType *type) +{ + if (!type) + return; + + Q_ASSERT(metaClass); + const TypeEntry *entry = (type ? type->typeEntry() : 0); + if (entry && entry->isComplex()) { + const ComplexTypeEntry *centry = static_cast(entry); + ComplexTypeEntry *class_entry = metaClass->typeEntry(); + if (class_entry && centry->include().isValid()) + class_entry->addExtraInclude(centry->include()); + } + + if (type->hasInstantiations()) { + const AbstractMetaTypeList &instantiations = type->instantiations(); + for (const AbstractMetaType *instantiation : instantiations) + addExtraIncludeForType(metaClass, instantiation); + } +} + +static void addExtraIncludesForFunction(AbstractMetaClass *metaClass, const AbstractMetaFunction *meta_function) +{ + Q_ASSERT(metaClass); + Q_ASSERT(meta_function); + addExtraIncludeForType(metaClass, meta_function->type()); + + const AbstractMetaArgumentList &arguments = meta_function->arguments(); + for (AbstractMetaArgument *argument : arguments) + addExtraIncludeForType(metaClass, argument->type()); +} + +void AbstractMetaClass::fixFunctions() +{ + if (m_functionsFixed) + return; + else + m_functionsFixed = true; + + AbstractMetaClass *superClass = baseClass(); + AbstractMetaFunctionList funcs = functions(); + + if (superClass) + superClass->fixFunctions(); + int iface_idx = 0; + while (superClass || iface_idx < interfaces().size()) { + // Since we always traverse the complete hierarchy we are only + // interrested in what each super class implements, not what + // we may have propagated from their base classes again. + AbstractMetaFunctionList superFuncs; + if (superClass) { + // Super classes can never be final + if (superClass->isFinalInTargetLang()) { + qCWarning(lcShiboken).noquote().nospace() + << "Final class '" << superClass->name() << "' set to non-final, as it is extended by other classes"; + *superClass -= AbstractMetaAttributes::FinalInTargetLang; + } + superFuncs = superClass->queryFunctions(AbstractMetaClass::ClassImplements); + AbstractMetaFunctionList virtuals = superClass->queryFunctions(AbstractMetaClass::VirtualInCppFunctions); + superFuncs += virtuals; + } else { + superFuncs = interfaces().at(iface_idx)->queryFunctions(AbstractMetaClass::NormalFunctions); + AbstractMetaFunctionList virtuals = interfaces().at(iface_idx)->queryFunctions(AbstractMetaClass::VirtualInCppFunctions); + superFuncs += virtuals; + } + + QSet funcsToAdd; + for (int sfi = 0; sfi < superFuncs.size(); ++sfi) { + AbstractMetaFunction *sf = superFuncs.at(sfi); + + if (sf->isRemovedFromAllLanguages(sf->implementingClass())) + continue; + + // skip functions added in base classes + if (sf->isUserAdded() && sf->declaringClass() != this) + continue; + + // we generally don't care about private functions, but we have to get the ones that are + // virtual in case they override abstract functions. + bool add = (sf->isNormal() || sf->isSignal() || sf->isEmptyFunction()); + for (int fi = 0; fi < funcs.size(); ++fi) { + AbstractMetaFunction *f = funcs.at(fi); + if (f->isRemovedFromAllLanguages(f->implementingClass())) + continue; + + + const AbstractMetaFunction::CompareResult cmp = f->compareTo(sf); + + if (cmp & AbstractMetaFunction::EqualModifiedName) { + add = false; + if (cmp & AbstractMetaFunction::EqualArguments) { + // Same function, propegate virtual... + if (!(cmp & AbstractMetaFunction::EqualAttributes)) { + if (!f->isEmptyFunction()) { + if (!sf->isFinalInCpp() && f->isFinalInCpp()) { + *f -= AbstractMetaAttributes::FinalInCpp; + } + if (!sf->isFinalInTargetLang() && f->isFinalInTargetLang()) { + *f -= AbstractMetaAttributes::FinalInTargetLang; + } +#if 0 + if (!f->isFinalInTargetLang() && f->isPrivate()) { + f->setFunctionType(AbstractMetaFunction::EmptyFunction); + f->setVisibility(AbstractMetaAttributes::Protected); + *f += AbstractMetaAttributes::FinalInTargetLang; + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("private virtual function '%1' in '%2'") + .arg(f->signature(), f->implementingClass()->name()); + } +#endif + } + } + + if (f->visibility() != sf->visibility()) { + QString warn = QStringLiteral("visibility of function '%1' modified in class '%2'") + .arg(f->name(), name()); + qCWarning(lcShiboken).noquote().nospace() << warn; +#if 0 + // If new visibility is private, we can't + // do anything. If it isn't, then we + // prefer the parent class's visibility + // setting for the function. + if (!f->isPrivate() && !sf->isPrivate()) + f->setVisibility(sf->visibility()); +#endif + // Private overrides of abstract functions have to go into the class or + // the subclasses will not compile as non-abstract classes. + // But they don't need to be implemented, since they can never be called. + if (f->isPrivate()) { + f->setFunctionType(AbstractMetaFunction::EmptyFunction); + *f += AbstractMetaAttributes::FinalInTargetLang; + *f += AbstractMetaAttributes::FinalInCpp; + } + } + + // Set the class which first declares this function, afawk + f->setDeclaringClass(sf->declaringClass()); + + if (sf->isFinalInTargetLang() && !sf->isPrivate() && !f->isPrivate() && !sf->isStatic() && !f->isStatic()) { + // Shadowed funcion, need to make base class + // function non-virtual + if (f->implementingClass() != sf->implementingClass() && f->implementingClass()->inheritsFrom(sf->implementingClass())) { + + // Check whether the superclass method has been redefined to non-final + + bool hasNonFinalModifier = false; + bool isBaseImplPrivate = false; + const FunctionModificationList &mods = sf->modifications(sf->implementingClass()); + for (const FunctionModification &mod : mods) { + if (mod.isNonFinal()) { + hasNonFinalModifier = true; + break; + } else if (mod.isPrivate()) { + isBaseImplPrivate = true; + break; + } + } + + if (!hasNonFinalModifier && !isBaseImplPrivate) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("Shadowing: %1::%2 and %3::%4") + .arg(sf->implementingClass()->name(), sf->signature(), + f->implementingClass()->name(), f->signature()); + } + } + } + + } + + if (cmp & AbstractMetaFunction::EqualDefaultValueOverload) { + AbstractMetaArgumentList arguments; + if (f->arguments().size() < sf->arguments().size()) + arguments = sf->arguments(); + else + arguments = f->arguments(); + //TODO: fix this + //for (int i=0; isetDefaultValueExpression("<#>" + QString()); + } + + + // Otherwise we have function shadowing and we can + // skip the thing... + } else if (cmp & AbstractMetaFunction::EqualName && !sf->isSignal()) { + // In the case of function shadowing where the function name has been altered to + // avoid conflict, we don't copy in the original. + add = false; + } + } + + if (add) + funcsToAdd << sf; + } + + for (AbstractMetaFunction *f : qAsConst(funcsToAdd)) + funcs << f->copy(); + + if (superClass) + superClass = superClass->baseClass(); + else + iface_idx++; + } + + bool hasPrivateConstructors = false; + bool hasPublicConstructors = false; + for (AbstractMetaFunction *func : qAsConst(funcs)) { + const FunctionModificationList &mods = func->modifications(this); + for (const FunctionModification &mod : mods) { + if (mod.isRenameModifier()) { + func->setName(mod.renamedTo()); + } + } + + // Make sure class is abstract if one of the functions is + if (func->isAbstract()) { + (*this) += AbstractMetaAttributes::Abstract; + (*this) -= AbstractMetaAttributes::Final; + } + + if (func->isConstructor()) { + if (func->isPrivate()) + hasPrivateConstructors = true; + else + hasPublicConstructors = true; + } + + + + // Make sure that we include files for all classes that are in use + + if (!func->isRemovedFrom(this, TypeSystem::ShellCode)) + addExtraIncludesForFunction(this, func); + } + + if (hasPrivateConstructors && !hasPublicConstructors) { + (*this) += AbstractMetaAttributes::Abstract; + (*this) -= AbstractMetaAttributes::Final; + } + + for (AbstractMetaFunction *f1 : qAsConst(funcs)) { + for (AbstractMetaFunction *f2 : qAsConst(funcs)) { + if (f1 != f2) { + const AbstractMetaFunction::CompareResult cmp = f1->compareTo(f2); + if ((cmp & AbstractMetaFunction::EqualName) + && !f1->isFinalInCpp() + && f2->isFinalInCpp()) { + *f2 += AbstractMetaAttributes::FinalOverload; + } + } + } + } + + setFunctions(funcs); +} + + +QString AbstractMetaType::minimalSignature() const +{ + QString minimalSignature; + if (isConstant()) + minimalSignature += QLatin1String("const "); + minimalSignature += typeEntry()->qualifiedCppName(); + if (hasInstantiations()) { + AbstractMetaTypeList instantiations = this->instantiations(); + minimalSignature += QLatin1String("< "); + for (int i = 0; i < instantiations.size(); ++i) { + if (i > 0) + minimalSignature += QLatin1Char(','); + minimalSignature += instantiations[i]->minimalSignature(); + } + minimalSignature += QLatin1String(" >"); + } + + for (int j = 0; j < indirections(); ++j) + minimalSignature += QLatin1Char('*'); + switch (referenceType()) { + case NoReference: + break; + case LValueReference: + minimalSignature += QLatin1Char('&'); + break; + case RValueReference: + minimalSignature += QLatin1String("&&"); + break; + } + + return minimalSignature; +} + +bool AbstractMetaType::hasNativeId() const +{ + return (isQObject() || isValue() || isObject()) && typeEntry()->isNativeIdBased(); +} + +bool AbstractMetaType::isTargetLangEnum() const +{ + return isEnum() && !static_cast(typeEntry())->forceInteger(); +} + +bool AbstractMetaType::isTargetLangFlags() const +{ + return isFlags() && !static_cast(typeEntry())->forceInteger(); +} + + +/******************************************************************************* + * Other stuff... + */ + + +AbstractMetaEnum *AbstractMetaClass::findEnum(const AbstractMetaClassList &classes, + const EnumTypeEntry *entry) +{ + Q_ASSERT(entry->isEnum()); + + QString qualifiedName = entry->qualifiedCppName(); + int pos = qualifiedName.lastIndexOf(QLatin1String("::")); + + QString enumName; + QString className; + + if (pos > 0) { + enumName = qualifiedName.mid(pos + 2); + className = qualifiedName.mid(0, pos); + } else { + enumName = qualifiedName; + className = TypeDatabase::globalNamespaceClassName(entry); + } + + AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes, className); + if (!metaClass) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("AbstractMeta::findEnum(), unknown class '%1' in '%2'") + .arg(className, entry->qualifiedCppName()); + return 0; + } + + return metaClass->findEnum(enumName); +} + +AbstractMetaEnumValue *AbstractMetaClass::findEnumValue(const AbstractMetaClassList &classes, + const QString &name) +{ + QStringList lst = name.split(QLatin1String("::")); + + if (lst.size() > 1) { + QString prefixName = lst.at(0); + QString enumName = lst.at(1); + + AbstractMetaClass* cl = findClass(classes, prefixName); + if (cl) + return cl->findEnumValue(enumName, 0); + } + + for (AbstractMetaClass *metaClass : classes) { + const AbstractMetaEnumList &enums = metaClass->enums(); + for (AbstractMetaEnum *metaEnum : enums) { + AbstractMetaEnumValue* enumValue = metaClass->findEnumValue(name, metaEnum); + if (enumValue) + return enumValue; + } + } + + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("no matching enum '%1'").arg(name); + return 0; +} + +/*! + * Searches the list after a class that mathces \a name; either as + * C++, Target language base name or complete Target language package.class name. + */ + +AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassList &classes, + const QString &name) +{ + if (name.isEmpty()) + return 0; + + for (AbstractMetaClass *c : classes) { + if (c->qualifiedCppName() == name) + return c; + } + + for (AbstractMetaClass *c : classes) { + if (c->fullName() == name) + return c; + } + + for (AbstractMetaClass *c : classes) { + if (c->name() == name) + return c; + } + + return 0; +} + +AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassList &classes, + const TypeEntry* typeEntry) +{ + for (AbstractMetaClass* c : classes) { + if (c->typeEntry() == typeEntry) + return c; + } + return 0; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaClass *ac) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AbstractMetaClass("; + if (ac) { + d << '"' << ac->fullName() << '"'; + if (ac->m_baseClass) + d << ", inherits \"" << ac->m_baseClass->name() << '"'; + const AbstractMetaEnumList &enums = ac->enums(); + if (!enums.isEmpty()) + d << ", enums[" << enums.size() << "]=" << enums; + const AbstractMetaFunctionList &functions = ac->functions(); + if (!functions.isEmpty()) { + const int count = functions.size(); + d << ", functions=[" << count << "]("; + for (int i = 0; i < count; ++i) { + if (i) + d << ", "; +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) + if (d.verbosity() > 2) + d << functions.at(i); + else +#endif + formatMetaFunctionBrief(d, functions.at(i)); + } + d << ')'; + } + const AbstractMetaFieldList &fields = ac->fields(); + if (!fields.isEmpty()) { + const int count = fields.size(); + d << ", fields=[" << count << "]("; + for (int i = 0; i < count; ++i) { + if (i) + d << ", "; + formatMetaField(d, fields.at(i)); + } + d << ')'; + } + } else { + d << '0'; + } + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +QString AbstractMetaEnum::name() const +{ + return m_typeEntry->targetLangName(); +} + +QString AbstractMetaEnum::qualifier() const +{ + return m_typeEntry->targetLangQualifier(); +} + +QString AbstractMetaEnum::package() const +{ + return m_typeEntry->targetLangPackage(); +} + +bool AbstractMetaEnum::isAnonymous() const +{ + return m_typeEntry->isAnonymous(); +} diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h new file mode 100644 index 000000000..4d6d5fb1f --- /dev/null +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h @@ -0,0 +1,1976 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 ABSTRACTMETALANG_H +#define ABSTRACTMETALANG_H + +#include "abstractmetalang_typedefs.h" +#include "typesystem_enums.h" +#include "typesystem_typedefs.h" + +#include "parser/codemodel_enums.h" + +#include +#include + +QT_FORWARD_DECLARE_CLASS(QDebug) + +class AbstractMeta; +class AbstractMetaClass; +class AbstractMetaField; +class AbstractMetaFunction; +class AbstractMetaType; +class AbstractMetaVariable; +class AbstractMetaArgument; +class AbstractMetaEnumValue; +class AbstractMetaEnum; +class QPropertySpec; + +class CodeSnip; +class ComplexTypeEntry; +class EnumTypeEntry; +class FlagsTypeEntry; +class FunctionTypeEntry; +class TypeEntry; + +struct ArgumentOwner; +struct FieldModification; +struct FunctionModification; +struct ReferenceCount; + +class Documentation +{ +public: + enum Format { + Native, + Target + }; + + Documentation() + : m_format(Documentation::Native) {} + + Documentation(const QString& value, Format fmt = Documentation::Native) + : m_data(value), m_format(fmt) {} + + QString value() const + { + return m_data; + } + + void setValue(const QString& value, Format fmt = Documentation::Native) + { + m_data = value; m_format = fmt; + } + + Documentation::Format format() const + { + return m_format; + } + +private: + QString m_data; + Format m_format; + +}; + +class AbstractMetaAttributes +{ + Q_GADGET +public: + AbstractMetaAttributes() : m_attributes(0), m_originalAttributes(0) {}; + + enum Attribute { + None = 0x00000000, + + Private = 0x00000001, + Protected = 0x00000002, + Public = 0x00000004, + Friendly = 0x00000008, + Visibility = 0x0000000f, + + Native = 0x00000010, + Abstract = 0x00000020, + Static = 0x00000040, + + FinalInTargetLang = 0x00000080, + FinalInCpp = 0x00000100, + ForceShellImplementation = 0x00000200, + + GetterFunction = 0x00000400, + SetterFunction = 0x00000800, + + FinalOverload = 0x00001000, + InterfaceFunction = 0x00002000, + + PropertyReader = 0x00004000, + PropertyWriter = 0x00008000, + PropertyResetter = 0x00010000, + + Fake = 0x00020000, + + Invokable = 0x00040000, + + Final = FinalInTargetLang | FinalInCpp + }; + Q_DECLARE_FLAGS(Attributes, Attribute) + Q_FLAG(Attribute) + + Attributes attributes() const + { + return m_attributes; + } + + void setAttributes(Attributes attributes) + { + m_attributes = attributes; + } + + Attributes originalAttributes() const + { + return m_originalAttributes; + } + + void setOriginalAttributes(Attributes attributes) + { + m_originalAttributes = attributes; + } + + Attributes visibility() const + { + return m_attributes & Visibility; + } + + void setVisibility(Attributes visi) + { + m_attributes = (m_attributes & ~Visibility) | visi; + } + + void operator+=(Attribute attribute) + { + m_attributes |= attribute; + } + + void operator-=(Attribute attribute) + { + m_attributes &= ~attribute; + } + + bool isNative() const + { + return m_attributes & Native; + } + + bool isFinal() const + { + return (m_attributes & Final) == Final; + } + + bool isFinalInTargetLang() const + { + return m_attributes & FinalInTargetLang; + } + + bool isFinalInCpp() const + { + return m_attributes & FinalInCpp; + } + + bool isAbstract() const + { + return m_attributes & Abstract; + } + + bool isStatic() const + { + return m_attributes & Static; + } + + bool isForcedShellImplementation() const + { + return m_attributes & ForceShellImplementation; + } + + bool isInterfaceFunction() const + { + return m_attributes & InterfaceFunction; + } + + bool isFinalOverload() const + { + return m_attributes & FinalOverload; + } + + bool isInvokable() const + { + return m_attributes & Invokable; + } + + bool isPropertyReader() const + { + return m_attributes & PropertyReader; + } + + bool isPropertyWriter() const + { + return m_attributes & PropertyWriter; + } + + bool isPropertyResetter() const + { + return m_attributes & PropertyResetter; + } + + bool isPrivate() const + { + return m_attributes & Private; + } + + bool isProtected() const + { + return m_attributes & Protected; + } + + bool isPublic() const + { + return m_attributes & Public; + } + + bool isFriendly() const + { + return m_attributes & Friendly; + } + + bool wasPrivate() const + { + return m_originalAttributes & Private; + } + + bool wasProtected() const + { + return m_originalAttributes & Protected; + } + + bool wasPublic() const + { + return m_originalAttributes & Public; + } + + bool wasFriendly() const + { + return m_originalAttributes & Friendly; + } + + void setDocumentation(const Documentation& doc) + { + m_doc = doc; + } + + Documentation documentation() const + { + return m_doc; + } + +private: + Attributes m_attributes; + Attributes m_originalAttributes; + Documentation m_doc; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaAttributes::Attributes) + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaAttributes *aa); +#endif + +class AbstractMetaType +{ + Q_GADGET +public: + + enum TypeUsagePattern { + InvalidPattern, + PrimitivePattern, + FlagsPattern, + EnumPattern, + ValuePattern, + StringPattern, + CharPattern, + ObjectPattern, + QObjectPattern, + ValuePointerPattern, + NativePointerPattern, + ContainerPattern, + SmartPointerPattern, + VariantPattern, + VarargsPattern, + JObjectWrapperPattern, + ArrayPattern, + ThreadPattern + }; + Q_ENUM(TypeUsagePattern) + + AbstractMetaType(); + ~AbstractMetaType(); + + QString package() const; + QString name() const; + QString fullName() const; + + void setTypeUsagePattern(TypeUsagePattern pattern) + { + m_pattern = pattern; + } + TypeUsagePattern typeUsagePattern() const + { + return m_pattern; + } + + // true when use pattern is container + bool hasInstantiations() const + { + return !m_instantiations.isEmpty(); + } + + void addInstantiation(AbstractMetaType* inst, bool owner = false) + { + if (owner) + m_children << inst; + m_instantiations << inst; + } + + void setInstantiations(const AbstractMetaTypeList &insts, bool owner = false) + { + m_instantiations = insts; + if (owner) { + m_children.clear(); + m_children = insts; + } + } + + AbstractMetaTypeList instantiations() const + { + return m_instantiations; + } + + void setInstantiationInCpp(bool incpp) + { + m_cppInstantiation = incpp; + } + bool hasInstantiationInCpp() const + { + return hasInstantiations() && m_cppInstantiation; + } + + QString minimalSignature() const; + + // true when the type is a QtJambiObject subclass + bool hasNativeId() const; + + // returns true if the typs is used as a non complex primitive, no & or *'s + bool isPrimitive() const + { + return m_pattern == PrimitivePattern; + } + + // returns true if the type is used as an enum + bool isEnum() const + { + return m_pattern == EnumPattern; + } + + // returns true if the type is used as a QObject * + bool isQObject() const + { + return m_pattern == QObjectPattern; + } + + // returns true if the type is used as an object, e.g. Xxx * + bool isObject() const + { + return m_pattern == ObjectPattern; + } + + // returns true if the type is used as an array, e.g. Xxx[42] + bool isArray() const + { + return m_pattern == ArrayPattern; + } + + // returns true if the type is used as a value type (X or const X &) + bool isValue() const + { + return m_pattern == ValuePattern; + } + + bool isValuePointer() const + { + return m_pattern == ValuePointerPattern; + } + + // returns true for more complex types... + bool isNativePointer() const + { + return m_pattern == NativePointerPattern; + } + + // returns true if the type was originally a QString or const QString & or equivalent for QLatin1String + bool isTargetLangString() const + { + return m_pattern == StringPattern; + } + + // returns true if the type was originally a QChar or const QChar & + bool isTargetLangChar() const + { + return m_pattern == CharPattern; + } + + // return true if the type was originally a QVariant or const QVariant & + bool isVariant() const + { + return m_pattern == VariantPattern; + } + + // return true if the type was originally a varargs + bool isVarargs() const + { + return m_pattern == VarargsPattern; + } + + // return true if the type was originally a JObjectWrapper or const JObjectWrapper & + bool isJObjectWrapper() const + { + return m_pattern == JObjectWrapperPattern; + } + + // returns true if the type was used as a container + bool isContainer() const + { + return m_pattern == ContainerPattern; + } + + // returns true if the type was used as a smart pointer + bool isSmartPointer() const { return m_pattern == SmartPointerPattern; } + + // returns true if the type was used as a flag + bool isFlags() const + { + return m_pattern == FlagsPattern; + } + + // returns true if the type was used as a thread + bool isThread() const + { + return m_pattern == ThreadPattern; + } + + bool isConstant() const + { + return m_constant; + } + void setConstant(bool constant) + { + m_constant = constant; + } + + ReferenceType referenceType() const { return m_referenceType; } + void setReferenceType(ReferenceType ref) { m_referenceType = ref; } + + /** + * Says if the type is to be implemented using target language + * equivalent of C++ enums, i.e. not plain ints. + * /return true if the type is to be implemented using target + * language enums + */ + bool isTargetLangEnum() const; + bool isIntegerEnum() const + { + return isEnum() && !isTargetLangEnum(); + } + + /** + * Says if the type is to be implemented using target language + * equivalent of Qt's QFlags, i.e. not plain ints. + * /return true if the type is to be implemented using target + * language QFlags + */ + bool isTargetLangFlags() const; + bool isIntegerFlags() const + { + return isFlags() && !isTargetLangFlags(); + } + + int actualIndirections() const + { + return m_indirections + (m_referenceType == LValueReference ? 1 : 0); + } + int indirections() const + { + return m_indirections; + } + void setIndirections(int indirections) + { + m_indirections = indirections; + } + + void setArrayElementCount(int n) + { + m_arrayElementCount = n; + } + int arrayElementCount() const + { + return m_arrayElementCount; + } + + const AbstractMetaType *arrayElementType() const + { + return m_arrayElementType; + } + void setArrayElementType(const AbstractMetaType *t) + { + m_arrayElementType = t; + } + + QString cppSignature() const; + + AbstractMetaType *copy() const; + + const TypeEntry *typeEntry() const + { + return m_typeEntry; + } + void setTypeEntry(const TypeEntry *type) + { + m_typeEntry = type; + } + + void setOriginalTypeDescription(const QString &otd) + { + m_originalTypeDescription = otd; + } + QString originalTypeDescription() const + { + return m_originalTypeDescription; + } + + void setOriginalTemplateType(const AbstractMetaType *type) + { + m_originalTemplateType = type; + } + const AbstractMetaType *originalTemplateType() const + { + return m_originalTemplateType; + } + + AbstractMetaType *getSmartPointerInnerType() const + { + Q_ASSERT(isSmartPointer()); + AbstractMetaTypeList instantiations = this->instantiations(); + Q_ASSERT(!instantiations.isEmpty()); + AbstractMetaType *innerType = instantiations.at(0); + return innerType; + } + + QString getSmartPointerInnerTypeName() const + { + Q_ASSERT(isSmartPointer()); + AbstractMetaType *innerType = getSmartPointerInnerType(); + Q_ASSERT(innerType); + return innerType->name(); + } + + /// Decides and sets the proper usage patter for the current meta type. + void decideUsagePattern(); + + bool hasTemplateChildren() const; + +private: + TypeUsagePattern determineUsagePattern() const; + + const TypeEntry *m_typeEntry; + AbstractMetaTypeList m_instantiations; + QString m_package; + mutable QString m_name; + mutable QString m_cachedCppSignature; + QString m_originalTypeDescription; + + int m_arrayElementCount; + const AbstractMetaType *m_arrayElementType; + const AbstractMetaType *m_originalTemplateType; + + TypeUsagePattern m_pattern; + uint m_constant : 1; + uint m_cppInstantiation : 1; + int m_indirections : 4; + uint m_reserved : 26; // unused + ReferenceType m_referenceType; + AbstractMetaTypeList m_children; + + Q_DISABLE_COPY(AbstractMetaType); +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaType *at); +#endif + +class AbstractMetaVariable +{ +public: + AbstractMetaVariable() : m_type(0), m_hasName(false) {} + AbstractMetaVariable(const AbstractMetaVariable &other); + + virtual ~AbstractMetaVariable() + { + delete m_type; + } + + AbstractMetaType *type() const + { + return m_type; + } + void setType(AbstractMetaType *type) + { + Q_ASSERT(m_type == 0); + m_type = type; + } + void replaceType(AbstractMetaType *type) + { + if (m_type) + delete m_type; + m_type = type; + } + + QString name() const + { + return m_name; + } + void setName(const QString &name, bool realName = true) + { + m_name = name; + m_hasName = realName; + } + bool hasName() const + { + return m_hasName; + } + QString originalName() const + { + return m_originalName; + } + void setOriginalName(const QString& name) + { + m_originalName = name; + } + void setDocumentation(const Documentation& doc) + { + m_doc = doc; + } + Documentation documentation() const + { + return m_doc; + } + +private: + QString m_originalName; + QString m_name; + AbstractMetaType *m_type; + bool m_hasName; + + Documentation m_doc; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaVariable *av); +#endif + +class AbstractMetaArgument : public AbstractMetaVariable +{ +public: + AbstractMetaArgument() : m_argumentIndex(0) {}; + + QString defaultValueExpression() const + { + return m_expression; + } + void setDefaultValueExpression(const QString &expr) + { + m_expression = expr; + } + + QString originalDefaultValueExpression() const + { + return m_originalExpression; + } + void setOriginalDefaultValueExpression(const QString &expr) + { + m_originalExpression = expr; + } + + QString toString() const + { + return type()->name() + QLatin1Char(' ') + AbstractMetaVariable::name() + + (m_expression.isEmpty() ? QString() : QLatin1String(" = ") + m_expression); + } + + int argumentIndex() const + { + return m_argumentIndex; + } + void setArgumentIndex(int argIndex) + { + m_argumentIndex = argIndex; + } + + AbstractMetaArgument *copy() const; +private: + QString m_expression; + QString m_originalExpression; + int m_argumentIndex; + + friend class AbstractMetaClass; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaArgument *aa); +#endif + +class AbstractMetaField : public AbstractMetaVariable, public AbstractMetaAttributes +{ +public: + AbstractMetaField(); + ~AbstractMetaField(); + + const AbstractMetaClass *enclosingClass() const + { + return m_class; + } + void setEnclosingClass(const AbstractMetaClass *cls) + { + m_class = cls; + } + + const AbstractMetaFunction *getter() const; + const AbstractMetaFunction *setter() const; + + FieldModificationList modifications() const; + + bool isModifiedRemoved(int types = TypeSystem::All) const; + + using AbstractMetaVariable::setDocumentation; + using AbstractMetaVariable::documentation; + + AbstractMetaField *copy() const; + +private: + mutable AbstractMetaFunction *m_getter; + mutable AbstractMetaFunction *m_setter; + const AbstractMetaClass *m_class; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaField *af); +#endif + +class AbstractMetaFunction : public AbstractMetaAttributes +{ + Q_GADGET +public: + enum FunctionType { + ConstructorFunction, + CopyConstructorFunction, + MoveConstructorFunction, + AssignmentOperatorFunction, + MoveAssignmentOperatorFunction, + DestructorFunction, + NormalFunction, + SignalFunction, + EmptyFunction, + SlotFunction, + GlobalScopeFunction + }; + Q_ENUM(FunctionType) + + enum CompareResultFlag { + EqualName = 0x00000001, + EqualArguments = 0x00000002, + EqualAttributes = 0x00000004, + EqualImplementor = 0x00000008, + EqualReturnType = 0x00000010, + EqualDefaultValueOverload = 0x00000020, + EqualModifiedName = 0x00000040, + + NameLessThan = 0x00001000, + + PrettySimilar = EqualName | EqualArguments, + Equal = 0x0000001f, + NotEqual = 0x00001000 + }; + Q_DECLARE_FLAGS(CompareResult, CompareResultFlag) + Q_FLAG(CompareResultFlag) + + AbstractMetaFunction() + : m_typeEntry(0), + m_functionType(NormalFunction), + m_type(0), + m_class(0), + m_implementingClass(0), + m_declaringClass(0), + m_propertySpec(0), + m_constant(false), + m_invalid(false), + m_reverse(false), + m_userAdded(false), + m_explicit(false), + m_pointerOperator(false), + m_isCallOperator(false) + { + } + + ~AbstractMetaFunction(); + + QString name() const + { + return m_name; + } + + void setName(const QString &name) + { + m_name = name; + } + + QString originalName() const + { + return m_originalName.isEmpty() ? name() : m_originalName; + } + + void setOriginalName(const QString &name) + { + m_originalName = name; + } + + void setReverseOperator(bool reverse) + { + m_reverse = reverse; + } + + bool isReverseOperator() const + { + return m_reverse; + } + + /** + * Returns true if this is a operator and the "self" operand is a pointer. + * e.g. class Foo {}; operator+(SomeEnum, Foo*); + */ + bool isPointerOperator() const + { + return m_pointerOperator; + } + + void setPointerOperator(bool value) + { + m_pointerOperator = value; + } + + void setExplicit(bool isExplicit) + { + m_explicit = isExplicit; + } + /** + * Says if the function (a constructor) was declared as explicit in C++. + * \return true if the function was declared as explicit in C++ + */ + bool isExplicit() const + { + return m_explicit; + } + + static bool isConversionOperator(QString funcName); + bool isConversionOperator() const + { + return isConversionOperator(originalName()); + } + + static bool isOperatorOverload(QString funcName); + bool isOperatorOverload() const + { + return isOperatorOverload(originalName()); + } + bool isCastOperator() const; + + bool isArithmeticOperator() const; + bool isBitwiseOperator() const; + bool isComparisonOperator() const; + bool isLogicalOperator() const; + bool isSubscriptOperator() const; + bool isAssignmentOperator() const; // Assignment or move assignment + bool isOtherOperator() const; + + /** + * Informs the arity of the operator or -1 if the function is not + * an operator overload. + * /return the arity of the operator or -1 + */ + int arityOfOperator() const; + bool isUnaryOperator() const { return arityOfOperator() == 1; } + bool isBinaryOperator() const { return arityOfOperator() == 2; } + bool isInplaceOperator() const; + + // TODO: ths function *should* know if it is virtual + // instead of asking to your implementing class. + bool isVirtual() const; + bool isThread() const; + bool allowThread() const; + QString modifiedName() const; + + QString minimalSignature() const; + QStringList possibleIntrospectionCompatibleSignatures() const; + + QString marshalledName() const; + + // true if one or more of the arguments are of QtJambiObject subclasses + bool argumentsHaveNativeId() const + { + for (const AbstractMetaArgument *arg : m_arguments) { + if (arg->type()->hasNativeId()) + return true; + } + + return false; + } + + bool isModifiedRemoved(int types = TypeSystem::All) const; + + AbstractMetaType *type() const + { + return m_type; + } + void setType(AbstractMetaType *type) + { + Q_ASSERT(m_type == 0); + m_type = type; + } + + void replaceType(AbstractMetaType *type) + { + if (m_type) + delete m_type; + m_type = type; + } + + // The class that has this function as a member. + const AbstractMetaClass *ownerClass() const + { + return m_class; + } + void setOwnerClass(const AbstractMetaClass *cls) + { + m_class = cls; + } + + // The first class in a hierarchy that declares the function + const AbstractMetaClass *declaringClass() const + { + return m_declaringClass; + } + void setDeclaringClass(const AbstractMetaClass *cls) + { + m_declaringClass = cls; + } + + // The class that actually implements this function + const AbstractMetaClass *implementingClass() const + { + return m_implementingClass; + } + void setImplementingClass(const AbstractMetaClass *cls) + { + m_implementingClass = cls; + } + + bool needsCallThrough() const; + + AbstractMetaArgumentList arguments() const + { + return m_arguments; + } + void setArguments(const AbstractMetaArgumentList &arguments) + { + m_arguments = arguments; + } + void addArgument(AbstractMetaArgument *argument) + { + m_arguments << argument; + } + int actualMinimumArgumentCount() const; + + void setInvalid(bool on) + { + m_invalid = on; + } + bool isInvalid() const + { + return m_invalid; + } + bool isDeprecated() const; + bool isDestructor() const + { + return functionType() == DestructorFunction; + } + bool isConstructor() const + { + return m_functionType == ConstructorFunction || m_functionType == CopyConstructorFunction + || m_functionType == MoveConstructorFunction; + } + bool isNormal() const + { + return functionType() == NormalFunction || isSlot() || isInGlobalScope(); + } + bool isInGlobalScope() const + { + return functionType() == GlobalScopeFunction; + } + bool isSignal() const + { + return functionType() == SignalFunction; + } + bool isSlot() const + { + return functionType() == SlotFunction; + } + bool isEmptyFunction() const + { + return functionType() == EmptyFunction; + } + FunctionType functionType() const + { + return m_functionType; + } + void setFunctionType(FunctionType type) + { + m_functionType = type; + } + + bool usesRValueReferences() const; + QStringList introspectionCompatibleSignatures(const QStringList &resolvedArguments = QStringList()) const; + QString signature() const; + QString targetLangSignature(bool minimal = false) const; + bool shouldReturnThisObject() const + { + return QLatin1String("this") == argumentReplaced(0); + } + bool shouldIgnoreReturnValue() const + { + return QLatin1String("void") == argumentReplaced(0); + } + + bool isConstant() const + { + return m_constant; + } + void setConstant(bool constant) + { + m_constant = constant; + } + + /// Returns true if the AbstractMetaFunction was added by the user via the type system description. + bool isUserAdded() const + { + return m_userAdded; + } + void setUserAdded(bool userAdded) + { + m_userAdded = userAdded; + } + + QString toString() const + { + return m_name; + } + + CompareResult compareTo(const AbstractMetaFunction *other) const; + + bool operator <(const AbstractMetaFunction &a) const; + + AbstractMetaFunction *copy() const; + + QString replacedDefaultExpression(const AbstractMetaClass *cls, int idx) const; + bool removedDefaultExpression(const AbstractMetaClass *cls, int idx) const; + QString conversionRule(TypeSystem::Language language, int idx) const; + QVector referenceCounts(const AbstractMetaClass *cls, int idx = -2) const; + ArgumentOwner argumentOwner(const AbstractMetaClass *cls, int idx) const; + + bool nullPointersDisabled(const AbstractMetaClass *cls = 0, int argument_idx = 0) const; + QString nullPointerDefaultValue(const AbstractMetaClass *cls = 0, int argument_idx = 0) const; + + bool resetObjectAfterUse(int argument_idx) const; + + // Returns whether garbage collection is disabled for the argument in any context + bool disabledGarbageCollection(const AbstractMetaClass *cls, int key) const; + + // 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 isRemovedFromAllLanguages(const AbstractMetaClass *) const; + bool isRemovedFrom(const AbstractMetaClass *, TypeSystem::Language language) const; + bool argumentRemoved(int) const; + + QString argumentReplaced(int key) const; + bool needsSuppressUncheckedWarning() const; + + bool hasModifications(const AbstractMetaClass *implementor) const; + /** + * Verifies if any modification to the function is an inject code. + * \return true if there is inject code modifications to the function. + */ + bool hasInjectedCode() const; + /** + * Returns a list of code snips for this function. + * The code snips can be filtered by position and language. + * \return list of code snips + */ + CodeSnipList injectedCodeSnips(TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionAny, + TypeSystem::Language language = TypeSystem::All) const; + + /** + * Verifies if any modification to the function alters/removes its + * arguments types or default values. + * \return true if there is some modification to function signature + */ + bool hasSignatureModifications() const; + FunctionModificationList modifications(const AbstractMetaClass* implementor = 0) const; + + /** + * Return the argument name if there is a modification the renamed value will be returned + */ + QString argumentName(int index, bool create = true, const AbstractMetaClass *cl = 0) const; + + void setPropertySpec(QPropertySpec *spec) + { + m_propertySpec = spec; + } + + QPropertySpec *propertySpec() const + { + return m_propertySpec; + } + + FunctionTypeEntry* typeEntry() const + { + return m_typeEntry; + } + + void setTypeEntry(FunctionTypeEntry* typeEntry) + { + m_typeEntry = typeEntry; + } + + bool isCallOperator() const; + +#ifndef QT_NO_DEBUG_STREAM + void formatDebugVerbose(QDebug &d) const; +#endif + +private: + QString m_name; + QString m_originalName; + mutable QString m_cachedMinimalSignature; + mutable QString m_cachedSignature; + mutable QString m_cachedModifiedName; + + FunctionTypeEntry* m_typeEntry; + FunctionType m_functionType; + AbstractMetaType *m_type; + const AbstractMetaClass *m_class; + const AbstractMetaClass *m_implementingClass; + const AbstractMetaClass *m_declaringClass; + QPropertySpec *m_propertySpec; + AbstractMetaArgumentList m_arguments; + uint m_constant : 1; + uint m_invalid : 1; + uint m_reverse : 1; + uint m_userAdded : 1; + uint m_explicit : 1; + uint m_pointerOperator : 1; + uint m_isCallOperator : 1; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::CompareResult) + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaFunction *af); +#endif + +class AbstractMetaEnumValue +{ +public: + AbstractMetaEnumValue() + : m_valueSet(false), m_value(0) + { + } + + int value() const + { + return m_value; + } + + void setValue(int value) + { + m_valueSet = true; + m_value = value; + } + + QString stringValue() const + { + return m_stringValue; + } + + void setStringValue(const QString &v) + { + m_stringValue = v; + } + + QString name() const + { + return m_name; + } + + void setName(const QString &name) + { + m_name = name; + } + + bool isValueSet() const + { + return m_valueSet; + } + + void setDocumentation(const Documentation& doc) + { + m_doc = doc; + } + + Documentation documentation() const + { + return m_doc; + } + +private: + QString m_name; + QString m_stringValue; + + bool m_valueSet; + int m_value; + + Documentation m_doc; +}; + +class AbstractMetaEnum : public AbstractMetaAttributes +{ +public: + AbstractMetaEnum() : m_typeEntry(0), m_class(0), m_hasQenumsDeclaration(false) {} + ~AbstractMetaEnum() + { + qDeleteAll(m_enumValues); + } + + AbstractMetaEnumValueList values() const + { + return m_enumValues; + } + + void addEnumValue(AbstractMetaEnumValue *enumValue) + { + m_enumValues << enumValue; + } + + QString name() const; + + QString qualifier() const; + + QString package() const; + + QString fullName() const + { + return package() + QLatin1Char('.') + qualifier() + QLatin1Char('.') + name(); + } + + // Has the enum been declared inside a Q_ENUMS() macro in its enclosing class? + void setHasQEnumsDeclaration(bool on) + { + m_hasQenumsDeclaration = on; + } + + bool hasQEnumsDeclaration() const + { + return m_hasQenumsDeclaration; + } + + EnumTypeEntry *typeEntry() const + { + return m_typeEntry; + } + + void setTypeEntry(EnumTypeEntry *entry) + { + m_typeEntry = entry; + } + + AbstractMetaClass *enclosingClass() const + { + return m_class; + } + + void setEnclosingClass(AbstractMetaClass *c) + { + m_class = c; + } + + bool isAnonymous() const; + +private: + AbstractMetaEnumValueList m_enumValues; + EnumTypeEntry *m_typeEntry; + AbstractMetaClass *m_class; + + uint m_hasQenumsDeclaration : 1; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AbstractMetaEnum *ae); +#endif + +class AbstractMetaClass : public AbstractMetaAttributes +{ + Q_GADGET +public: + enum FunctionQueryOption { + Constructors = 0x0000001, // Only constructors + //Destructors = 0x0000002, // Only destructors. Not included in class. + VirtualFunctions = 0x0000004, // Only virtual functions (virtual in both TargetLang and C++) + FinalInTargetLangFunctions = 0x0000008, // Only functions that are non-virtual in TargetLang + FinalInCppFunctions = 0x0000010, // Only functions that are non-virtual in C++ + ClassImplements = 0x0000020, // Only functions implemented by the current class + Inconsistent = 0x0000040, // Only inconsistent functions (inconsistent virtualness in TargetLang/C++) + StaticFunctions = 0x0000080, // Only static functions + Signals = 0x0000100, // Only signals + NormalFunctions = 0x0000200, // Only functions that aren't signals + Visible = 0x0000400, // Only public and protected functions + ForcedShellFunctions = 0x0000800, // Only functions that are overridden to be implemented in the shell class + WasPublic = 0x0001000, // Only functions that were originally public + WasProtected = 0x0002000, // Only functions that were originally protected + NonStaticFunctions = 0x0004000, // No static functions + Empty = 0x0008000, // Empty overrides of abstract functions + Invisible = 0x0010000, // Only private functions + VirtualInCppFunctions = 0x0020000, // Only functions that are virtual in C++ + NonEmptyFunctions = 0x0040000, // Only functions with target language API implementations + VirtualInTargetLangFunctions = 0x0080000, // Only functions which are virtual in TargetLang + AbstractFunctions = 0x0100000, // Only abstract functions + WasVisible = 0x0200000, // Only functions that were public or protected in the original code + NotRemovedFromTargetLang = 0x0400000, // Only functions that have not been removed from TargetLang + NotRemovedFromShell = 0x0800000, // Only functions that have not been removed from the shell class + VirtualSlots = 0x1000000, // Only functions that are set as virtual slots in the type system + OperatorOverloads = 0x2000000 // Only functions that are operator overloads + }; + Q_DECLARE_FLAGS(FunctionQueryOptions, FunctionQueryOption) + Q_FLAG(FunctionQueryOption) + + enum OperatorQueryOption { + ArithmeticOp = 0x01, // Arithmetic: +, -, *, /, %, +=, -=, *=, /=, %=, ++, --, unary+, unary- + BitwiseOp = 0x02, // Bitwise: <<, <<=, >>, >>=, ~, &, &=, |, |=, ^, ^= + ComparisonOp = 0x04, // Comparison: <, <=, >, >=, !=, == + LogicalOp = 0x08, // Logical: !, &&, || + ConversionOp = 0x10, // Conversion: operator [const] TYPE() + SubscriptionOp = 0x20, // Subscription: [] + AssignmentOp = 0x40, // Assignment: = + OtherOp = 0x80, // The remaining operators: call(), etc + AllOperators = ArithmeticOp | BitwiseOp | ComparisonOp + | LogicalOp | ConversionOp | SubscriptionOp + | AssignmentOp | OtherOp + }; + Q_DECLARE_FLAGS(OperatorQueryOptions, OperatorQueryOption) + Q_FLAG(OperatorQueryOption) + + AbstractMetaClass() + : m_hasVirtuals(false), + m_isPolymorphic(false), + m_hasNonpublic(false), + m_hasVirtualSlots(false), + m_hasNonPrivateConstructor(false), + m_functionsFixed(false), + m_hasPrivateDestructor(false), + m_hasProtectedDestructor(false), + m_hasVirtualDestructor(false), + m_forceShellClass(false), + m_hasHashFunction(false), + m_hasEqualsOperator(false), + m_hasCloneOperator(false), + m_isTypeDef(false), + m_hasToStringCapability(false), + m_enclosingClass(0), + m_baseClass(0), + m_templateBaseClass(0), + m_extractedInterface(0), + m_typeEntry(0), + m_stream(false) + { + } + + virtual ~AbstractMetaClass(); + + AbstractMetaClass *extractInterface(); + void fixFunctions(); + + AbstractMetaFunctionList functions() const + { + return m_functions; + } + + void setFunctions(const AbstractMetaFunctionList &functions); + void addFunction(AbstractMetaFunction *function); + bool hasFunction(const AbstractMetaFunction *f) const; + bool hasFunction(const QString &str) const; + const AbstractMetaFunction* findFunction(const QString& functionName) const; + bool hasSignal(const AbstractMetaFunction *f) const; + + bool hasConstructors() const; + bool hasCopyConstructor() const; + bool hasPrivateCopyConstructor() const; + + void addDefaultConstructor(); + void addDefaultCopyConstructor(bool isPrivate = false); + + bool hasNonPrivateConstructor() const + { + return m_hasNonPrivateConstructor; + } + + void setHasNonPrivateConstructor(bool value) + { + m_hasNonPrivateConstructor = value; + } + + bool hasPrivateDestructor() const + { + return m_hasPrivateDestructor; + } + + void setHasPrivateDestructor(bool value) + { + m_hasPrivateDestructor = value; + } + + bool hasProtectedDestructor() const + { + return m_hasProtectedDestructor; + } + + void setHasProtectedDestructor(bool value) + { + m_hasProtectedDestructor = value; + } + + bool hasVirtualDestructor() const + { + return m_hasVirtualDestructor; + } + + void setHasVirtualDestructor(bool value) + { + m_hasVirtualDestructor = value; + } + + AbstractMetaFunctionList queryFunctionsByName(const QString &name) const; + AbstractMetaFunctionList queryFunctions(FunctionQueryOptions query) const; + AbstractMetaFunctionList functionsInTargetLang() const; + AbstractMetaFunctionList functionsInShellClass() const; + inline AbstractMetaFunctionList cppSignalFunctions() const; + AbstractMetaFunctionList publicOverrideFunctions() const; + AbstractMetaFunctionList virtualOverrideFunctions() const; + AbstractMetaFunctionList virtualFunctions() const; + AbstractMetaFunctionList implicitConversions() const; + + /** + * Retrieves all class' operator overloads that meet + * query criteria defined with the OperatorQueryOption + * enum. + * /param query composition of OperatorQueryOption enum values + * /return list of operator overload methods that meet the + * query criteria + */ + AbstractMetaFunctionList operatorOverloads(OperatorQueryOptions query = AllOperators) const; + + bool hasOperatorOverload() const; + bool hasArithmeticOperatorOverload() const; + bool hasBitwiseOperatorOverload() const; + bool hasComparisonOperatorOverload() const; + bool hasLogicalOperatorOverload() const; + bool hasSubscriptOperatorOverload() const; + bool hasAssignmentOperatorOverload() const; + bool hasConversionOperatorOverload() const; + + AbstractMetaFieldList fields() const + { + return m_fields; + } + + void setFields(const AbstractMetaFieldList &fields) + { + m_fields = fields; + } + + void addField(AbstractMetaField *field) + { + m_fields << field; + } + + AbstractMetaEnumList enums() const + { + return m_enums; + } + void setEnums(const AbstractMetaEnumList &enums) + { + m_enums = enums; + } + + void addEnum(AbstractMetaEnum *e) + { + m_enums << e; + } + + AbstractMetaEnum *findEnum(const QString &enumName); + AbstractMetaEnum *findEnumForValue(const QString &enumName); + AbstractMetaEnumValue *findEnumValue(const QString &enumName, AbstractMetaEnum *meta_enum); + + AbstractMetaClassList interfaces() const + { + return m_interfaces; + } + void addInterface(AbstractMetaClass *interface); + void setInterfaces(const AbstractMetaClassList &interface); + + QString fullName() const + { + return package() + QLatin1Char('.') + name(); + } + + /** + * Retrieves the class name without any namespace/scope information. + * /return the class name without scope information + */ + QString name() const; + + QString baseClassName() const + { + return m_baseClass ? m_baseClass->name() : QString(); + } + + AbstractMetaClass *baseClass() const + { + return m_baseClass; + } + + void setBaseClass(AbstractMetaClass *base_class); + + const AbstractMetaClass *enclosingClass() const + { + return m_enclosingClass; + } + + void setEnclosingClass(AbstractMetaClass *cl) + { + m_enclosingClass = cl; + } + + const AbstractMetaClassList& innerClasses() const + { + return m_innerClasses; + } + + void addInnerClass(AbstractMetaClass* cl) + { + m_innerClasses << cl; + } + + void setInnerClasses(AbstractMetaClassList innerClasses) + { + m_innerClasses = innerClasses; + } + + QString package() const; + + bool isInterface() const; + + bool isNamespace() const; + + bool isQObject() const; + + bool isQtNamespace() const + { + return isNamespace() && name() == QLatin1String("Qt"); + } + + QString qualifiedCppName() const; + + bool hasSignals() const; + bool inheritsFrom(const AbstractMetaClass *other) const; + + void setForceShellClass(bool on) + { + m_forceShellClass = on; + } + + bool generateShellClass() const; + + bool hasVirtualSlots() const + { + return m_hasVirtualSlots; + } + + /** + * Says if a class has any virtual functions of its own. + * \return true if the class implements any virtual methods + */ + bool hasVirtualFunctions() const + { + return !isFinal() && m_hasVirtuals; + } + /** + * Says if the class that declares or inherits a virtual function. + * \return true if the class implements or inherits any virtual methods + */ + bool isPolymorphic() const + { + return m_isPolymorphic; + } + + /** + * Tells if this class has one or more functions that are protected. + * \return true if the class has protected functions. + */ + bool hasProtectedFunctions() const; + + /** + * Tells if this class has one or more fields (member variables) that are protected. + * \return true if the class has protected fields. + */ + bool hasProtectedFields() const; + + /** + * Tells if this class has one or more members (functions or fields) that are protected. + * \return true if the class has protected members. + */ + bool hasProtectedMembers() const; + + + QVector templateArguments() const + { + return m_templateArgs; + } + + void setTemplateArguments(const QVector &args) + { + m_templateArgs = args; + } + + bool hasFieldAccessors() const; + + // only valid during metabuilder's run + QStringList baseClassNames() const + { + return m_baseClassNames; + } + + void setBaseClassNames(const QStringList &names) + { + m_baseClassNames = names; + } + + const ComplexTypeEntry *typeEntry() const + { + return m_typeEntry; + } + + ComplexTypeEntry *typeEntry() + { + return m_typeEntry; + } + + void setTypeEntry(ComplexTypeEntry *type) + { + m_typeEntry = type; + } + + void setHasHashFunction(bool on) + { + m_hasHashFunction = on; + } + + bool hasHashFunction() const + { + return m_hasHashFunction; + } + virtual bool hasDefaultToStringFunction() const; + + void setHasEqualsOperator(bool on) + { + m_hasEqualsOperator = on; + } + + bool hasEqualsOperator() const + { + return m_hasEqualsOperator; + } + + void setHasCloneOperator(bool on) + { + m_hasCloneOperator = on; + } + + bool hasCloneOperator() const + { + return m_hasCloneOperator; + } + + void addPropertySpec(QPropertySpec *spec) + { + m_propertySpecs << spec; + } + + QVector propertySpecs() const + { + return m_propertySpecs; + } + + QPropertySpec *propertySpecForRead(const QString &name) const; + QPropertySpec *propertySpecForWrite(const QString &name) const; + QPropertySpec *propertySpecForReset(const QString &name) const; + + /// Returns a list of conversion operators for this class. The conversion operators are defined in other classes of the same module. + AbstractMetaFunctionList externalConversionOperators() const + { + return m_externalConversionOperators; + } + /// Adds a converter operator for this class. + void addExternalConversionOperator(AbstractMetaFunction* conversionOp) + { + if (!m_externalConversionOperators.contains(conversionOp)) + m_externalConversionOperators.append(conversionOp); + } + /// Returns true if this class has any converter operators defined elsewhere. + bool hasExternalConversionOperators() const + { + return !m_externalConversionOperators.isEmpty(); + } + + void sortFunctions(); + + const AbstractMetaClass *templateBaseClass() const + { + return m_templateBaseClass; + } + + void setTemplateBaseClass(const AbstractMetaClass *cls) + { + m_templateBaseClass = cls; + } + + bool hasTemplateBaseClassInstantiations() const; + AbstractMetaTypeList templateBaseClassInstantiations() const; + void setTemplateBaseClassInstantiations(AbstractMetaTypeList& instantiations); + + void setTypeDef(bool typeDef) { m_isTypeDef = typeDef; } + bool isTypeDef() const { return m_isTypeDef; } + + void setStream(bool stream) + { + m_stream = stream; + } + + bool isStream() const + { + return m_stream; + } + + void setToStringCapability(bool value) + { + m_hasToStringCapability = value; + } + + bool hasToStringCapability() const + { + return m_hasToStringCapability; + } + + static AbstractMetaClass *findClass(const AbstractMetaClassList &classes, + const QString &name); + static AbstractMetaClass *findClass(const AbstractMetaClassList &classes, + const TypeEntry* typeEntry); + static AbstractMetaEnumValue *findEnumValue(const AbstractMetaClassList &classes, + const QString &string); + static AbstractMetaEnum *findEnum(const AbstractMetaClassList &classes, + const EnumTypeEntry *entry); + +private: +#ifndef QT_NO_DEBUG_STREAM + friend QDebug operator<<(QDebug d, const AbstractMetaClass *ac); +#endif + uint m_hasVirtuals : 1; + uint m_isPolymorphic : 1; + uint m_hasNonpublic : 1; + uint m_hasVirtualSlots : 1; + uint m_hasNonPrivateConstructor : 1; + uint m_functionsFixed : 1; + uint m_hasPrivateDestructor : 1; + uint m_hasProtectedDestructor : 1; + uint m_hasVirtualDestructor : 1; + uint m_forceShellClass : 1; + uint m_hasHashFunction : 1; + uint m_hasEqualsOperator : 1; + uint m_hasCloneOperator : 1; + uint m_isTypeDef : 1; + uint m_hasToStringCapability : 1; + + const AbstractMetaClass *m_enclosingClass; + AbstractMetaClass *m_baseClass; + const AbstractMetaClass *m_templateBaseClass; + AbstractMetaFunctionList m_functions; + AbstractMetaFieldList m_fields; + AbstractMetaEnumList m_enums; + AbstractMetaClassList m_interfaces; + AbstractMetaClass *m_extractedInterface; + QVector m_propertySpecs; + AbstractMetaClassList m_innerClasses; + + AbstractMetaFunctionList m_externalConversionOperators; + + QStringList m_baseClassNames; + QVector m_templateArgs; + ComplexTypeEntry *m_typeEntry; +// FunctionModelItem m_qDebugStreamFunction; + + bool m_stream; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaClass::FunctionQueryOptions) +Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaClass::OperatorQueryOptions) + +class QPropertySpec +{ +public: + QPropertySpec(const TypeEntry *type) + : m_type(type), + m_index(-1) + {} + + const TypeEntry *type() const + { + return m_type; + } + + QString name() const + { + return m_name; + } + + void setName(const QString &name) + { + m_name = name; + } + + QString read() const + { + return m_read; + } + + void setRead(const QString &read) + { + m_read = read; + } + + QString write() const + { + return m_write; + } + + void setWrite(const QString &write) + { + m_write = write; + } + + QString designable() const + { + return m_designable; + } + + void setDesignable(const QString &designable) + { + m_designable = designable; + } + + QString reset() const + { + return m_reset; + } + + void setReset(const QString &reset) + { + m_reset = reset; + } + + int index() const + { + return m_index; + } + + void setIndex(int index) + { + m_index = index; + } + +private: + QString m_name; + QString m_read; + QString m_write; + QString m_designable; + QString m_reset; + const TypeEntry *m_type; + int m_index; +}; + +inline AbstractMetaFunctionList AbstractMetaClass::cppSignalFunctions() const +{ + return queryFunctions(Signals + | Visible + | NotRemovedFromTargetLang); +} + +#endif // ABSTRACTMETALANG_H diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang_typedefs.h b/sources/shiboken2/ApiExtractor/abstractmetalang_typedefs.h new file mode 100644 index 000000000..da8369895 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/abstractmetalang_typedefs.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 ABSTRACTMETALANG_TYPEDEFS_H +#define ABSTRACTMETALANG_TYPEDEFS_H + +#include + +class AbstractMetaClass; +class AbstractMetaField; +class AbstractMetaArgument; +class AbstractMetaEnum; +class AbstractMetaEnumValue; +class AbstractMetaFunction; +class AbstractMetaType; + +typedef QVector AbstractMetaArgumentList; +typedef QVector AbstractMetaClassList; +typedef QVector AbstractMetaEnumList; +typedef QVector AbstractMetaEnumValueList; +typedef QVector AbstractMetaFieldList; +typedef QVector AbstractMetaFunctionList; +typedef QVector AbstractMetaTypeList; + +#endif // ABSTRACTMETALANG_TYPEDEFS_H diff --git a/sources/shiboken2/ApiExtractor/apiextractor.cpp b/sources/shiboken2/ApiExtractor/apiextractor.cpp new file mode 100644 index 000000000..abb7c08b9 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/apiextractor.cpp @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "apiextractor.h" +#include "abstractmetalang.h" + +#include +#include +#include +#include +#include +#include + +#include "reporthandler.h" +#include "typesystem.h" +#include "fileout.h" +#include "abstractmetabuilder.h" +#include "typedatabase.h" +#include "typesystem.h" + +static bool appendFile(const QString& sourceFileName, QFile& targetFile) +{ + QFile sourceFile(sourceFileName); + if (!sourceFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + std::cerr << "Cannot open " << qPrintable(QDir::toNativeSeparators(sourceFileName)) + << ": " << qPrintable(sourceFile.errorString()) << '\n'; + return false; + } + targetFile.write(sourceFile.readAll()); + return true; +} + +ApiExtractor::ApiExtractor() : m_builder(0) +{ + // Environment TYPESYSTEMPATH + QString envTypesystemPaths = QFile::decodeName(getenv("TYPESYSTEMPATH")); + if (!envTypesystemPaths.isEmpty()) + TypeDatabase::instance()->addTypesystemPath(envTypesystemPaths); +} + +ApiExtractor::~ApiExtractor() +{ + delete m_builder; +} + +void ApiExtractor::addTypesystemSearchPath (const QString& path) +{ + TypeDatabase::instance()->addTypesystemPath(path); +} + +void ApiExtractor::addTypesystemSearchPath(const QStringList& paths) +{ + for (const QString &path : paths) + addTypesystemSearchPath(path); +} + +void ApiExtractor::addIncludePath(const HeaderPath& path) +{ + m_includePaths << path; +} + +void ApiExtractor::addIncludePath(const HeaderPaths& paths) +{ + m_includePaths << paths; +} + +void ApiExtractor::setLogDirectory(const QString& logDir) +{ + m_logDirectory = logDir; +} + +void ApiExtractor::setCppFileName(const QString& cppFileName) +{ + m_cppFileName = cppFileName; +} + +void ApiExtractor::setTypeSystem(const QString& typeSystemFileName) +{ + m_typeSystemFileName = typeSystemFileName; +} + +void ApiExtractor::setDebugLevel(ReportHandler::DebugLevel debugLevel) +{ + ReportHandler::setDebugLevel(debugLevel); +} + +void ApiExtractor::setSuppressWarnings ( bool value ) +{ + TypeDatabase::instance()->setSuppressWarnings(value); +} + +void ApiExtractor::setSilent ( bool value ) +{ + ReportHandler::setSilent(value); +} + +bool ApiExtractor::setApiVersion(const QString& package, const QString &version) +{ + return TypeDatabase::instance()->setApiVersion(package, version); +} + +void ApiExtractor::setDropTypeEntries(QString dropEntries) +{ + dropEntries.remove(QLatin1Char(' ')); + QStringList entries = dropEntries.split(QLatin1Char(';')); + TypeDatabase::instance()->setDropTypeEntries(entries); +} + +AbstractMetaEnumList ApiExtractor::globalEnums() const +{ + Q_ASSERT(m_builder); + return m_builder->globalEnums(); +} + +AbstractMetaFunctionList ApiExtractor::globalFunctions() const +{ + Q_ASSERT(m_builder); + return m_builder->globalFunctions(); +} + +AbstractMetaClassList ApiExtractor::classes() const +{ + Q_ASSERT(m_builder); + return m_builder->classes(); +} + +AbstractMetaClassList ApiExtractor::smartPointers() const +{ + Q_ASSERT(m_builder); + return m_builder->smartPointers(); +} + +AbstractMetaClassList ApiExtractor::classesTopologicalSorted(const Dependencies &additionalDependencies) const +{ + Q_ASSERT(m_builder); + return m_builder->classesTopologicalSorted(Q_NULLPTR, additionalDependencies); +} + +PrimitiveTypeEntryList ApiExtractor::primitiveTypes() const +{ + return TypeDatabase::instance()->primitiveTypes(); +} + +ContainerTypeEntryList ApiExtractor::containerTypes() const +{ + return TypeDatabase::instance()->containerTypes(); +} + +QSet ApiExtractor::qtMetaTypeDeclaredTypeNames() const +{ + Q_ASSERT(m_builder); + return m_builder->qtMetaTypeDeclaredTypeNames(); +} + +static const AbstractMetaEnum* findEnumOnClasses(AbstractMetaClassList metaClasses, const EnumTypeEntry* typeEntry) +{ + const AbstractMetaEnum* result = 0; + for (const AbstractMetaClass* metaClass : qAsConst(metaClasses)) { + const AbstractMetaEnumList &enums = metaClass->enums(); + for (const AbstractMetaEnum *metaEnum : enums) { + if (metaEnum->typeEntry() == typeEntry) { + result = metaEnum; + break; + } + } + if (result) + break; + result = findEnumOnClasses(metaClass->innerClasses(), typeEntry); + } + 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(typeEntry)); + if (typeEntry->isEnum()) + return findAbstractMetaEnum(reinterpret_cast(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()); +} + +int ApiExtractor::classCount() const +{ + Q_ASSERT(m_builder); + return m_builder->classes().count(); +} + +bool ApiExtractor::run() +{ + if (m_builder) + return false; + + if (m_typeSystemFileName.isEmpty()) { + std::cerr << "You must specify a Type System file." << std::endl; + return false; + } else if (!TypeDatabase::instance()->parseFile(m_typeSystemFileName)) { + std::cerr << "Cannot parse file: " << qPrintable(m_typeSystemFileName); + return false; + } + + const QString pattern = QDir::tempPath() + QLatin1Char('/') + + QFileInfo(m_cppFileName).baseName() + QStringLiteral("_XXXXXX.hpp"); + QTemporaryFile ppFile(pattern); + bool autoRemove = !qEnvironmentVariableIsSet("KEEP_TEMP_FILES"); + // make sure that a tempfile can be written + if (!ppFile.open()) { + std::cerr << "could not create tempfile " << qPrintable(pattern) + << ": " << qPrintable(ppFile.errorString()) << '\n'; + return false; + } + + if (!appendFile(m_cppFileName, ppFile)) + return false; + const QString preprocessedCppFileName = ppFile.fileName(); + ppFile.close(); + m_builder = new AbstractMetaBuilder; + m_builder->setLogDirectory(m_logDirectory); + m_builder->setGlobalHeader(m_cppFileName); + QByteArrayList arguments; + arguments.reserve(m_includePaths.size() + 1); + for (const HeaderPath &headerPath : qAsConst(m_includePaths)) + arguments.append(HeaderPath::includeOption(headerPath)); + arguments.append(QFile::encodeName(preprocessedCppFileName)); + qCDebug(lcShiboken) << __FUNCTION__ << arguments; + const bool result = m_builder->build(arguments); + if (!result) + autoRemove = false; + if (!autoRemove) { + ppFile.setAutoRemove(false); + std::cerr << "Keeping temporary file: " << qPrintable(QDir::toNativeSeparators(preprocessedCppFileName)) << '\n'; + } + return result; +} + +#ifndef QT_NO_DEBUG_STREAM +template +static void debugFormatSequence(QDebug &d, const char *key, const Container& c) +{ + typedef typename Container::const_iterator ConstIt; + if (c.isEmpty()) + return; + const ConstIt begin = c.begin(); + const ConstIt end = c.end(); + d << "\n " << key << '[' << c.size() << "]=("; + for (ConstIt it = begin; it != end; ++it) { + if (it != begin) + d << ", "; + d << *it; + } + d << ')'; +} + +QDebug operator<<(QDebug d, const ApiExtractor &ae) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "ApiExtractor(typeSystem=\"" << ae.typeSystem() << "\", cppFileName=\"" + << ae.cppFileName() << ", "; + ae.m_builder->formatDebug(d); + d << ')'; + return d; +} +#endif // QT_NO_DEBUG_STREAM diff --git a/sources/shiboken2/ApiExtractor/apiextractor.h b/sources/shiboken2/ApiExtractor/apiextractor.h new file mode 100644 index 000000000..ac90f5b2f --- /dev/null +++ b/sources/shiboken2/ApiExtractor/apiextractor.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 APIEXTRACTOR_H +#define APIEXTRACTOR_H + +#include "reporthandler.h" +#include "dependency.h" +#include "abstractmetalang_typedefs.h" +#include "apiextractormacros.h" +#include "header_paths.h" +#include "typedatabase_typedefs.h" +#include "typesystem_typedefs.h" +#include + +class AbstractMetaBuilder; +class AbstractMetaClass; +class AbstractMetaEnum; +class AbstractMetaFunction; +class AbstractMetaType; +class ContainerTypeEntry; +class EnumTypeEntry; +class FlagsTypeEntry; +class PrimitiveTypeEntry; +class TypeEntry; + +QT_BEGIN_NAMESPACE +class QDebug; +class QIODevice; +QT_END_NAMESPACE + +class ApiExtractor +{ +public: + ApiExtractor(); + ~ApiExtractor(); + + void setTypeSystem(const QString& typeSystemFileName); + QString typeSystem() const { return m_typeSystemFileName; } + void setCppFileName(const QString& cppFileName); + QString cppFileName() const { return m_cppFileName; } + void setDebugLevel(ReportHandler::DebugLevel debugLevel); + void setSuppressWarnings(bool value); + void setSilent(bool value); + void addTypesystemSearchPath(const QString& path); + void addTypesystemSearchPath(const QStringList& paths); + void addIncludePath(const HeaderPath& path); + void addIncludePath(const HeaderPaths& paths); + HeaderPaths includePaths() const { return m_includePaths; } + void setLogDirectory(const QString& logDir); + bool setApiVersion(const QString& package, const QString& version); + void setDropTypeEntries(QString dropEntries); + + AbstractMetaEnumList globalEnums() const; + AbstractMetaFunctionList globalFunctions() const; + AbstractMetaClassList classes() const; + AbstractMetaClassList smartPointers() const; + AbstractMetaClassList classesTopologicalSorted(const Dependencies &additionalDependencies = Dependencies()) const; + PrimitiveTypeEntryList primitiveTypes() const; + ContainerTypeEntryList containerTypes() const; + QSet qtMetaTypeDeclaredTypeNames() 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; + + bool run(); +private: + QString m_typeSystemFileName; + QString m_cppFileName; + HeaderPaths m_includePaths; + AbstractMetaBuilder* m_builder; + QString m_logDirectory; + + // disable copy + ApiExtractor(const ApiExtractor&); + ApiExtractor& operator=(const ApiExtractor&); +#ifndef QT_NO_DEBUG_STREAM + friend QDebug operator<<(QDebug d, const ApiExtractor &ae); +#endif +}; + +#endif // APIEXTRACTOR_H diff --git a/sources/shiboken2/ApiExtractor/apiextractormacros.h b/sources/shiboken2/ApiExtractor/apiextractormacros.h new file mode 100644 index 000000000..41a710773 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/apiextractormacros.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 APIEXTRACTORMACROS_H +#define APIEXTRACTORMACROS_H + + +// APIEXTRACTOR_API is used for the public API symbols. +#if defined _WIN32 + #define APIEXTRACTOR_DEPRECATED(func) __declspec(deprecated) func +#elif __GNUC__ >= 4 + #define APIEXTRACTOR_DEPRECATED(func) func __attribute__ ((deprecated)) +#else + #define APIEXTRACTOR_DEPRECATED(func) func +#endif +#endif diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp new file mode 100644 index 000000000..dc0c59dd5 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp @@ -0,0 +1,770 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "clangbuilder.h" +#include "compilersupport.h" +#include "clangutils.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#if QT_VERSION < 0x050800 +# define Q_FALLTHROUGH() (void)0 +#endif + +namespace clang { + +static inline QString colonColon() { return QStringLiteral("::"); } +static inline QString templateBrackets() { return QStringLiteral("<>"); } + +static inline bool isClassCursor(const CXCursor &c) +{ + return c.kind == CXCursor_ClassDecl || c.kind == CXCursor_StructDecl + || c.kind == CXCursor_ClassTemplate + || c.kind == CXCursor_ClassTemplatePartialSpecialization; +} + +static inline bool withinClassDeclaration(const CXCursor &cursor) +{ + return isClassCursor(clang_getCursorLexicalParent(cursor)); +} + +static QString fixTypeName(QString t) +{ + // Fix "Foo &" -> "Foo&", similarly "Bar **" -> "Bar**" + int pos = t.size() - 1; + for (; pos >= 0 && (t.at(pos) == QLatin1Char('&') || t.at(pos) == QLatin1Char('*')); --pos) {} + if (pos > 0 && t.at(pos) == QLatin1Char(' ')) + t.remove(pos, 1); + return t; +} + +// Insert template parameter to class name: "Foo<>" -> "Foo" -> "Foo" +// This needs to be done immediately when template parameters are encountered since +// the class name "Foo" is the scope for nested items. +static bool insertTemplateParameterIntoClassName(const QString &parmName, QString *name) +{ + if (Q_UNLIKELY(!name->endsWith(QLatin1Char('>')))) + return false; + const bool needsComma = name->at(name->size() - 2) != QLatin1Char('<'); + const int insertionPos = name->size() - 1; + name->insert(insertionPos, parmName); + if (needsComma) + name->insert(insertionPos, QLatin1Char(',')); + return true; +} + +static inline bool insertTemplateParameterIntoClassName(const QString &parmName, + const ClassModelItem &item) +{ + QString name = item->name(); + const bool result = insertTemplateParameterIntoClassName(parmName, &name); + item->setName(name); + return result; +} + +static inline CodeModel::AccessPolicy accessPolicy(CX_CXXAccessSpecifier access) +{ + CodeModel::AccessPolicy result = CodeModel::Public; + switch (access) { + case CX_CXXProtected: + result = CodeModel::Protected; + break; + case CX_CXXPrivate: + result = CodeModel::Private; + break; + default: + break; + } + return result; +} + +static void setFileName(const CXCursor &cursor, _CodeModelItem *item) +{ + const SourceRange range = getCursorRange(cursor); + if (!range.first.file.isEmpty()) { // Has been observed to be 0 for invalid locations + item->setFileName(QDir::cleanPath(range.first.file)); + item->setStartPosition(int(range.first.line), int(range.first.column)); + item->setEndPosition(int(range.second.line), int(range.second.column)); + } +} + +class BuilderPrivate { +public: + typedef QHash CursorClassHash; + typedef QHash CursorTypedefHash; + + explicit BuilderPrivate(BaseVisitor *bv) : m_baseVisitor(bv), m_model(new CodeModel) + { + m_scopeStack.push(NamespaceModelItem(new _FileModelItem(m_model))); + } + + // Determine scope from top item. Note that the scope list does not necessarily + // match the scope stack in case of forward-declared inner classes whose definition + // appears in the translation unit while the scope is the outer class. + void updateScope() + { + if (m_scopeStack.size() <= 1) + m_scope.clear(); + else + m_scope = m_scopeStack.back()->scope() << m_scopeStack.back()->name(); + } + + void pushScope(const ScopeModelItem &i) + { + m_scopeStack.push(i); + updateScope(); + } + + void popScope() + { + m_scopeStack.pop(); + updateScope(); + } + + bool addClass(const CXCursor &cursor, CodeModel::ClassType t); + FunctionModelItem createFunction(const CXCursor &cursor, + CodeModel::FunctionType t = CodeModel::Normal) const; + FunctionModelItem createMemberFunction(const CXCursor &cursor, + CodeModel::FunctionType t = CodeModel::Normal) const; + void qualifyConstructor(const CXCursor &cursor); + TypeInfo createTypeInfo(const CXType &type) const; + TypeInfo createTypeInfo(const CXCursor &cursor) const + { return createTypeInfo(clang_getCursorType(cursor)); } + + TemplateParameterModelItem createTemplateParameter(const CXCursor &cursor) const; + TemplateParameterModelItem createNonTypeTemplateParameter(const CXCursor &cursor) const; + void addField(const CXCursor &cursor); + + QString cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor) const; + void addBaseClass(const CXCursor &cursor); + + template + void qualifyTypeDef(const CXCursor &typeRefCursor, const QSharedPointer &item) const; + + BaseVisitor *m_baseVisitor; + CodeModel *m_model; + + QStack m_scopeStack; + QStringList m_scope; + // Store all classes by cursor so that base classes can be found and inner + // classes can be correctly parented in case of forward-declared inner classes + // (QMetaObject::Connection) + CursorClassHash m_cursorClassHash; + CursorTypedefHash m_cursorTypedefHash; + + ClassModelItem m_currentClass; + EnumModelItem m_currentEnum; + FunctionModelItem m_currentFunction; + ArgumentModelItem m_currentArgument; + VariableModelItem m_currentField; + + int m_anonymousEnumCount = 0; + CodeModel::FunctionType m_currentFunctionType = CodeModel::Normal; +}; + +bool BuilderPrivate::addClass(const CXCursor &cursor, CodeModel::ClassType t) +{ + QString className = getCursorSpelling(cursor); + m_currentClass.reset(new _ClassModelItem(m_model, className)); + setFileName(cursor, m_currentClass.data()); + m_currentClass->setClassType(t); + // Some inner class? Note that it does not need to be (lexically) contained in a + // class since it is possible to forward declare an inner class: + // class QMetaObject { class Connection; } + // class QMetaObject::Connection {} + const CXCursor semPar = clang_getCursorSemanticParent(cursor); + if (isClassCursor(semPar)) { + const CursorClassHash::const_iterator it = m_cursorClassHash.constFind(semPar); + if (it == m_cursorClassHash.constEnd()) { + const QString message = QStringLiteral("Unable to find parent of inner class ") + className; + const Diagnostic d(message, cursor, CXDiagnostic_Error); + qWarning() << d; + m_baseVisitor->appendDiagnostic(d); + return false; + } + const ClassModelItem &containingClass = it.value(); + containingClass->addClass(m_currentClass); + m_currentClass->setScope(containingClass->scope() << containingClass->name()); + } else { + m_currentClass->setScope(m_scope); + m_scopeStack.back()->addClass(m_currentClass); + } + pushScope(m_currentClass); + m_cursorClassHash.insert(cursor, m_currentClass); + return true; +} + +FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor, + CodeModel::FunctionType t) const +{ + QString name = getCursorSpelling(cursor); + // Apply type fixes to "operator X &" -> "operator X&" + if (name.startsWith(QLatin1String("operator "))) + name = fixTypeName(name); + FunctionModelItem result(new _FunctionModelItem(m_model, name)); + setFileName(cursor, result.data()); + result->setType(createTypeInfo(clang_getCursorResultType(cursor))); + result->setFunctionType(t); + result->setScope(m_scope); + result->setStatic(clang_Cursor_getStorageClass(cursor) == CX_SC_Static); + return result; +} + +FunctionModelItem BuilderPrivate::createMemberFunction(const CXCursor &cursor, + CodeModel::FunctionType t) const +{ + FunctionModelItem result = createFunction(cursor, t); + result->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor))); + result->setConstant(clang_CXXMethod_isConst(cursor) != 0); + result->setStatic(clang_CXXMethod_isStatic(cursor) != 0); + result->setVirtual(clang_CXXMethod_isVirtual(cursor) != 0); + result->setAbstract(clang_CXXMethod_isPureVirtual(cursor) != 0); + result->setFunctionType(m_currentFunctionType); + return result; +} + +// For CXCursor_Constructor, on endToken(). +void BuilderPrivate::qualifyConstructor(const CXCursor &cursor) +{ + // Clang does not tell us whether a constructor is explicit, preventing it + // from being used for implicit conversions. Try to guess whether a + // constructor is explicit in the C++99 sense (1 parameter) by checking for + // isConvertingConstructor() == 0. Fixme: The notion of "isConvertingConstructor" + // should be used in the code model instead of "explicit" + if (clang_CXXConstructor_isDefaultConstructor(cursor) == 0 + && m_currentFunction->arguments().size() == 1 + && clang_CXXConstructor_isCopyConstructor(cursor) == 0 + && clang_CXXConstructor_isMoveConstructor(cursor) == 0) { + m_currentFunction->setExplicit(clang_CXXConstructor_isConvertingConstructor(cursor) == 0); + } +} + +TemplateParameterModelItem BuilderPrivate::createTemplateParameter(const CXCursor &cursor) const +{ + return TemplateParameterModelItem(new _TemplateParameterModelItem(m_model, getCursorSpelling(cursor))); +} + +TemplateParameterModelItem BuilderPrivate::createNonTypeTemplateParameter(const CXCursor &cursor) const +{ + TemplateParameterModelItem result = createTemplateParameter(cursor); + result->setType(createTypeInfo(cursor)); + return result; +} + +// CXCursor_VarDecl, CXCursor_FieldDecl cursors +void BuilderPrivate::addField(const CXCursor &cursor) +{ + VariableModelItem field(new _VariableModelItem(m_model, getCursorSpelling(cursor))); + field->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor))); + field->setScope(m_scope); + field->setType(createTypeInfo(cursor)); + field->setMutable(clang_CXXField_isMutable(cursor) != 0); + m_currentField = field; + m_scopeStack.back()->addVariable(field); +} + +// Array helpers: Parse "a[2][4]" into a list of dimensions + +struct ArrayDimensionResult +{ + QVector dimensions; + 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; +} + +TypeInfo BuilderPrivate::createTypeInfo(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)); + result.setFunctionPointer(true); + for (int a = 0; a < argCount; ++a) + result.addArgument(createTypeInfo(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); + } + + // "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)); + } + + 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); + + // clang_isVolatileQualifiedType() returns true for "volatile int", but not for "volatile int *" + if (typeName.startsWith(QLatin1String("volatile "))) { + typeName.remove(0, 9); + typeInfo.setVolatile(true); + } + + typeName = typeName.trimmed(); + + typeInfo.setQualifiedName(typeName.split(colonColon())); + // 3320:CINDEX_LINKAGE int clang_getNumArgTypes(CXType T); function ptr types? + return typeInfo; +} + +// extract an expression from the cursor via source +// CXCursor_EnumConstantDecl, ParmDecl (a = Flag1 | Flag2) +QString BuilderPrivate::cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor) const +{ + BaseVisitor::CodeSnippet snippet = bv->getCodeSnippet(cursor); + const char *equalSign = std::find(snippet.first, snippet.second, '='); + if (equalSign == snippet.second) + return QString(); + ++equalSign; + return QString::fromLocal8Bit(equalSign, int(snippet.second - equalSign)).trimmed(); +} + +// Add a base class to the current class from CXCursor_CXXBaseSpecifier +void BuilderPrivate::addBaseClass(const CXCursor &cursor) +{ + const CXType inheritedType = clang_getCursorType(cursor); // Note spelling has "struct baseClass", + QString baseClassName = getTypeName(inheritedType); // use type. + const CXCursor declCursor = clang_getTypeDeclaration(inheritedType); + const CursorClassHash::const_iterator it = m_cursorClassHash.constFind(declCursor); + if (it == m_cursorClassHash.constEnd()) { + // Set unqualified name. This happens in cases like "class X : public std::list<...>" + // "template class Foo : public T" and standard types like true_type, false_type. + m_currentClass->setBaseClasses(m_currentClass->baseClasses() << baseClassName); + return; + } + // Completely qualify the class name by looking it up and taking its scope + // plus the actual baseClass stripped off any scopes. Consider: + // namespace std { + // template class vector {}; + // namespace n { + // class Foo : public vector {}; + // } + // } + // should have "std::vector" as base class (whereas the type of the base class is + // "std::vector"). + const QStringList &baseScope = it.value()->scope(); + if (!baseScope.isEmpty()) { + const int lastSep = baseClassName.lastIndexOf(colonColon()); + if (lastSep >= 0) + baseClassName.remove(0, lastSep + colonColon().size()); + baseClassName.prepend(colonColon()); + baseClassName.prepend(baseScope.join(colonColon())); + } + m_currentClass->setBaseClasses(m_currentClass->baseClasses() << baseClassName); +} + +static inline CXCursor definitionFromTypeRef(const CXCursor &typeRefCursor) +{ + Q_ASSERT(typeRefCursor.kind == CXCursor_TypeRef); + return clang_getTypeDeclaration(clang_getCursorType(typeRefCursor)); +} + +// Qualify function arguments or fields that are typedef'ed from another scope: +// enum ConversionFlag {}; +// typedef QFlags ConversionFlags; +// class QTextCodec { +// enum ConversionFlag {}; +// typedef QFlags ConversionFlags; +// struct ConverterState { +// explicit ConverterState(ConversionFlags); +// ^^ qualify to QTextCodec::ConversionFlags +// ConversionFlags m_flags; +// ^^ ditto + +template // ArgumentModelItem, VariableModelItem +void BuilderPrivate::qualifyTypeDef(const CXCursor &typeRefCursor, const QSharedPointer &item) const +{ + typedef typename CursorTypedefHash::const_iterator ConstIt; + + TypeInfo type = item->type(); + if (type.qualifiedName().size() == 1) { // item's type is unqualified. + const ConstIt it = m_cursorTypedefHash.constFind(definitionFromTypeRef(typeRefCursor)); + if (it != m_cursorTypedefHash.constEnd() && !it.value()->scope().isEmpty()) { + type.setQualifiedName(it.value()->scope() + type.qualifiedName()); + item->setType(type); + } + } +} + +Builder::Builder() +{ + d = new BuilderPrivate(this); +} + +Builder::~Builder() +{ + delete d; +} + +bool Builder::visitLocation(const CXSourceLocation &location) const +{ + return !clang_Location_isInSystemHeader(location); +} + +FileModelItem Builder::dom() const +{ + Q_ASSERT(!d->m_scopeStack.isEmpty()); + return qSharedPointerDynamicCast<_FileModelItem>(d->m_scopeStack.constFirst()); +} + +static QString msgOutOfOrder(const CXCursor &cursor, const char *expectedScope) +{ + return getCursorKindName(cursor.kind) + QLatin1Char(' ') + + getCursorSpelling(cursor) + QLatin1String(" encountered outside ") + + QLatin1String(expectedScope) + QLatin1Char('.'); +} + +static CodeModel::ClassType codeModelClassTypeFromCursor(CXCursorKind kind) +{ + CodeModel::ClassType result = CodeModel::Class; + if (kind == CXCursor_UnionDecl) + result = CodeModel::Union; + else if (kind == CXCursor_StructDecl) + result = CodeModel::Struct; + return result; +} + +BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) +{ + switch (cursor.kind) { + case CXCursor_CXXAccessSpecifier: + d->m_currentFunctionType = CodeModel::Normal; + break; + case CXCursor_AnnotateAttr: { + const QString annotation = getCursorSpelling(cursor); + if (annotation == QLatin1String("qt_slot")) + d->m_currentFunctionType = CodeModel::Slot; + else if (annotation == QLatin1String("qt_signal")) + d->m_currentFunctionType = CodeModel::Signal; + else + d->m_currentFunctionType = CodeModel::Normal; + } + break; + case CXCursor_CXXBaseSpecifier: + if (d->m_currentClass.isNull()) { + const Diagnostic d(msgOutOfOrder(cursor, "class"), cursor, CXDiagnostic_Error); + qWarning() << d; + appendDiagnostic(d); + return Error; + } + d->addBaseClass(cursor); + break; + case CXCursor_ClassDecl: + case CXCursor_UnionDecl: + case CXCursor_StructDecl: + if (clang_isCursorDefinition(cursor) == 0) + return Skip; + if (!d->addClass(cursor, codeModelClassTypeFromCursor(cursor.kind))) + return Error; + break; + case CXCursor_ClassTemplate: + case CXCursor_ClassTemplatePartialSpecialization: + if (clang_isCursorDefinition(cursor) == 0) + return Skip; + d->addClass(cursor, CodeModel::Class); + d->m_currentClass->setName(d->m_currentClass->name() + templateBrackets()); + d->m_scope.back() += templateBrackets(); + break; + case CXCursor_EnumDecl: { + QString name = getCursorSpelling(cursor); + const bool anonymous = name.isEmpty(); + if (anonymous) + name = QStringLiteral("enum_") + QString::number(++d->m_anonymousEnumCount); + d->m_currentEnum.reset(new _EnumModelItem(d->m_model, name)); + setFileName(cursor, d->m_currentEnum.data()); + d->m_currentEnum->setScope(d->m_scope); + d->m_currentEnum->setAnonymous(anonymous); + if (!qSharedPointerDynamicCast<_ClassModelItem>(d->m_scopeStack.back()).isNull()) + d->m_currentEnum->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor))); + d->m_scopeStack.back()->addEnum(d->m_currentEnum); + } + break; + case CXCursor_EnumConstantDecl: { + const QString name = getCursorSpelling(cursor); + if (d->m_currentEnum.isNull()) { + const Diagnostic d(msgOutOfOrder(cursor, "enum"), cursor, CXDiagnostic_Error); + qWarning() << d; + appendDiagnostic(d); + return Error; + } + EnumeratorModelItem enumConstant(new _EnumeratorModelItem(d->m_model, name)); + enumConstant->setValue(d->cursorValueExpression(this, cursor)); + d->m_currentEnum->addEnumerator(enumConstant); + } + break; + case CXCursor_VarDecl: + // static class members are seen as CXCursor_VarDecl + if (!d->m_currentClass.isNull() && isClassCursor(clang_getCursorSemanticParent(cursor))) { + d->addField(cursor); + d->m_currentField->setStatic(true); + } + break; + case CXCursor_FieldDecl: + d->addField(cursor); + break; +#if CINDEX_VERSION_MAJOR > 0 || CINDEX_VERSION_MINOR >= 37 // Clang 4.0 + case CXCursor_FriendDecl: + return Skip; +#endif + case CXCursor_Constructor: + case CXCursor_Destructor: // Note: Also use clang_CXXConstructor_is..Constructor? + case CXCursor_CXXMethod: + case CXCursor_ConversionFunction: + // Skip inline member functions outside class, only go by declarations inside class + if (!withinClassDeclaration(cursor)) + return Skip; + d->m_currentFunction = d->createMemberFunction(cursor, CodeModel::Normal); + d->m_scopeStack.back()->addFunction(d->m_currentFunction); + break; + // Not fully supported, currently, seen as normal function + // Note: May appear inside class (member template) or outside (free template). + case CXCursor_FunctionTemplate: { + const CXCursor semParent = clang_getCursorSemanticParent(cursor); + if (isClassCursor(semParent)) { + if (semParent == clang_getCursorLexicalParent(cursor)) { + d->m_currentFunction = d->createMemberFunction(cursor, CodeModel::Normal); + d->m_scopeStack.back()->addFunction(d->m_currentFunction); + break; + } else { + return Skip; // inline member functions outside class + } + } + } + Q_FALLTHROUGH(); // fall through to free template function. + case CXCursor_FunctionDecl: + d->m_currentFunction = d->createFunction(cursor); + d->m_scopeStack.back()->addFunction(d->m_currentFunction); + break; + case CXCursor_Namespace: { + const QString name = getCursorSpelling(cursor); + const NamespaceModelItem parentNamespaceItem = qSharedPointerDynamicCast<_NamespaceModelItem>(d->m_scopeStack.back()); + if (parentNamespaceItem.isNull()) { + const QString message = msgOutOfOrder(cursor, "namespace") + + QLatin1String(" (current scope: ") + d->m_scopeStack.back()->name() + QLatin1Char(')'); + const Diagnostic d(message, cursor, CXDiagnostic_Error); + qWarning() << d; + appendDiagnostic(d); + return Error; + } + // If possible, continue existing namespace (as otherwise, all headers + // where a namespace is continued show up in the type database). + NamespaceModelItem namespaceItem = parentNamespaceItem->findNamespace(name); + if (namespaceItem.isNull()) { + namespaceItem.reset(new _NamespaceModelItem(d->m_model, name)); + setFileName(cursor, namespaceItem.data()); + namespaceItem->setScope(d->m_scope); + parentNamespaceItem->addNamespace(namespaceItem); + } + d->pushScope(namespaceItem); + } + break; + case CXCursor_ParmDecl: + // Skip in case of nested CXCursor_ParmDecls in case one parameter is a function pointer + // and function pointer typedefs. + if (d->m_currentArgument.isNull() && !d->m_currentFunction.isNull()) { + const QString name = getCursorSpelling(cursor); + d->m_currentArgument.reset(new _ArgumentModelItem(d->m_model, name)); + d->m_currentArgument->setType(d->createTypeInfo(cursor)); + d->m_currentFunction->addArgument(d->m_currentArgument); + QString defaultValueExpression = d->cursorValueExpression(this, cursor); + if (!defaultValueExpression.isEmpty()) { + d->m_currentArgument->setDefaultValueExpression(defaultValueExpression); + d->m_currentArgument->setDefaultValue(true); + } + } else { + return Skip; + } + break; + case CXCursor_TemplateTypeParameter: + case CXCursor_NonTypeTemplateParameter: { + const TemplateParameterModelItem tItem = cursor.kind == CXCursor_TemplateTemplateParameter + ? d->createTemplateParameter(cursor) : d->createNonTypeTemplateParameter(cursor); + // Apply to function/member template? + if (!d->m_currentFunction.isNull()) { + d->m_currentFunction->setTemplateParameters(d->m_currentFunction->templateParameters() << tItem); + } else if (!d->m_currentClass.isNull()) { // Apply to class + const QString &tplParmName = tItem->name(); + if (Q_UNLIKELY(!insertTemplateParameterIntoClassName(tplParmName, d->m_currentClass) + || !insertTemplateParameterIntoClassName(tplParmName, &d->m_scope.back()))) { + const QString message = QStringLiteral("Error inserting template parameter \"") + tplParmName + + QStringLiteral("\" into ") + d->m_currentClass->name(); + const Diagnostic d(message, cursor, CXDiagnostic_Error); + qWarning() << d; + appendDiagnostic(d); + return Error; + } + d->m_currentClass->setTemplateParameters(d->m_currentClass->templateParameters() << tItem); + } + } + break; + case CXCursor_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); + } + break; + case CXCursor_TypeRef: + if (!d->m_currentFunction.isNull()) { + if (d->m_currentArgument.isNull()) + d->qualifyTypeDef(cursor, d->m_currentFunction); // return type + else + d->qualifyTypeDef(cursor, d->m_currentArgument); + } else if (!d->m_currentField.isNull()) { + d->qualifyTypeDef(cursor, d->m_currentField); + } + break; + default: + break; + } + return BaseVisitor::Recurse; +} + +bool Builder::endToken(const CXCursor &cursor) +{ + switch (cursor.kind) { + case CXCursor_UnionDecl: + case CXCursor_ClassDecl: + case CXCursor_StructDecl: + case CXCursor_ClassTemplate: + case CXCursor_ClassTemplatePartialSpecialization: + d->popScope(); + // Continue in outer class after leaving inner class? + if (ClassModelItem lastClass = qSharedPointerDynamicCast<_ClassModelItem>(d->m_scopeStack.back())) + d->m_currentClass = lastClass; + else + d->m_currentClass.clear(); + d->m_currentFunctionType = CodeModel::Normal; + break; + case CXCursor_EnumDecl: + d->m_currentEnum.clear(); + break; + case CXCursor_VarDecl: + case CXCursor_FieldDecl: + d->m_currentField.clear(); + break; + case CXCursor_Constructor: + d->qualifyConstructor(cursor); + d->m_currentFunction.clear(); + break; + case CXCursor_Destructor: + case CXCursor_CXXMethod: + case CXCursor_FunctionDecl: + case CXCursor_FunctionTemplate: + d->m_currentFunction.clear(); + break; + case CXCursor_Namespace: + d->popScope(); + break; + case CXCursor_ParmDecl: + d->m_currentArgument.clear(); + break; + default: + break; + } + return true; +} + +} // namespace clang diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.h b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.h new file mode 100644 index 000000000..c97b7d2b7 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 CLANGBUILDER_H +#define CLANGBUILDER_H + +#include "clangparser.h" + +#include + +namespace clang { + +class BuilderPrivate; + +class Builder : public BaseVisitor { +public: + Builder(); + ~Builder(); + + bool visitLocation(const CXSourceLocation &location) const override; + + StartTokenResult startToken(const CXCursor &cursor) override; + bool endToken(const CXCursor &cursor) override; + + FileModelItem dom() const; + +private: + BuilderPrivate *d; +}; + +} // namespace clang + +#endif // CLANGBUILDER_H diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.cpp new file mode 100644 index 000000000..8d0fd098a --- /dev/null +++ b/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "clangdebugutils.h" +#include "clangutils.h" + +#include +#include + +#include + +#ifndef QT_NO_DEBUG_STREAM + +#ifdef Q_OS_WIN +const char pathSep = '\\'; +#else +const char pathSep = '/'; +#endif + +static const char *baseName(const char *fileName) +{ + const char *b = strrchr(fileName, pathSep); + return b ? b + 1 : fileName; +} + +QDebug operator<<(QDebug s, const CXString &cs) +{ + s << clang_getCString(cs); + return s; +} + +QDebug operator<<(QDebug s, CXCursorKind cursorKind) // Enum +{ + const CXString kindName = clang_getCursorKindSpelling(cursorKind); + s << kindName; + clang_disposeString(kindName); + return s; +} + +static const char *accessSpecsStrings[] +{ + // CX_CXXInvalidAccessSpecifier, CX_CXXPublic, CX_CXXProtected, CX_CXXPrivate + "invalid", "public", "protected", "private" +}; + +QDebug operator<<(QDebug s, CX_CXXAccessSpecifier ac) +{ + s << accessSpecsStrings[ac]; + return s; +} + +QDebug operator<<(QDebug s, const CXType &t) +{ + CXString typeSpelling = clang_getTypeSpelling(t); + s << typeSpelling; + clang_disposeString(typeSpelling); + return s; +} + +QDebug operator<<(QDebug s, const CXCursor &cursor) +{ + QDebugStateSaver saver(s); + s.nospace(); + s.noquote(); + const CXCursorKind kind = clang_getCursorKind(cursor); + s << kind; + if (kind >= CXCursor_FirstInvalid && kind <= CXCursor_LastInvalid) + return s; + const CXType type = clang_getCursorType(cursor); + switch (kind) { + case CXCursor_CXXAccessSpecifier: + s << ' ' << clang_getCXXAccessSpecifier(cursor); + break; + case CXCursor_CXXBaseSpecifier: + s << ", inherits=\"" << clang::getCursorSpelling(clang_getTypeDeclaration(type)) << '"'; + break; + case CXCursor_CXXMethod: + case CXCursor_FunctionDecl: + case CXCursor_ConversionFunction: + s << ", result type=\"" << clang_getCursorResultType(cursor) << '"'; + break; + case CXCursor_TypedefDecl: + s << ", underlyingType=\"" << clang_getTypedefDeclUnderlyingType(cursor) << '"'; + break; + default: + break; + } + + if (type.kind != CXType_Invalid) + s << ", type=\"" << type << '"'; + if (clang_Cursor_hasAttrs(cursor)) + s << ", [attrs]"; + + const QString cursorSpelling = clang::getCursorSpelling(cursor); + if (!cursorSpelling.isEmpty()) + s << ", spelling=\"" << cursorSpelling << '"'; + CXString cursorDisplay = clang_getCursorDisplayName(cursor); + if (const char *dpy = clang_getCString(cursorDisplay)) { + const QString display = QString::fromUtf8(dpy); + if (display != cursorSpelling) + s << ", display=\"" << dpy << '"'; + } + clang_disposeString(cursorDisplay); + return s; +} + +QDebug operator<<(QDebug s, const CXSourceLocation &location) +{ + QDebugStateSaver saver(s); + s.nospace(); + CXFile file; // void * + unsigned line; + unsigned column; + unsigned offset; + clang_getExpansionLocation(location, &file, &line, &column, &offset); + const CXString cxFileName = clang_getFileName(file); + // Has been observed to be 0 for invalid locations + if (const char *cFileName = clang_getCString(cxFileName)) + s << baseName(cFileName) << ':'; + s << line << ':' << column; + clang_disposeString(cxFileName); + return s; +} + +#endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.h b/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.h new file mode 100644 index 000000000..323efdd2a --- /dev/null +++ b/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 CLANGDEBUGUTILS_H +#define CLANGDEBUGUTILS_H + +#include + +#include + +QT_FORWARD_DECLARE_CLASS(QDebug) +QT_FORWARD_DECLARE_CLASS(QString) + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug s, const CXString &cs); +QDebug operator<<(QDebug s, CXCursorKind cursorKind); +QDebug operator<<(QDebug s, CX_CXXAccessSpecifier ac); +QDebug operator<<(QDebug s, const CXType &t); +QDebug operator<<(QDebug s, const CXCursor &cursor); +QDebug operator<<(QDebug s, const CXSourceLocation &location); +#endif // !QT_NO_DEBUG_STREAM + +#endif // CLANGDEBUGUTILS_H diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp new file mode 100644 index 000000000..eb3be115c --- /dev/null +++ b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "clangparser.h" +#include "clangutils.h" +#include "clangdebugutils.h" +#include "compilersupport.h" + +#include +#include +#include +#include +#include +#include + +namespace clang { + +SourceFileCache::Snippet SourceFileCache::getCodeSnippet(const CXCursor &cursor) +{ + Snippet result(nullptr, nullptr); + const SourceRange range = getCursorRange(cursor); + if (range.first.file.isEmpty() || range.second.file != range.first.file) + return result; + FileBufferCache::Iterator it = m_fileBufferCache.find(range.first.file); + if (it == m_fileBufferCache.end()) { + QFile file(range.first.file); + if (!file.open(QIODevice::ReadOnly)) { + qWarning().noquote().nospace() + << "Can't open " << QDir::toNativeSeparators(range.first.file) + << ": " << file.errorString(); + return result; + } + it = m_fileBufferCache.insert(range.first.file, file.readAll()); + } + + const unsigned pos = range.first.offset; + const unsigned end = range.second.offset; + const QByteArray &contents = it.value(); + if (end >= unsigned(contents.size())) { + qWarning().noquote().nospace() << "Range end " << end << " is above size of " + << range.first.file << " (" << contents.size() << ')'; + return result; + } + result.first = contents.constData() + pos; + result.second = contents.constData() + end; + return result; +} + +BaseVisitor::BaseVisitor() = default; +BaseVisitor::~BaseVisitor() = default; + +bool BaseVisitor::visitLocation(const CXSourceLocation &location) const +{ + return clang_Location_isFromMainFile(location) != 0; +} + +BaseVisitor::StartTokenResult BaseVisitor::cbHandleStartToken(const CXCursor &cursor) +{ + switch (cursor.kind) { + default: + break; + } + + return startToken(cursor); +} + +bool BaseVisitor::cbHandleEndToken(const CXCursor &cursor, StartTokenResult startResult) +{ + const bool result = startResult != Recurse || endToken(cursor); + switch (cursor.kind) { + default: + break; + } + + return result; +} + +BaseVisitor::CodeSnippet BaseVisitor::getCodeSnippet(const CXCursor &cursor) +{ + CodeSnippet result = m_fileCache.getCodeSnippet(cursor); + if (result.first == nullptr) + appendDiagnostic(Diagnostic(QStringLiteral("Unable to retrieve code snippet."), cursor, CXDiagnostic_Error)); + return result; +} + +QString BaseVisitor::getCodeSnippetString(const CXCursor &cursor) +{ + CodeSnippet result = m_fileCache.getCodeSnippet(cursor); + return result.first != nullptr + ? QString::fromUtf8(result.first, int(result.second - result.first)) + : QString(); +} + +static CXChildVisitResult + visitorCallback(CXCursor cursor, CXCursor /* parent */, CXClientData clientData) +{ + BaseVisitor *bv = reinterpret_cast(clientData); + + const CXSourceLocation location = clang_getCursorLocation(cursor); + if (!bv->visitLocation(location)) + return CXChildVisit_Continue; + + const BaseVisitor::StartTokenResult startResult = bv->cbHandleStartToken(cursor); + switch (startResult) { + case clang::BaseVisitor::Error: + return CXChildVisit_Break; + case clang::BaseVisitor::Skip: + break; + case clang::BaseVisitor::Recurse: + clang_visitChildren(cursor, visitorCallback, clientData); + break; + } + + if (!bv->cbHandleEndToken(cursor, startResult)) + return CXChildVisit_Break; + + return CXChildVisit_Continue; +} + +BaseVisitor::Diagnostics BaseVisitor::diagnostics() const +{ + return m_diagnostics; +} + +void BaseVisitor::setDiagnostics(const Diagnostics &d) +{ + m_diagnostics = d; +} + +void BaseVisitor::appendDiagnostic(const Diagnostic &d) +{ + m_diagnostics.append(d); +} + +static inline const char **byteArrayListToFlatArgV(const QByteArrayList &bl) +{ + const char **result = new const char *[bl.size() + 1]; + result[bl.size()] = nullptr; + std::transform(bl.cbegin(), bl.cend(), result, + [] (const QByteArray &a) { return a.constData(); }); + return result; +} + +static QByteArray msgCreateTranslationUnit(const QByteArrayList clangArgs, unsigned flags) +{ + QByteArray result = "clang_parseTranslationUnit2(0x"; + result += QByteArray::number(flags, 16); + const int count = clangArgs.size(); + result += ", cmd[" + QByteArray::number(count) + "]="; + for (int i = 0; i < count; ++i) { + const QByteArray &arg = clangArgs.at(i); + if (i) + result += ' '; + const bool quote = arg.contains(' ') || arg.contains('('); + if (quote) + result += '"'; + result += arg; + if (quote) + result += '"'; + } + result += ')'; + return result; +} + +static CXTranslationUnit createTranslationUnit(CXIndex index, + const QByteArrayList &args, + unsigned flags = 0) +{ + // courtesy qdoc + const unsigned defaultFlags = CXTranslationUnit_SkipFunctionBodies + | CXTranslationUnit_Incomplete; + + static const QByteArrayList defaultArgs = { + "-std=c++14", // ! otherwise, t.h is parsed as "C" + "-fPIC", + "-fno-exceptions", // Workaround for clang bug http://reviews.llvm.org/D17988 +#ifdef Q_OS_MACOS + "-Wno-expansion-to-defined", // Workaround for warnings in Darwin stdlib, see + // https://github.com/darlinghq/darling/issues/204 +#endif + "-Wno-constant-logical-operand" + }; + + const QByteArrayList clangArgs = emulatedCompilerOptions() + defaultArgs + args; + QScopedArrayPointer argv(byteArrayListToFlatArgV(clangArgs)); + qDebug().noquote().nospace() << msgCreateTranslationUnit(clangArgs, flags); + + CXTranslationUnit tu; + CXErrorCode err = clang_parseTranslationUnit2(index, nullptr, argv.data(), + clangArgs.size(), nullptr, 0, + defaultFlags | flags, &tu); + if (err || !tu) { + qWarning().noquote().nospace() << "Could not parse " + << clangArgs.constLast().constData() << ", error code: " << err; + return nullptr; + } + return tu; +} + +/* clangFlags are flags to clang_parseTranslationUnit2() such as + * CXTranslationUnit_KeepGoing (from CINDEX_VERSION_MAJOR/CINDEX_VERSION_MINOR 0.35) + */ + +bool parse(const QByteArrayList &clangArgs, unsigned clangFlags, BaseVisitor &bv) +{ + CXIndex index = clang_createIndex(0 /* excludeDeclarationsFromPCH */, + 1 /* displayDiagnostics */); + if (!index) { + qWarning() << "clang_createIndex() failed!"; + return false; + } + + CXTranslationUnit translationUnit = createTranslationUnit(index, clangArgs, clangFlags); + if (!translationUnit) + return false; + + CXCursor rootCursor = clang_getTranslationUnitCursor(translationUnit); + + clang_visitChildren(rootCursor, visitorCallback, reinterpret_cast(&bv)); + + QVector diagnostics = getDiagnostics(translationUnit); + diagnostics.append(bv.diagnostics()); + bv.setDiagnostics(diagnostics); + + const bool ok = maxSeverity(diagnostics) < CXDiagnostic_Error; + if (!ok) { + QDebug debug = qWarning(); + debug.noquote(); + debug.nospace(); + debug << "Errors in " + << QDir::toNativeSeparators(QFile::decodeName(clangArgs.constLast())) << ":\n"; + for (const Diagnostic &diagnostic : diagnostics) + debug << diagnostic << '\n'; + } + + clang_disposeTranslationUnit(translationUnit); + clang_disposeIndex(index); + return ok; +} + +} // namespace clang diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangparser.h b/sources/shiboken2/ApiExtractor/clangparser/clangparser.h new file mode 100644 index 000000000..ef1424f17 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/clangparser/clangparser.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 CLANGPARSER_H +#define CLANGPARSER_H + +#include + +#include +#include +#include +#include +#include + +namespace clang { + +struct Diagnostic; + +class SourceFileCache { +public: + typedef QPair Snippet; + + Snippet getCodeSnippet(const CXCursor &cursor); + +private: + typedef QHash FileBufferCache; + + FileBufferCache m_fileBufferCache; +}; + +class BaseVisitor { + Q_DISABLE_COPY(BaseVisitor) +public: + typedef QVector Diagnostics; + typedef SourceFileCache::Snippet CodeSnippet; + + enum StartTokenResult { Error, Skip, Recurse }; + + BaseVisitor(); + virtual ~BaseVisitor(); + + // Whether location should be visited. + // defaults to clang_Location_isFromMainFile() + virtual bool visitLocation(const CXSourceLocation &location) const; + + virtual StartTokenResult startToken(const CXCursor &cursor) = 0; + virtual bool endToken(const CXCursor &cursor) = 0; + + StartTokenResult cbHandleStartToken(const CXCursor &cursor); + bool cbHandleEndToken(const CXCursor &cursor, StartTokenResult startResult); + + CodeSnippet getCodeSnippet(const CXCursor &cursor); + QString getCodeSnippetString(const CXCursor &cursor); + + Diagnostics diagnostics() const; + void setDiagnostics(const Diagnostics &d); + void appendDiagnostic(const Diagnostic &d); + +private: + SourceFileCache m_fileCache; + Diagnostics m_diagnostics; +}; + +bool parse(const QByteArrayList &clangArgs, unsigned clangFlags, BaseVisitor &ctx); + +} // namespace clang + +#endif // !CLANGPARSER_H diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp new file mode 100644 index 000000000..fdc8d3312 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "clangutils.h" + +#include +#include +#include +#include + +bool operator==(const CXCursor &c1, const CXCursor &c2) +{ + return c1.kind == c2.kind + && c1.xdata == c2.xdata + && std::equal(c1.data, c1.data + sizeof(c1.data) / sizeof(c1.data[0]), c2.data); +} + +uint qHash(const CXCursor &c, uint seed) +{ + return qHash(c.kind) ^ qHash(c.xdata) ^ qHash(c.data[0]) + ^ qHash(c.data[1]) ^ qHash(c.data[2]) ^ seed; +} + +namespace clang { + +SourceLocation getExpansionLocation(const CXSourceLocation &location) +{ + SourceLocation result; + CXFile file; // void * + clang_getExpansionLocation(location, &file, &result.line, &result.column, &result.offset); + const CXString cxFileName = clang_getFileName(file); + // Has been observed to be 0 for invalid locations + if (const char *cFileName = clang_getCString(cxFileName)) + result.file = QString::fromUtf8(cFileName); + clang_disposeString(cxFileName); + return result; +} + +SourceLocation getCursorLocation(const CXCursor &cursor) +{ + const CXSourceRange extent = clang_getCursorExtent(cursor); + return getExpansionLocation(clang_getRangeStart(extent)); +} + +CXString getFileNameFromLocation(const CXSourceLocation &location) +{ + CXFile file; + unsigned line; + unsigned column; + unsigned offset; + clang_getExpansionLocation(location, &file, &line, &column, &offset); + return clang_getFileName(file); +} + +SourceRange getCursorRange(const CXCursor &cursor) +{ + const CXSourceRange extent = clang_getCursorExtent(cursor); + return qMakePair(getExpansionLocation(clang_getRangeStart(extent)), + getExpansionLocation(clang_getRangeEnd(extent))); +} + +QString getCursorKindName(CXCursorKind cursorKind) +{ + CXString kindName = clang_getCursorKindSpelling(cursorKind); + const QString result = QString::fromUtf8(clang_getCString(kindName)); + clang_disposeString(kindName); + return result; +} + +QString getCursorSpelling(const CXCursor &cursor) +{ + CXString cursorSpelling = clang_getCursorSpelling(cursor); + const QString result = QString::fromUtf8(clang_getCString(cursorSpelling)); + clang_disposeString(cursorSpelling); + return result; +} + +QString getCursorDisplayName(const CXCursor &cursor) +{ + CXString displayName = clang_getCursorDisplayName(cursor); + const QString result = QString::fromUtf8(clang_getCString(displayName)); + clang_disposeString(displayName); + return result; +} + +QString getTypeName(const CXType &type) +{ + CXString typeSpelling = clang_getTypeSpelling(type); + const QString result = QString::fromUtf8(clang_getCString(typeSpelling)); + clang_disposeString(typeSpelling); + return result; +} + +Diagnostic::Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s) + : message(m), location(getCursorLocation(c)), source(Other), severity(s) +{ +} + +Diagnostic Diagnostic::fromCXDiagnostic(CXDiagnostic cd) +{ + Diagnostic result; + result.source = Clang; + CXString spelling = clang_getDiagnosticSpelling(cd); + result.message = QString::fromUtf8(clang_getCString(spelling)); + clang_disposeString(spelling); + result.severity = clang_getDiagnosticSeverity(cd); + result.location = getExpansionLocation(clang_getDiagnosticLocation(cd)); + + CXDiagnosticSet childDiagnostics = clang_getChildDiagnostics(cd); + if (const unsigned childCount = clang_getNumDiagnosticsInSet(childDiagnostics)) { + result.childMessages.reserve(int(childCount)); + const unsigned format = clang_defaultDiagnosticDisplayOptions(); + for (unsigned i = 0; i < childCount; ++i) { + CXDiagnostic childDiagnostic = clang_getDiagnosticInSet(childDiagnostics, i); + CXString cdm = clang_formatDiagnostic(childDiagnostic, format); + result.childMessages.append(QString::fromUtf8(clang_getCString(cdm))); + clang_disposeString(cdm); + clang_disposeDiagnostic(childDiagnostic); + } + } + + return result; +} + +QVector getDiagnostics(CXTranslationUnit tu) +{ + QVector result; + const unsigned count = clang_getNumDiagnostics(tu); + result.reserve(int(count)); + for (unsigned i = 0; i < count; ++i) { + const CXDiagnostic d = clang_getDiagnostic(tu, i); + result.append(Diagnostic::fromCXDiagnostic(d)); + clang_disposeDiagnostic(d); + } + return result; +} + +CXDiagnosticSeverity maxSeverity(const QVector &ds) +{ + CXDiagnosticSeverity result = CXDiagnostic_Ignored; + for (const Diagnostic d : ds) { + if (d.severity > result) + result = d.severity; + } + return result; +} + +#ifndef QT_NO_DEBUG_STREAM + +QDebug operator<<(QDebug s, const SourceLocation &l) +{ + QDebugStateSaver saver(s); + s.nospace(); + s.noquote(); + s << QDir::toNativeSeparators(l.file) << ':' << l.line; + if (l.column) + s << ':' << l.column; + return s; +} + +// Roughly follow g++ format: +// file.cpp:214:37: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] +QDebug operator<<(QDebug s, const Diagnostic &d) +{ + QDebugStateSaver saver(s); + s.nospace(); + s.noquote(); + s << d.location << ": "; + switch (d.severity) { + case CXDiagnostic_Ignored: + s << "ignored"; + break; + case CXDiagnostic_Note: + s << "note"; + break; + case CXDiagnostic_Warning: + s << "warning"; + break; + case CXDiagnostic_Error: + s << "error"; + break; + case CXDiagnostic_Fatal: + s << "fatal"; + break; + } + s << ": " << d.message; + + if (d.source != Diagnostic::Clang) + s << " [other]"; + + if (const int childMessagesCount = d.childMessages.size()) { + s << '\n'; + for (int i = 0; i < childMessagesCount; ++i) + s << " " << d.childMessages.at(i) << '\n'; + } + + return s; +} + +#endif // QT_NO_DEBUG_STREAM + +} // namespace clang diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h new file mode 100644 index 000000000..3437f51eb --- /dev/null +++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 CLANGUTILS_H +#define CLANGUTILS_H + +#include +#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QDebug) + +bool operator==(const CXCursor &c1, const CXCursor &c2); +uint qHash(const CXCursor &c, uint seed = 0); + +namespace clang { + +QString getCursorKindName(CXCursorKind cursorKind); +QString getCursorSpelling(const CXCursor &cursor); +QString getCursorDisplayName(const CXCursor &cursor); +QString getTypeName(const CXType &type); +inline QString getCursorTypeName(const CXCursor &cursor) + { return getTypeName(clang_getCursorType(cursor)); } +inline QString getCursorResultTypeName(const CXCursor &cursor) + { return getTypeName(clang_getCursorResultType(cursor)); } + +inline bool isCursorValid(const CXCursor &c) +{ + return c.kind < CXCursor_FirstInvalid || c.kind > CXCursor_LastInvalid; +} + +struct SourceLocation +{ + int compare(const SourceLocation &rhs) const; + + QString file; + unsigned line = 0; + unsigned column = 0; + unsigned offset = 0; +}; + +SourceLocation getExpansionLocation(const CXSourceLocation &location); + +typedef QPair SourceRange; + +SourceLocation getCursorLocation(const CXCursor &cursor); +CXString getFileNameFromLocation(const CXSourceLocation &location); +SourceRange getCursorRange(const CXCursor &cursor); + +struct Diagnostic { + enum Source { Clang, Other }; + + Diagnostic() : source(Clang) {} + // Clang + static Diagnostic fromCXDiagnostic(CXDiagnostic cd); + // Other + explicit Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s = CXDiagnostic_Warning); + + QString message; + QStringList childMessages; + SourceLocation location; + Source source; + CXDiagnosticSeverity severity; +}; + +QVector getDiagnostics(CXTranslationUnit tu); +CXDiagnosticSeverity maxSeverity(const QVector &ds); + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug, const SourceLocation &); +QDebug operator<<(QDebug, const Diagnostic &); +#endif // QT_NO_DEBUG_STREAM +} // namespace clang + +#endif // CLANGUTILS_H diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp new file mode 100644 index 000000000..df82f9080 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "compilersupport.h" +#include "header_paths.h" + +#include +#include +#include + +#include +#include +#include + +namespace clang { + +static bool runProcess(const QString &program, const QStringList &arguments, + QByteArray *stdOutIn = nullptr, QByteArray *stdErrIn = nullptr) +{ + QProcess process; + process.start(program, arguments, QProcess::ReadWrite); + if (!process.waitForStarted()) { + qWarning().noquote().nospace() << "Unable to start " + << process.program() << ": " << process.errorString(); + return false; + } + process.closeWriteChannel(); + const bool finished = process.waitForFinished(); + const QByteArray stdErr = process.readAllStandardError(); + if (stdErrIn) + *stdErrIn = stdErr; + if (stdOutIn) + *stdOutIn = process.readAllStandardOutput(); + + if (!finished) { + qWarning().noquote().nospace() << process.program() << " timed out: " << stdErr; + process.kill(); + return false; + } + + if (process.exitStatus() != QProcess::NormalExit) { + qWarning().noquote().nospace() << process.program() << " crashed: " << stdErr; + return false; + } + + if (process.exitCode() != 0) { + qWarning().noquote().nospace() << process.program() << " exited " + << process.exitCode() << ": " << stdErr; + return false; + } + + return true; +} + +#if defined(Q_CC_GNU) + +static QByteArray frameworkPath() { return QByteArrayLiteral(" (framework directory)"); } + +// Determine g++'s internal include paths from the output of +// g++ -E -x c++ - -v search starts here: +// /usr/local/include +// /System/Library/Frameworks (framework directory) +// End of search list. +static HeaderPaths gppInternalIncludePaths(const QString &compiler) +{ + HeaderPaths result; + QStringList arguments; + arguments << QStringLiteral("-E") << QStringLiteral("-x") << QStringLiteral("c++") + << QStringLiteral("-") << QStringLiteral("-v"); + QByteArray stdOut; + QByteArray stdErr; + if (!runProcess(compiler, arguments, &stdOut, &stdErr)) + return result; + const QByteArrayList stdErrLines = stdErr.split('\n'); + bool isIncludeDir = false; + for (const QByteArray &line : stdErrLines) { + if (isIncludeDir) { + if (line.startsWith(QByteArrayLiteral("End of search list"))) { + isIncludeDir = false; + } else { + HeaderPath headerPath(line.trimmed()); + if (headerPath.path.endsWith(frameworkPath())) { + headerPath.m_isFramework = true; + headerPath.path.truncate(headerPath.path.size() - frameworkPath().size()); + } + result.append(headerPath); + } + } else if (line.startsWith(QByteArrayLiteral("#include <...> search starts here"))) { + isIncludeDir = true; + } + } + return result; +} +#endif // Q_CC_MSVC + +// For MSVC, we set the MS compatibility version and let Clang figure out its own +// options and include paths. +// For the others, we pass "-nostdinc" since libclang tries to add it's own system +// include paths, which together with the clang compiler paths causes some clash +// which causes std types not being found and construct -I/-F options from the +// include paths of the host compiler. + +static QByteArray noStandardIncludeOption() { return QByteArrayLiteral("-nostdinc"); } + +// Returns clang options needed for emulating the host compiler +QByteArrayList emulatedCompilerOptions() +{ + QByteArrayList result; +#if defined(Q_CC_MSVC) + const HeaderPaths headerPaths; + result.append(QByteArrayLiteral("-fms-compatibility-version=19")); +#elif defined(Q_CC_CLANG) + const HeaderPaths headerPaths = gppInternalIncludePaths(QStringLiteral("clang++")); + result.append(noStandardIncludeOption()); +#elif defined(Q_CC_GNU) + const HeaderPaths headerPaths = gppInternalIncludePaths(QStringLiteral("g++")); + result.append(noStandardIncludeOption()); +#else + const HeaderPaths headerPaths; +#endif + std::transform(headerPaths.cbegin(), headerPaths.cend(), + std::back_inserter(result), [](const HeaderPath &p) { + return HeaderPath::includeOption(p, true); + }); + return result; +} + +} // namespace clang diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h new file mode 100644 index 000000000..f556da551 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 COMPILERSUPPORT_H +#define COMPILERSUPPORT_H + +#include + +namespace clang { + +QByteArrayList emulatedCompilerOptions(); + +} // namespace clang + +#endif // COMPILERSUPPORT_H diff --git a/sources/shiboken2/ApiExtractor/cmake_uninstall.cmake b/sources/shiboken2/ApiExtractor/cmake_uninstall.cmake new file mode 100644 index 000000000..df95fb9d8 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/cmake_uninstall.cmake @@ -0,0 +1,21 @@ +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + IF(EXISTS "$ENV{DESTDIR}${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ELSE(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + ENDIF(EXISTS "$ENV{DESTDIR}${file}") +ENDFOREACH(file) diff --git a/sources/shiboken2/ApiExtractor/dependency.h b/sources/shiboken2/ApiExtractor/dependency.h new file mode 100644 index 000000000..17fbffcce --- /dev/null +++ b/sources/shiboken2/ApiExtractor/dependency.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 DEPENDENCY_H +#define DEPENDENCY_H + +#include +#include + +// Dependencies for topologically sorting classes +struct Dependency { + QString parent; + QString child; +}; + +typedef QVector Dependencies; + +#endif // DEPENDENCY_H diff --git a/sources/shiboken2/ApiExtractor/doc/CMakeLists.txt b/sources/shiboken2/ApiExtractor/doc/CMakeLists.txt new file mode 100644 index 000000000..d78844dc8 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/CMakeLists.txt @@ -0,0 +1,10 @@ + +find_program(SPHINX sphinx-build DOC "Path to sphinx-build binary.") + +if (SPHINX) + message("-- sphinx-build - found") + configure_file(conf.py.in conf.py @ONLY) + add_custom_target(doc ${SPHINX} -b html -c . ${CMAKE_CURRENT_SOURCE_DIR} html ) +else() + message("-- sphinx-build - not found! doc target disabled") +endif() \ No newline at end of file diff --git a/sources/shiboken2/ApiExtractor/doc/_templates/index.html b/sources/shiboken2/ApiExtractor/doc/_templates/index.html new file mode 100644 index 000000000..4aa14ede5 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_templates/index.html @@ -0,0 +1,27 @@ +{% extends "layout.html" %} +{% set title = 'Overview' %} +{% block body %} +
+

API Extractor {{ version }}

+ +

API Extractor is a tool that eases the development of bindings of Qt-based libraries for high + level languages by automating most of the process. + +

API Extractor is based on the + QtScriptGenerator project.

+ +

Documentation

+ + + +
+ + + + +
+
+{% endblock %} diff --git a/sources/shiboken2/ApiExtractor/doc/_templates/layout.html b/sources/shiboken2/ApiExtractor/doc/_templates/layout.html new file mode 100644 index 000000000..9dc53722d --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_templates/layout.html @@ -0,0 +1,41 @@ +{% extends "!layout.html" %} + +# Invert sidebars +{%- block sidebar1 %}{{ sidebar() }}{%- endblock %} +{%- block sidebar2 %}{%- endblock %} + +{%- block header %} +
+
+
+ + +
+
+{%- endblock -%} + +{%- block footer %} + +
+{%- endblock %} + +# No top relbar. +{%- block relbar1 %}{%- endblock %} + +# No bottom relbar. +{%- block relbar2 %}{%- endblock %} diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/searchbox.html b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/searchbox.html new file mode 100644 index 000000000..55a972156 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/searchbox.html @@ -0,0 +1,12 @@ +{%- if pagename != "search" %} + + +{%- endif %} diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_header.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_header.png new file mode 100644 index 000000000..843e7e2c5 Binary files /dev/null and b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_header.png differ diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_topo.jpg b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_topo.jpg new file mode 100644 index 000000000..4229ae8db Binary files /dev/null and b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_topo.jpg differ diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/fakebar.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/fakebar.png new file mode 100644 index 000000000..b45830e00 Binary files /dev/null and b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/fakebar.png differ diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_indt.jpg b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_indt.jpg new file mode 100644 index 000000000..2a1fbe7a1 Binary files /dev/null and b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_indt.jpg differ diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_openbossa.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_openbossa.png new file mode 100644 index 000000000..51e868d6e Binary files /dev/null and b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_openbossa.png differ diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_python.jpg b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_python.jpg new file mode 100644 index 000000000..cd474efba Binary files /dev/null and b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_python.jpg differ diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_qt.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_qt.png new file mode 100644 index 000000000..37800f454 Binary files /dev/null and b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_qt.png differ diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidedocs.css b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidedocs.css new file mode 100644 index 000000000..fd81f4379 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidedocs.css @@ -0,0 +1,409 @@ +* { + font: 100% Verdana, Arial, Helvetica, sans-serif; + font-size:12px; +} + +html { + height: 100%; +} + +body { + margin: 0; + padding: 0; + text-align: center; + background-color: #EBEBEB; + height: 100%; + color: #333; +} + +strong { + font-weight:bold; +} + +.document { + padding-bottom: 90px; +} + +#container { + position: relative; + min-height: 100%; + background-image: url(fakebar.png); + background-repeat: repeat-y; + background-color: white; +} + +.footer { + position: absolute; + bottom: 0px; + margin-top: 50px; + text-align:center; + background-color: white; + border-top: 2px solid #e0e0e0; + white-space: nowrap; + height: 90px; + width: 100%; +} + +.footer img { + margin-left: 8px; + margin-right: 8px; +} + +.sphinxsidebar { + float: left; + width: 250px; + padding: 0px 10px 0px 10px; + text-align: left; +} + +.sphinxsidebar ul { + padding: 0px; + margin: 0px; + list-style-position: inside; +} + +.sphinxsidebar > ul { + padding: 0px; + margin: 0px; +} + +.sphinxsidebar ul li { + margin-left: 10px; + padding: 0px; +} + +.sphinxsidebar h3, .sphinxsidebar h3 a { + font-weight: bold; + color: #333; +} + +.documentwrapper { + margin-left: 270px; + text-align: left; + background-color: #ffffff; + border-left: 1px solid #989898; + font-size:18px; + padding: 10px 50px 15px 50px; + height: 100%; +} + +h1 { + font-size:18px; + padding-left: 50px; + padding-bottom: 15px; + padding-top: 15px; + border-bottom: 1px solid #c2c2c2; + text-transform:uppercase; + margin-right: -100px; + position: relative; + left: -50px; + top: -10px; +} + +h2 { + font-size:12px; + font-weight:bold; + border-left-width: 1px; + border-right-width: 1px; + border-top-width: 1px; + border-bottom-width: 2px; + border-style: solid; + border-left-color: #b1b1b1; + border-right-color: #b1b1b1; + border-top-color: #b1b1b1; + border-bottom-color: #009491; + background-color: #e0e0e0; + padding:5px; + margin-top: 20px; + -moz-border-radius:5px; + -webkit-border-radius:5px; + -khtml-border-radius:5px; +} + +h3, h4 { + font-weight: bolder; +} + +pre { + border-top: 1px solid #e0e0e0; + border-bottom: 1px solid #e0e0e0; + background-color: #fafafa; + padding: 5px; + font: 100% monospace; + overflow: auto; +} + +pre * { + font: 100% monospace; +} + +.headerlink { + font-size: 100%; + color: inherit; + float: right; + visibility: Hidden; +} + +h1 .headerlink { + padding-right: 50px; +} + +h1:hover .headerlink, h2:hover .headerlink, h3:hover .headerlink { + visibility: Visible; +} + +a, a:visited { + color: #009491; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +div.note { + border: 1px solid #e3e3e3; +} + +table.docutils { + margin-left: auto; + margin-right: auto; + margin-bottom: 10px; + border: none; +} + +table.docutils td { + border: none; +} + +table.docutils th { + border: none; + font-weight: bold; + vertical-align: top; +} + +h2 em { + float: right; + font-size: 10px; + position: relative; + top: -20px; +} + +/* Table of pymaemo components */ + +#development table.docutils td { + border-bottom: 1px solid #EBEBEB; +} + +#development th { + background-color: #EBEBEB; + color: #FC7E00; + padding: 5px; +} + +#development th:first-child { + -moz-border-radius: 20px 0px 0px 0px; + -webkit-border-radius: 20px 0px 0px 0px; + -khtml-border-radius: 20px 0px 0px 0px; + padding-left: 10px; +} +#development th:last-child { + -moz-border-radius: 0px 20px 0px 0px; + -webkit-border-radius: 0px 20px 0px 0px; + -khtml-border-radius: 0px 20px 0px 0px; + padding-right: 10px; + width: 100px; +} + +hr { + border: none; + border-bottom: 1px dashed #EBEBEB; + width: 70% +} + +.oldnews { + text-align: right; +} + +/******************* TOPO *****************************/ +.header { + background-image: url(bg_topo.jpg); + background-repeat: repeat-x; + height: 147px; +} + +.header_container { + background-image: url(bg_header.png); + background-repeat: no-repeat; + background-position: 100px 0px; +} + +.logo { + text-align: left; + margin-bottom: 10px; +} + +#searchbox { + border-top: 1px solid #989898; + padding-top: 10px; + margin-left: -10px; + margin-right: -10px; + padding-left: 10px; + padding-right: 10px; +} + +#search_button { + border: 1px solid #3A393A; + background-color: #3A393A; + color: white; + cursor: pointer; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -khtml-border-radius: 5px; + +} + +form { + margin: 0px; + padding: 0px; +} + +/* search field */ +form #q { + width: 136px; +/* height: 22px; */ + border: none; + margin: 0px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -khtml-border-radius: 5px; + margin-top: 2px; + padding: 4px; + line-height: 22px +} + +#search-results h2 { + display: none; +} + +#search-results h2 { + display: none; +} + +#search-results ul.search { + margin: 0px; + padding: 0px; +} + +ul.search div.context { + padding-left: 40px; +} + +#installation td { + text-align: center; + font-weight: bold; +} + +em { + color: inherit; + font-style:italic; +} + +/******** REL bar *********/ + +.related { + display: inline; +} + +.related ul { + padding: 0px 0px 0px 10px; + margin: 0px; + text-align: left; + background-image: url(relbar_bg.png); +} + +.related li { + display: inline; + color: white; + font-weight: bold; +} + +.related li a { + color: inherit; + line-height: 35px; + font-weight: bold; + vertical-align: middle; +} + +.related li.right { + float: right; + margin-right: 5px; +} + +.related h3 { + display: none; +} + +.align-center { + text-align: center; +} + +.contentstable { + width: 100%; +} + +.contentstable td { + padding-left: 30px; + vertical-align: top; +} + +p.biglink a { + font-size: 20px; +} + +dt:target, .highlight { + background-color: #fbe54e; +} + +img { + border: 0px; +} + +.figure .caption { + font-style:italic; +} + +table.footnote { + margin: 0px; +} diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidelogo.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidelogo.png new file mode 100644 index 000000000..076c1057c Binary files /dev/null and b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidelogo.png differ diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/relbar_bg.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/relbar_bg.png new file mode 100644 index 000000000..4036733a7 Binary files /dev/null and b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/relbar_bg.png differ diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/theme.conf b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/theme.conf new file mode 100644 index 000000000..e0a652a5d --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/theme.conf @@ -0,0 +1,7 @@ +[theme] +inherit = default +stylesheet = pysidedocs.css +pygments_style = none + +[options] +nosidebar = false diff --git a/sources/shiboken2/ApiExtractor/doc/conf.py.in b/sources/shiboken2/ApiExtractor/doc/conf.py.in new file mode 100644 index 000000000..70750c899 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/conf.py.in @@ -0,0 +1,163 @@ +# -*- coding: utf-8 -*- +# +# ApiExtractor documentation build configuration file, created by +# sphinx-quickstart on Wed Apr 22 15:04:20 2009. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.append(os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.refcounting', 'sphinx.ext.coverage'] + +rst_epilog = """ +.. |project| replace:: API Extractor +""" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +source_encoding = 'utf-8' + +# The master toctree document. +#master_doc = 'contents' + +# General information about the project. +project = u'API Extractor' +copyright = u'2009-2010, Nokia Corporation' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '@apiextractor_MAJOR_VERSION@.@apiextractor_MINOR_VERSION@' +# The full version, including alpha/beta/rc tags. +release = '@apiextractor_VERSION@' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'pysidedocs' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = { +#} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_themes'] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# 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 = { '' : ''} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +html_additional_pages = { 'index' : 'index.html'} + +# If false, no index is generated. +html_use_index = False + +# If true, the index is split into individual pages for each letter. +html_split_index = False + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = False + +html_add_permalinks = True; + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + diff --git a/sources/shiboken2/ApiExtractor/doc/contents.rst b/sources/shiboken2/ApiExtractor/doc/contents.rst new file mode 100644 index 000000000..83a4889fe --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/contents.rst @@ -0,0 +1,9 @@ +Table of contents +***************** +.. toctree:: + :numbered: + :maxdepth: 3 + + overview.rst + ownership.rst + typesystem.rst diff --git a/sources/shiboken2/ApiExtractor/doc/dependency-apiextractor.svg b/sources/shiboken2/ApiExtractor/doc/dependency-apiextractor.svg new file mode 100644 index 000000000..6bec8b5a8 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/dependency-apiextractor.svg @@ -0,0 +1,360 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + Boost + Qt Software + INdT/Nokia + + + + + + + + Qt 4.5 + 4.5 + headers and libraries - compile-time and run-time + GNU General Public License v3 /GNU Lesser General Public Licence v2.1 + + + + libapiextractor + 0.2 + headers and libraries - compile-time and run-time + LGPL version 2.1 + + + + boost::graph + 1.38.0 + headers and libraries - compile-time and run-time + Boost Software License 1.0 + + + diff --git a/sources/shiboken2/ApiExtractor/doc/overview.rst b/sources/shiboken2/ApiExtractor/doc/overview.rst new file mode 100644 index 000000000..471e2439b --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/overview.rst @@ -0,0 +1,15 @@ +.. _gen-overview: + +********************** +API Extractor Overview +********************** + +The **API Extractor** library is used by the binding generator to parse headers +of a given library and merge this data with information provided by +typesystem (XML) files, resulting in a representation of how the API should be +exported to the chosen target language. The generation of source code for the +bindings is performed by specific generators using the API Extractor library. + +The API Extractor is based on QtScriptGenerator_ codebase. + +.. _QtScriptGenerator: http://labs.trolltech.com/page/Projects/QtScript/Generator diff --git a/sources/shiboken2/ApiExtractor/doc/ownership.rst b/sources/shiboken2/ApiExtractor/doc/ownership.rst new file mode 100644 index 000000000..760967da6 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/ownership.rst @@ -0,0 +1,85 @@ +Ownership Management +******************** + +Among the various types of instances interactions, sometimes an object +may be *owned* by another object, so that the owner is responsible for +destroying the owned object, like in Qt's object system [#]_. +This kind of relationship has a big role on interfacing with the target language, like +with Python's reference counting. + + +Ownership transfers +------------------- + +From C++ to target +^^^^^^^^^^^^^^^^^^ + + When an object that is currently owned by C++ has its ownership transfered + back to the target language, the binding can know for sure when the object will be deleted and + tie the C++ instance existence to the wrapper, calling the C++ destructor normally when the + wrapper is deleted. + + .. code-block:: xml + + + + + + +From target to C++ +^^^^^^^^^^^^^^^^^^ + + In the opposite direction,when an object ownership is transfered from the target language + to C++, the native code takes full control of the object life and you don't + know when that object will be deleted, rendering the wrapper object invalid, + unless you're wrapping an object with a virtual destructor, + so you can override it and be notified of its destruction. + + By default it's safer to just render the wrapper + object invalid and raise some error if the user tries to access + one of this objects members or pass it as argument to some function, to avoid unpleasant segfaults. + Also you should avoid calling the C++ destructor when deleting the wrapper. + + .. code-block:: xml + + + + + + +Parent-child relationship +------------------------- + +One special type of relationship is the parent-child. When an object is called +the parent of another object (the child), the former is in charge of deleting its +child when deleted and the target language can trust that the child will be alive +as long as the parent is, unless some other method can take the C++ ownership away from the parent. + +One of the main uses of this scheme is Qt's object system, with ownership among QObject-derived +classes, creating "trees" of instances. + + .. code-block:: xml + + + + + +In this example, the instance with the method that is being invoked (indicated by 'index="this"' on +modify-argument) will be marked as a child +of the first argument using the `parent` tag. To remove ownership, just use "remove" in the action attribute. **Removing +parentship also transfers the ownership back to python.** + +Invalidation after use +---------------------- + +Sometimes an object is created as a virtual method call argument and destroyed after the +call returned. In this case, you should use the ``invalidate-after-use`` attribute in the +``modify-argument`` tag to mark the wrapper as invalid right after the virtual method returns. + + .. code-block:: xml + + + +In this example the second argument will be invalidated after this method call. + +.. [#] See *Object Trees and Object Ownership* http://doc.trolltech.com/4.5/objecttrees.html diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem.rst b/sources/shiboken2/ApiExtractor/doc/typesystem.rst new file mode 100644 index 000000000..69dda43a0 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/typesystem.rst @@ -0,0 +1,29 @@ +The API Extractor Type System +***************************** + +The typesystem is used by a binding generator or any other software using the APIExtractor library +to map a C++ library API onto a higher level language. + +The typesystem specification is a handwritten XML document listing the types +that will be available in the generated target language API; types that are not +declared in the specification will be ignored along with everything depending on +them. In addition, it is possible to manipulate and modify types and functions. +It is even possible to use the typesystem specification to inject arbitrary +code into the source files, such as an extra member function. + +Below there is a complete reference guide to the various nodes (XML tags) of the typesystem. +For usage examples, take a look at the typesystem files used to generate PySide. These files +can be found in the PySide/ directory of the PySide package. + +.. toctree:: + + typesystem_specifying_types + typesystem_manipulating_objects + typesystem_modify_function + typesystem_arguments + typesystem_solving_compilation + typesystem_templates + typesystem_conversionrule + typesystem_documentation + + diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_arguments.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_arguments.rst new file mode 100644 index 000000000..16e0678d3 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_arguments.rst @@ -0,0 +1,192 @@ +.. _modifying-arguments: + +Modifying Arguments +------------------- + +.. _conversion-rule: + +conversion-rule +^^^^^^^^^^^^^^^ + + The conversion-rule node allows you to write customized code to convert + the given argument between the target language and C++, and it is a child of the modify-argument node. + + .. code-block:: xml + + + + // the code + + + + This node is typically used in combination with the replace-type and + remove-argument nodes. The given code is used instead of the generator's + conversion code. + + Writing %N in the code (where N is a number), will insert the name of the + nth argument. Alternatively, %in and %out which will be replaced with the + name of the conversion's input and output variable, respectively. Note the + output variable must be declared explicitly, for example: + + .. code-block:: xml + + + bool %out = (bool) %in; + + + .. note:: You can also use the conversion-rule node to specify :ref:`a conversion code which will be used instead of the generator's conversion code everywhere for a given type `. + +remove-argument +^^^^^^^^^^^^^^^ + + The remove-argument node removes the given argument from the function's + signature, and it is a child of the modify-argument node. + + .. code-block:: xml + + + + + +rename to +^^^^^^^^^ + + The 'rename to' node is used to rename a argument and use this new name in the generated code. + + .. code-block:: xml + + + + + + +remove-default-expression +^^^^^^^^^^^^^^^^^^^^^^^^^ + + The remove-default-expression node disables the use of the default expression + for the given argument, and it is a child of the modify-argument node. + + .. code-block:: xml + + + + + +replace-default-expression +^^^^^^^^^^^^^^^^^^^^^^^^^^ + + The replace-default-expression node replaces the specified argument with the + expression specified by the ``with`` attribute, and it is a child of the + modify-argument node. + + .. code-block:: xml + + + + + + +replace-type +^^^^^^^^^^^^ + + The replace-type node replaces the type of the given argument to the one + specified by the ``modified-type`` attribute, and it is a child of the + modify-argument node. + + .. code-block:: xml + + + + + + If the new type is a class, the ``modified-type`` attribute must be set to + the fully qualified name (including name of the package as well as the class + name). + +define-ownership +^^^^^^^^^^^^^^^^ + + The define-ownership tag indicates that the function changes the ownership + rules of the argument object. The ``class`` attribute specifies the class of + function where to inject the ownership altering code. The ``owner`` attribute + specifies the new ownership of the object. It accepts the following values: + + * target: the target language will assume full ownership of the object. + The native resources will be deleted when the target language + object is finalized. + * c++: The native code assumes full ownership of the object. The target + language object will not be garbage collected. + * default: The object will get default ownership, depending on how it + was created. + + .. code-block:: xml + + + + + + +reference-count +^^^^^^^^^^^^^^^ + + The reference-count tag dictates how an argument should be handled by the + target language reference counting system (if there is any), it also indicates + the kind of relationship the class owning the function being modified has with + the argument. For instance, in a model/view relation a view receiving a model + as argument for a **setModel** method should increment the model's reference + counting, since the model should be kept alive as much as the view lives. + Remember that out hypothetical view could not become parent of the model, + since the said model could be used by other views as well. + The ``action`` attribute specifies what should be done to the argument + reference counting when the modified method is called. It accepts the + following values: + + * add: increments the argument reference counter. + * add-all: increments the reference counter for each item in a collection. + * remove: decrements the argument reference counter. + * set: will assign the argument to the variable containing the reference. + * ignore: does nothing with the argument reference counter + (sounds worthless, but could be used in situations + where the reference counter increase is mandatory + by default). + + .. code-block:: xml + + + + + + + The variable-name attribute specifies the name used for the variable that + holds the reference(s). + + +replace-value +^^^^^^^^^^^^^ + + The ``replace-value`` attribute lets you replace the return statement of a + function with a fixed string. This attribute can only be used for the + argument at ``index`` 0, which is always the function's return value. + + .. code-block:: xml + + + + +parent +^^^^^^ + + The parent node lets you define the argument parent which will + take ownership of argument and will destroy the C++ child object when the + parent is destroyed. + + .. code-block:: xml + + + + + + In the ``index`` argument you must specify the parent argument. The action + *add* creates a parent link between objects, while *remove* will undo the + parentage relationship. diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_conversionrule.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_conversionrule.rst new file mode 100644 index 000000000..c62d5bbf6 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_conversionrule.rst @@ -0,0 +1,113 @@ +.. _conversion-rule-tag: + +Conversion Rule Tag +------------------- + +.. _conversion-rule: + +conversion-rule +^^^^^^^^^^^^^^^ + + The **conversion-rule** tag specifies how a **primitive-type**, a **container-type**, + or a **value-type** may be converted to and from the native C++ language types to the + target language types. + + .. code-block:: xml + + + + + // Code to convert a native value to a target language object. + + + + // Code to convert target language type object of type TARGETTYPEA + // to the C++ native type represented by the value/primitive/container-type. + + + // Code to convert target language type object of type TARGETTYPEB + // to the C++ native type represented by the value/primitive/container-type. + + + + + + The example above show the structure of a complete conversion rule. Each of the + child tags comprising the conversion rule are described in their own sections + below. + + +.. _native-to-target: + +native-to-target +^^^^^^^^^^^^^^^^ + + The **native-to-target** tag tells how to convert a native C++ value to its + target language equivalent. The text inside the tag is a C++ code the takes + an input value an does what's needed to convert it to the output value. + ``insert-template`` tags may be used to insert commonly repeating code. + + .. code-block:: xml + + + + // Code to convert a native value to a target language object. + + + + Use the replace node to modify the template code. + Notice that the generator must provide type system variables for the input + and output values and types, namely **%in**, **%out**, **%INTYPE** and + **%OUTTYPE**. In the case of container types, **%INTYPE** refers to the + full container type (e.g. **"list"**) and **%INTYPE_0**, **%INTYPE_1**, + **%INTYPE_#**, should be replaced by the types used in the container template + (e.g. **%INTYPE_0** correspondes to **"int"** for **"list"**). + + +.. _target-to-native: + +target-to-native +^^^^^^^^^^^^^^^^ + + The **target-to-native** tag encloses at least one, but usually many, conversions + from target language values to C++ native values. The *optional* attribute + ``replace`` tells if the target language to C++ conversions will be added to, or if + they will replace the implicit conversions collected by *ApiExtractor*. The default + value for it is *yes*. + + + .. code-block:: xml + + + \ + // List of target to native conversions meant to replace or expand + // the already existing implicit conversions. + + + + +.. _add-conversion: + +add-conversion +^^^^^^^^^^^^^^ + + Each **add-conversion** tag adds a rule for conversion of a target language type, + indicated by the ``type`` attribute, to the C++ native type represented by the + **primitive-type**, a **container-type**, or **value-type**, to which the parent + **conversion-rule** belongs. + + .. code-block:: xml + + + + // Code to convert target language type object of type TARGETTYPE_A + // to the C++ native type represented by the value/primitive/container-type. + + + + The ``check`` attribute tells how a target value should be checked to see if it belongs to + the type expected. This attribute is *optional*, for it can be derived from the ``type`` + attribute, but it isn't unusual that some special check is needed. The variables + **%in**, **%out**, **%INTYPE**, **%INTYPE_#**, and **%OUTTYPE**, must be provided by + the generator as in the ``native-to-target`` tag. + diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_documentation.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_documentation.rst new file mode 100644 index 000000000..43f72a1ba --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_documentation.rst @@ -0,0 +1,43 @@ +Manipulating Documentation +-------------------------- + +inject-documentation +^^^^^^^^^^^^^^^^^^^^ + + The inject-documentation node inserts the documentation into the generated + documentation. This node is a child of the object-type, value-type and + modify-function nodes. + + .. code-block:: xml + + + + // the documentation + + + + The **mode** attribute default value is *replace*. + + The **format** attribute specifies when the documentation injection will + occur and it accepts the following values: + + * native: Before XML<->Backend transformation occur, so the injected code *must* be a valid XML. + * target: After XML<->Backend transformation occur, so the injected code *must* be a valid backend format. + + At the moment the only supported backend is Sphinx. + +modify-documentation +^^^^^^^^^^^^^^^^^^^^ + + The modify-documentation node allows you to change the auto-generated + documentation. API Extractor transforms XML's from qdoc3 (the Qt documentation + tool) into .rst files to be processed later using Sphinx. So you can modify + the XML before the transformation occur. + + .. code-block:: xml + + + + + + The **xpath** attribute is the XPath to the node that you want to modify. diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst new file mode 100644 index 000000000..2838c95e1 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst @@ -0,0 +1,132 @@ +.. _manipulating-object-and-value-types: + +Manipulating Object and Value Types +----------------------------------- + +.. _inject-code: + +inject-code +^^^^^^^^^^^ + The inject-code node inserts the given code into the generated code for the + given type or function, and it is a child of the :ref:`object-type`, :ref:`value-type`, + :ref:`modify-function` and :ref:`add-function` nodes. + + .. code-block:: xml + + + + // the code + + + + 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: + + * native: The c++ code + * target: The binding code + * target-declaration: The code will be injected into the generated header + file containing the c++ wrapper class definition. + + If the ``position`` attribute is set to *beginning* (the default), the code + is inserted at the beginning of the function. If it is set to *end*, the code + is inserted at the end of the function. + + The ``since`` attribute specify the API version where this code was injected. + +modify-field +^^^^^^^^^^^^ + + The modify-field node allows you to alter the access privileges for a given + C++ field when mapping it onto the target language, and it is a child of an + :ref:`object-type` or a :ref:`value-type` node. + + .. code-block:: xml + + + + + + The ``name`` attribute is the name of the field, the *optional* ``write`` + and ``read`` attributes specify the field's access privileges in the target + language API (both are set to true by default). + The ``remove`` attribute is an *optional* attribute, which can mark the field + to be discarded on generation; it has the same purpose of the deprecated tag + :ref:`remove`. + +.. _modify-function: + +modify-function +^^^^^^^^^^^^^^^ + + The modify-function node allows you to modify a given C++ function when mapping + it onto the target language, and it is a child of an :ref:`object-type` or a :ref:`value-type` + node. Use the :ref:`modify-argument` node to specify which argument the modification + affects. + + .. code-block:: xml + + + + + + The ``signature`` attribute is a normalized C++ signature, excluding return + values but including potential const declarations. + + The ``since`` attribute specify the API version when this function was modified. + + 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`. + +.. _add-function: + +add-function +^^^^^^^^^^^^ + + The add-function node allows you to add a given function onto the target language, + and it is a child of an :ref:`object-type` or :ref:`value-type` nodes if the + function is suposed to be a method, or :ref:`namespace` and :ref:`typesystem` if + the function is suposed to be a function inside a namespace or a global function. + + Typically when adding a function some code must be injected to provide the function + logic. This can be done using the :ref:`inject-code` node. + + .. code-block:: xml + + + + + + The ``return-type`` attribute defaults to *void*, the ``access`` to *public* and the ``static`` one to *no*. + + The ``since`` attribute specify the API version when this function was added. + +.. _conversion-rule-on-types: + +conversion-rule +^^^^^^^^^^^^^^^ + + The conversion-rule node allows you to write customized code to convert the given argument between the target + language and C++, and is a child of the :ref:`value-type`, :ref:`object-type`, :ref:`primitive-type` and + :ref:`container-type` nodes. + + The code pointed by the file attribute is very tied to the generator using APIExtractor, so it don't follow any + rules, but the generator rules.. + + .. code-block:: xml + + + + + + The ``since`` attribute specify the API version when this conversion rule became valid. + + .. 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 `. + diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_modify_function.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_modify_function.rst new file mode 100644 index 000000000..071cea4f5 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_modify_function.rst @@ -0,0 +1,78 @@ +.. _modifying-functions: + +Modifying Functions +------------------- + +.. _modify-argument: + +modify-argument +^^^^^^^^^^^^^^^ + + The modify-argument node specifies which of the given function's arguments the + modification affects, and is a child of the modify-function node. Use the + remove-argument, replace-default-expression, remove-default-expression, + replace-type, reference-count and define-ownership nodes to specify the details + of the modification. + + .. code-block:: xml + + + + // modifications + + + + Set the ``index`` attribute to "1" for the first argument, "2" for the second + one and so on. Alternatively, set it to "return" or "this" if you want to + modify the function's return value or the object the function is called upon, + respectively. + +.. _remove: + +remove +^^^^^^ + + The remove node removes the given method from the generated target language + API, and it is a child of the modify-function node. + + .. code-block:: xml + + + + + + .. warning:: This tag is deprecated, use the ``remove`` attribute from :ref:`modify-function` tag instead. + +.. _access: + +access +^^^^^^ + + The access node changes the access privileges of the given function in the + generated target language API, and it is a child of the modify-function node. + + .. code-block:: xml + + + + + + .. warning:: This tag is deprecated, use the ``access`` attribute from :ref:`modify-function` tag instead. + +.. _rename: + +rename +^^^^^^ + + The rename node changes the name of the given function in the generated target + language API, and it is a child of the modify-function node. + + .. code-block:: xml + + + + + + The ``to`` attribute is the new name of the function. + + .. warning:: This tag is deprecated, use the ``rename`` attribute from :ref:`modify-function` tag instead. diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_solving_compilation.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_solving_compilation.rst new file mode 100644 index 000000000..81d14a187 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_solving_compilation.rst @@ -0,0 +1,70 @@ +Solving compilation problems +---------------------------- + +suppress-warning +^^^^^^^^^^^^^^^^ + + The generator will generate several warnings which may be irrelevant to the + user. The suppress-warning node suppresses the specified warning, and it is + a child of the typesystem node. + + .. code-block:: xml + + + + + + The **text** attribute is the warning text to suppress, and may contain the * + wildcard (use "" to escape regular expression matching if the warning contain + a regular "*"). + +extra-includes +^^^^^^^^^^^^^^ + + The extra-includes node contains declarations of additional include files, + and it can be a child of the interface-type, namespace-type, value-type and + object-type nodes. + + The generator automatically tries to read the global header for each type but + sometimes it is required to include extra files in the generated C++ code to + make sure that the code compiles. These files must be listed using include + nodes witin the extra-include node: + + .. code-block:: xml + + + + + + + + The **file-name** attribute is the file to include, such as "QStringList". + The **location** attribute is where the file is located: *global* means that + the file is located in $INCLUDEPATH and will be included using #include <...>, + *local* means that the file is in a local directory and will be included + using #include "...". + + +include +^^^^^^^ + + The include node specifies the name and location of a file that must be + included, and it is a child of the interface-type, namespace-type, value-type, + object-type or extra-includes nodes + + The generator automatically tries to read the global header for each type. Use + the include node to override this behavior, providing an alternative file. The + include node can also be used to specify extra include files. + + .. code-block:: xml + + + + + + The **file-name** attribute is the file to include, such as "QStringList". + The **location** attribute is where the file is located: *global* means that + the file is located in $INCLUDEPATH and will be included using #include <...>, + *local* means that the file is in a local directory and will be included + using #include "...". diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst new file mode 100644 index 000000000..0d24a6d52 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst @@ -0,0 +1,371 @@ +Specifying Types +---------------- + +.. _typesystem: + +typesystem +^^^^^^^^^^ + + This is the root node containing all the type system information. It can + have a number of attributes, described below. + + .. code-block:: xml + + + + + The **package** attribute is a string describing the package to be used, + e.g. "QtCore". + The *optional* **default-superclass** attribute is the canonical C++ base class + name of all objects, e.g., "object". + +load-typesystem +^^^^^^^^^^^^^^^ + + The load-typesystem node specifies which type systems to load when mapping + multiple libraries to another language or basing one library on another, and + it is a child of the typesystem node. + + .. code-block:: xml + + + + + + The **name** attribute is the filename of the typesystem to load, the + **generate** attribute specifies whether code should be generated or not. The + later must be specified when basing one library on another, making the generator + able to understand inheritance hierarchies, primitive mapping, parameter types + in functions, etc. + + Most libraries will be based on both the QtCore and QtGui modules, in which + case code generation for these libraries will be disabled. + + +rejection +^^^^^^^^^ + + The rejection node rejects the given class, or the specified function or + field, and it is a child of the typesystem node. + + .. code-block:: xml + + + + + + The **class** attribute is the C++ class name of the class to reject. Use the + *optional* **function-name** or **field-name** attributes to reject a particular + function or field. Note that the **field-name** and **function-name** cannot + be specified at the same time. To remove all occurrences of a given field or + function, set the class attribute to \*. + +.. _primitive-type: + +primitive-type +^^^^^^^^^^^^^^ + + The primitive-type node describes how a primitive type is mapped from C++ to + the target language, and is a child of the typesystem node. Note that most + primitives are already specified in the QtCore typesystem. + + .. code-block:: xml + + + + + + The **name** attribute is the name of the primitive in C++, the optional, + **target-name** attribute is the name of the primitive type in the target + language. If the later two attributes are not specified their default value + will be the same as the **name** attribute. + + The *optional* **since** value is used to specify the API version of this type. + + If the *optional* **preferred-conversion** attribute is set to *no*, it + indicates that this version of the primitive type is not the preferred C++ + equivalent of the target language type. For example, in Python both "qint64" + and "long long" become "long" but we should prefer the "qint64" version. For + this reason we mark "long long" with preferred-conversion="no". + + The *optional* **default-constructor** specifies the minimal constructor + call to build one value of the primitive-type. This is not needed when the + primitive-type may be built with a default constructor (the one without + arguments). + + The *optional* **preferred-conversion** attribute tells how to build a default + instance of the primitive type. It should be a constructor call capable of + creating a instance of the primitive type. Example: a class "Foo" could have + a **preferred-conversion** value set to "Foo()". Usually this attribute is + used only for classes declared as primitive types and not for primitive C++ + types, but that depends on the application using *ApiExtractor*. + + +.. _namespace: + +namespace-type +^^^^^^^^^^^^^^ + + The namespace-type node maps the given C++ namespace to the target language, + and it is a child of the typesystem node. Note that within namespaces, the + generator only supports enums (i.e., no functions or classes). + + .. code-block:: xml + + + + + + The **name** attribute is the name of the namespace, e.g., "Qt". + + The *optional* **generate** attribute is used to inform if you need to prepend + the given namespace into each generated class. Its default value is **yes**. + + The **package** attribute can be used to override the package of the type system. + + The *optional* **since** value is used to specify the API version of this type. + + The **revision** attribute can be used to specify a revision for each type, easing the + production of ABI compatible bindings. + +enum-type +^^^^^^^^^ + + The enum-type node maps the given enum from C++ to the target language, + and it is a child of the typesystem node. Use the reject-enum-value to + reject values. + + .. code-block:: xml + + + + + + The **name** attribute is the fully qualified C++ name of the enum + (e.g.,"Qt::FillRule"). If the *optional* **flags** attribute is set to *yes* + (the default is *no*), the generator will expect an existing QFlags for the + given enum type. The **lower-bound** and **upper-bound** attributes are used + to specify runtime bounds checking for the enum value. The value must be a + compilable target language statement, such as "QGradient.Spread.PadSpread" + (taking again Python as an example). If the **force-integer** attribute is + set to *yes* (the default is *no*), the generated target language code will + use the target language integers instead of enums. And finally, the + **extensible** attribute specifies whether the given enum can be extended + with user values (the default is *no*). + + The *optional* **since** value is used to specify the API version of this type. + + The attribute **identified-by-value** helps to specify anonymous enums using the + name of one of their values, which is unique for the anonymous enum scope. + Notice that the **enum-type** tag can either have **name** or **identified-by-value** + but not both. + + The **revision** attribute can be used to specify a revision for each type, easing the + production of ABI compatible bindings. + + The **flags-revision** attribute has the same purposes of **revision** attribute but + is used for the QFlag related to this enum. + + +reject-enum-value +^^^^^^^^^^^^^^^^^ + + The reject-enum-value node rejects the enum value specified by the **name** + attribute, and it is a child of the enum-type node. + + .. code-block:: xml + + + + + + This node is used when a C++ enum implementation has several identical numeric + values, some of which are typically obsolete. + +.. _value-type: + +value-type +^^^^^^^^^^ + + The value-type node indicates that the given C++ type is mapped onto the target + language as a value type. This means that it is an object passed by value on C++, + i.e. it is stored in the function call stack. It is a child of the :ref:`typesystem` node. + + .. code-block:: xml + + + + + + The **name** attribute is the fully qualified C++ class name, such as + "QMatrix" or "QPainterPath::Element". The **copyable** attribute is used to + force or not specify if this type is copyable. The *optional* **hash-function** + attribute informs the function name of a hash function for the type. + + The *optional* attribute **stream** specifies whether this type will be able to + use externally defined operators, like QDataStream << and >>. If equals to **yes**, + these operators will be called as normal methods within the current class. + + The *optional* **since** value is used to specify the API version of this type. + + The *optional* **default-constructor** specifies the minimal constructor + call to build one instance of the value-type. This is not needed when the + value-type may be built with a default constructor (the one without arguments). + Usually a code generator may guess a minimal constructor for a value-type based + on its constructor signatures, thus **default-constructor** is used only in + very odd cases. + + The **revision** attribute can be used to specify a revision for each type, easing the + production of ABI compatible bindings. + +.. _object-type: + +object-type +^^^^^^^^^^^ + + The object-type node indicates that the given C++ type is mapped onto the target + language as an object type. This means that it is an object passed by pointer on + C++ and it is stored on the heap. It is a child of the :ref:`typesystem` node. + + .. code-block:: xml + + + + + + The **name** attribute is the fully qualified C++ class name. If there is no + C++ base class, the default-superclass attribute can be used to specify a + superclass for the given type, in the generated target language API. The + **copyable** and **hash-function** attributes are the same as described for + :ref:`value-type`. + + The *optional* attribute **stream** specifies whether this type will be able to + use externally defined operators, like QDataStream << and >>. If equals to **yes**, + these operators will be called as normal methods within the current class. + + The *optional* **since** value is used to specify the API version of this type. + + The **revision** attribute can be used to specify a revision for each type, easing the + production of ABI compatible bindings. + +interface-type +^^^^^^^^^^^^^^ + + The interface-type node indicates that the given class is replaced by an + interface pattern when mapping from C++ to the target language. Using the + interface-type node implicitly makes the given type an :ref:`object-type`. + + .. code-block:: xml + + + + + + The **name** attribute is the fully qualified C++ class name. The *optional* + **package** attribute can be used to override the package of the type system. + If there is no C++ base class, the *optional* **default-superclass** attribute + can be used to specify a superclass in the generated target language API, for + the given class. + + The *optional* **since** value is used to specify the API version of this interface. + + The **revision** attribute can be used to specify a revision for each type, easing the + production of ABI compatible bindings. + +.. _container-type: + +container-type +^^^^^^^^^^^^^^ + + The container-type node indicates that the given class is a container and + must be handled using one of the conversion helpers provided by attribute **type**. + + .. code-block:: xml + + + + + + The **name** attribute is the fully qualified C++ class name. The **type** + attribute is used to indicate what conversion rule will be applied to the + container. It can be: *list*, *string-list*, *linked-list*, *vector*, *stack*, + *queue*, *set*, *map*, *multi-map*, *hash*, *multi-hash* or *pair*. + + The *optional* **since** value is used to specify the API version of this container. + + +.. _custom-type: + +custom-type +^^^^^^^^^^^ + + The custom-type node simply makes the parser aware of the existence of a target + language type, thus avoiding errors when trying to find a type used in function + signatures and other places. The proper handling of the custom type is meant to + be done by a generator using the APIExractor. + + .. code-block:: xml + + + + + + The **name** attribute is the name of the custom type, e.g., "PyObject". + + +.. _function: + +function +^^^^^^^^ + + The function node indicates that the given C++ global function is mapped onto + the target language. + + .. code-block:: xml + + + + + + This tag has some limitations, it doesn't support function modifications, besides you + can't add a function overload using :ref:`add-function` tag to an existent function. + These limitation will be addressed in future versions of ApiExtractor. + + The function tag has two *optional* attributes: **since**, whose value is used to specify + the API version of this function, and **rename**, to modify the function name. + diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_templates.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_templates.rst new file mode 100644 index 000000000..31b155c5a --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_templates.rst @@ -0,0 +1,55 @@ +.. _using-code-templates: + +Using Code Templates +-------------------- + +template +^^^^^^^^ + + The template node registers a template that can be used to avoid duplicate + code when extending the generated code, and it is a child of the typesystem + node. + + .. code-block:: xml + + + + + + Use the insert-template node to insert the template code (identified by the + template's ``name`` attribute) into the generated code base. + + +insert-template +^^^^^^^^^^^^^^^ + + The insert-template node includes the code template identified by the name + attribute, and it can be a child of the inject-code, conversion-rule, template, + custom-constructor and custom-destructor nodes. + + .. code-block:: xml + + + + + + Use the replace node to modify the template code. + + +replace +^^^^^^^ + + The replace node allows you to modify template code before inserting it into + the generated code, and it can be a child of the insert-template node. + + .. code-block:: xml + + + + + + This node will replace the attribute ``from`` with the value pointed by + ``to``. + diff --git a/sources/shiboken2/ApiExtractor/docparser.cpp b/sources/shiboken2/ApiExtractor/docparser.cpp new file mode 100644 index 000000000..bae438f18 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/docparser.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "docparser.h" +#include "abstractmetalang.h" +#include "typesystem.h" +#include +#include +#include + +#include +#include +#include + +DocParser::DocParser() +{ + xmlSubstituteEntitiesDefault(1); +} + +DocParser::~DocParser() +{ +} + +QString DocParser::getDocumentation(QXmlQuery& xquery, const QString& query, + const DocModificationList& mods) const +{ + QString doc = execXQuery(xquery, query); + return applyDocModifications(mods, doc); +} + +QString DocParser::execXQuery(QXmlQuery& xquery, const QString& query) const +{ + QString escapedQuery(query); + // XQuery can't have invalid XML characters + escapedQuery.replace(QLatin1Char('&'), QLatin1String("&")); + escapedQuery.replace(QLatin1Char('<'), QLatin1String("<")); + xquery.setQuery(escapedQuery); + if (!xquery.isValid()) { + qWarning() << "Bad XQuery: " << escapedQuery; + return QString(); + } + + QString result; + xquery.evaluateTo(&result); + return result; +} + +namespace +{ + +struct XslResources +{ + xmlDocPtr xmlDoc; + xsltStylesheetPtr xslt; + xmlDocPtr xslResult; + + XslResources() : xmlDoc(0), xslt(0), xslResult(0) {} + + ~XslResources() + { + if (xslt) + xsltFreeStylesheet(xslt); + + if (xslResult) + xmlFreeDoc(xslResult); + + if (xmlDoc) + xmlFreeDoc(xmlDoc); + + xsltCleanupGlobals(); + xmlCleanupParser(); + } +}; + +} // namespace + +QString DocParser::applyDocModifications(const DocModificationList& mods, const QString& xml) const +{ + if (mods.isEmpty()) + return xml; + + bool hasXPathBasedModification = false; + for (const DocModification &mod : mods) { + if (mod.mode() == TypeSystem::DocModificationXPathReplace) { + hasXPathBasedModification = true; + break; + } + } + + if (!hasXPathBasedModification) + return xml; + + QString xsl = QLatin1String("\n" + "\n" + "\n" + " \n" + "\n" + "\n" + "\n" + " \n" + " \n" + "\n" + "\n" + ); + for (const DocModification &mod : mods) { + if (mod.mode() == TypeSystem::DocModificationXPathReplace) { + QString xpath = mod.xpath(); + xpath.replace(QLatin1Char('"'), QLatin1String(""")); + xsl += QLatin1String("") + + mod.code() + QLatin1String("\n"); + } + } + xsl += QLatin1String(""); + + XslResources res; + // Read XML data + QByteArray xmlData = xml.toUtf8(); + res.xmlDoc = xmlParseMemory(xmlData.constData(), xmlData.size()); + if (!res.xmlDoc) + return xml; + + // Read XSL data as a XML file + QByteArray xslData = xsl.toUtf8(); + // xsltFreeStylesheet will delete this pointer + xmlDocPtr xslDoc = xmlParseMemory(xslData.constData(), xslData.size()); + if (!xslDoc) + return xml; + + // Parse XSL data + res.xslt = xsltParseStylesheetDoc(xslDoc); + if (!res.xslt) + return xml; + + // Apply XSL + res.xslResult = xsltApplyStylesheet(res.xslt, res.xmlDoc, 0); + xmlChar* buffer = 0; + int bufferSize; + QString result; + if (!xsltSaveResultToString(&buffer, &bufferSize, res.xslResult, res.xslt)) { + result = QString::fromUtf8(reinterpret_cast(buffer), bufferSize); + std::free(buffer); + } else { + result = xml; + } + + Q_ASSERT(result != xml); + return result; +} + diff --git a/sources/shiboken2/ApiExtractor/docparser.h b/sources/shiboken2/ApiExtractor/docparser.h new file mode 100644 index 000000000..5573f6851 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/docparser.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 DOCPARSER_H +#define DOCPARSER_H + +#include "typesystem_typedefs.h" + +#include + +QT_BEGIN_NAMESPACE +class QDomDocument; +class QDomNode; +class QXmlQuery; +QT_END_NAMESPACE + +class AbstractMetaClass; +class DocModification; +class Documentation; + +class DocParser +{ +public: + DocParser(); + virtual ~DocParser(); + virtual void fillDocumentation(AbstractMetaClass* metaClass) = 0; + + /** + * Process and retrieves documentation concerning the entire + * module or library. + * \return object containing module/library documentation information + */ + virtual Documentation retrieveModuleDocumentation() = 0; + + void setDocumentationDataDirectory(const QString& dir) + { + m_docDataDir = dir; + } + + /** + * Informs the location of the XML data generated by the tool + * (e.g.: DoxyGen, qdoc) used to extract the library's documentation + * comment. + * \return the path for the directory containing the XML data created + * from the library's documentation beign parsed. + */ + QString documentationDataDirectory() const + { + return m_docDataDir; + } + + void setLibrarySourceDirectory(const QString& dir) + { + m_libSourceDir = dir; + } + /** + * Informs the location of the library being parsed. The library + * source code is parsed for the documentation comments. + * \return the path for the directory containing the source code of + * the library beign parsed. + */ + QString librarySourceDirectory() const + { + return m_libSourceDir; + } + + void setPackageName(const QString& packageName) + { + m_packageName = packageName; + } + /** + * Retrieves the name of the package (or module or library) being parsed. + * \return the name of the package (module/library) being parsed + */ + QString packageName() const + { + return m_packageName; + } + + /** + * Process and retrieves documentation concerning the entire + * module or library. + * \param name module name + * \return object containing module/library documentation information + * \todo Merge with retrieveModuleDocumentation() on next ABI change. + */ + virtual Documentation retrieveModuleDocumentation(const QString& name) = 0; + +protected: + QString getDocumentation(QXmlQuery& xquery, const QString& query, + const DocModificationList& mods) const; + +private: + QString m_packageName; + QString m_docDataDir; + QString m_libSourceDir; + + QString execXQuery(QXmlQuery& xquery, const QString& query) const; + QString applyDocModifications(const DocModificationList& mods, const QString& xml) const; +}; + +#endif // DOCPARSER_H + diff --git a/sources/shiboken2/ApiExtractor/doxygenparser.cpp b/sources/shiboken2/ApiExtractor/doxygenparser.cpp new file mode 100644 index 000000000..6b90fe6fc --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doxygenparser.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "doxygenparser.h" +#include "abstractmetalang.h" +#include "reporthandler.h" +#include "typesystem.h" + +#include +#include +#include + +namespace +{ + +QString getSectionKindAttr(const AbstractMetaFunction* func) +{ + 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; + } +} + +} + +Documentation DoxygenParser::retrieveModuleDocumentation() +{ + return retrieveModuleDocumentation(packageName()); +} + +void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass) +{ + if (!metaClass) + return; + + QString doxyFileSuffix; + if (metaClass->enclosingClass()) { + doxyFileSuffix += metaClass->enclosingClass()->name(); + doxyFileSuffix += QLatin1String("_1_1"); // FIXME: Check why _1_1!! + } + doxyFileSuffix += metaClass->name(); + 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) { + doxyFilePath = documentationDataDirectory() + QLatin1Char('/') + + QLatin1String(prefixes[i]) + doxyFileSuffix; + if (QFile::exists(doxyFilePath)) + break; + doxyFilePath.clear(); + } + + if (doxyFilePath.isEmpty()) { + qCWarning(lcShiboken).noquote().nospace() + << "Can't find doxygen file for class " << metaClass->name() << ", tried: " + << QDir::toNativeSeparators(documentationDataDirectory()) + << "/{struct|class|namespace}"<< doxyFileSuffix; + return; + } + QXmlQuery xquery; + xquery.setFocus(QUrl(doxyFilePath)); + + // Get class documentation + QString classDoc = getDocumentation(xquery, QLatin1String("/doxygen/compounddef/detaileddescription"), + metaClass->typeEntry()->docModifications()); + if (classDoc.isEmpty()) { + qCWarning(lcShiboken).noquote().nospace() + << "Can't find documentation for class \"" << metaClass->name() << "\"."; + } + metaClass->setDocumentation(classDoc); + + //Functions Documentation + const AbstractMetaFunctionList &funcs = metaClass->functionsInTargetLang(); + for (AbstractMetaFunction *func : funcs) { + if (!func || func->isPrivate()) + continue; + + QString query = QLatin1String("/doxygen/compounddef/sectiondef"); + // properties + if (func->isPropertyReader() || func->isPropertyWriter() + || func->isPropertyResetter()) { + query += QLatin1String("[@kind=\"property\"]/memberdef/name[text()=\"") + + func->propertySpec()->name() + QLatin1String("\"]"); + isProperty = true; + } else { // normal methods + QString kind = getSectionKindAttr(func); + query += QLatin1String("[@kind=\"") + kind + + QLatin1String("-func\"]/memberdef/name[text()=\"") + + func->originalName() + QLatin1String("\"]"); + + if (func->arguments().isEmpty()) { + QString args = func->isConstant() ? QLatin1String("() const ") : QLatin1String("()"); + query += QLatin1String("/../argsstring[text()=\"") + args + QLatin1String("\"]"); + } else { + int i = 1; + const AbstractMetaArgumentList &arguments = func->arguments(); + for (AbstractMetaArgument *arg : arguments) { + if (!arg->type()->isPrimitive()) { + query += QLatin1String("/../param[") + QString::number(i) + + QLatin1String("]/type/ref[text()=\"") + + arg->type()->name() + QLatin1String("\"]/../.."); + } else { + query += QLatin1String("/../param[") + QString::number(i) + + QLatin1String("]/type[text()=\"") + + arg->type()->name() + QLatin1String("\"]/.."); + } + ++i; + } + } + } + if (!isProperty) { + query += QLatin1String("/../detaileddescription"); + } else { + query = QLatin1Char('(') + query; + query += QLatin1String("/../detaileddescription)[1]"); + } + QString doc = getDocumentation(xquery, query, DocModificationList()); + func->setDocumentation(doc); + isProperty = false; + } + + //Fields + const AbstractMetaFieldList &fields = metaClass->fields(); + for (AbstractMetaField *field : fields) { + if (field->isPrivate()) + return; + + QString query = QLatin1String("/doxygen/compounddef/sectiondef/memberdef/name[text()=\"") + + field->name() + QLatin1String("\"]/../detaileddescription"); + QString doc = getDocumentation(xquery, query, DocModificationList()); + field->setDocumentation(doc); + } + + //Enums + const AbstractMetaEnumList &enums = metaClass->enums(); + for (AbstractMetaEnum *meta_enum : enums) { + QString query = QLatin1String("/doxygen/compounddef/sectiondef/memberdef[@kind=\"enum\"]/name[text()=\"") + + meta_enum->name() + QLatin1String("\"]/.."); + QString doc = getDocumentation(xquery, query, DocModificationList()); + meta_enum->setDocumentation(doc); + } + +} + +Documentation DoxygenParser::retrieveModuleDocumentation(const QString& name){ + + QString sourceFile = documentationDataDirectory() + QLatin1String("/indexpage.xml"); + + if (!QFile::exists(sourceFile)) { + qCWarning(lcShiboken).noquote().nospace() + << "Can't find doxygen XML file for module " << name << ", tried: " + << QDir::toNativeSeparators(sourceFile); + return Documentation(); + } + + QXmlQuery xquery; + xquery.setFocus(QUrl(sourceFile)); + + // Module documentation + QString query = QLatin1String("/doxygen/compounddef/detaileddescription"); + return Documentation(getDocumentation(xquery, query, DocModificationList())); +} + diff --git a/sources/shiboken2/ApiExtractor/doxygenparser.h b/sources/shiboken2/ApiExtractor/doxygenparser.h new file mode 100644 index 000000000..3f9ca5142 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doxygenparser.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 DOXYGENPARSER_H +#define DOXYGENPARSER_H + +#include "docparser.h" + +class DoxygenParser : public DocParser +{ +public: + DoxygenParser() {} + void fillDocumentation(AbstractMetaClass *metaClass) override; + Documentation retrieveModuleDocumentation() override; + Documentation retrieveModuleDocumentation(const QString& name) override; +}; + +#endif // DOXYGENPARSER_H diff --git a/sources/shiboken2/ApiExtractor/fileout.cpp b/sources/shiboken2/ApiExtractor/fileout.cpp new file mode 100644 index 000000000..c97347fe1 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/fileout.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "fileout.h" +#include "reporthandler.h" + +#include +#include +#include + +#include + +bool FileOut::dummy = false; +bool FileOut::diff = false; + +#ifdef Q_OS_LINUX +const char* colorDelete = "\033[31m"; +const char* colorAdd = "\033[32m"; +const char* colorInfo = "\033[36m"; +const char* colorReset = "\033[0m"; +#else +const char* colorDelete = ""; +const char* colorAdd = ""; +const char* colorInfo = ""; +const char* colorReset = ""; +#endif + +FileOut::FileOut(QString n): + name(n), + stream(&tmp), + isDone(false) +{} + +static int* lcsLength(QList a, QList 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; + + for (int row = 1; row < height; row++) { + for (int col = 1; col < width; col++) { + if (a[row-1] == b[col-1]) + res[width * row + col] = res[width * (row-1) + col-1] + 1; + else + res[width * row + col] = qMax(res[width * row + col-1], + res[width * (row-1) + col]); + } + } + return res; +} + +enum Type { + Add, + Delete, + Unchanged +}; + +struct Unit +{ + Unit(Type type, int pos) : + type(type), + start(pos), + end(pos) {} + + Type type; + int start; + int end; + + void print(QList a, QList 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); + } + } +}; + +static QList *unitAppend(QList *res, Type type, int pos) +{ + if (!res) { + res = new QList; + res->append(new Unit(type, pos)); + return res; + } + + Unit *last = res->last(); + if (last->type == type) + last->end = pos; + else + res->append(new Unit(type, pos)); + + return res; +} + +static QList *diffHelper(int *lcs, QList a, QList 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); + } + } + delete lcs; + return 0; +} + +static void diff(QList a, QList b) +{ + QList *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); + } + delete(res); +} + + +FileOut::State FileOut::done() +{ + Q_ASSERT(!isDone); + if (name.isEmpty()) + return Failure; + + isDone = true; + bool fileEqual = false; + QFile fileRead(name); + QFileInfo info(fileRead); + stream.flush(); + QByteArray original; + if (info.exists() && (diff || (info.size() == tmp.size()))) { + if (!fileRead.open(QIODevice::ReadOnly)) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("failed to open file '%1' for reading") + .arg(QDir::toNativeSeparators(fileRead.fileName())); + return Failure; + } + + original = fileRead.readAll(); + fileRead.close(); + fileEqual = (original == tmp); + } + + if (fileEqual) + return Unchanged; + + if (!FileOut::dummy) { + QDir dir(info.absolutePath()); + if (!dir.mkpath(dir.absolutePath())) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("unable to create directory '%1'") + .arg(QDir::toNativeSeparators(dir.absolutePath())); + return Failure; + } + + QFile fileWrite(name); + if (!fileWrite.open(QIODevice::WriteOnly)) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("failed to open file '%1' for writing") + .arg(QDir::toNativeSeparators(fileWrite.fileName())); + return Failure; + } + QTextCodec *codec = QTextCodec::codecForName("UTF-8"); + stream.setCodec(codec); + stream.setDevice(&fileWrite); + stream << tmp; + } + if (diff) { + std::printf("%sFile: %s%s\n", colorInfo, qPrintable(name), colorReset); + ::diff(original.split('\n'), tmp.split('\n')); + std::printf("\n"); + } + + return Success; +} diff --git a/sources/shiboken2/ApiExtractor/fileout.h b/sources/shiboken2/ApiExtractor/fileout.h new file mode 100644 index 000000000..14ce3a251 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/fileout.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 FILEOUT_H +#define FILEOUT_H + +#include +#include + +class FileOut : public QObject +{ +private: + QByteArray tmp; + QString name; + +public: + enum State { Failure, Unchanged, Success }; + + FileOut(QString name); + ~FileOut() + { + if (!isDone) + done(); + } + + State done(); + + QTextStream stream; + + static bool dummy; + static bool diff; + +private: + bool isDone; +}; + +#endif // FILEOUT_H diff --git a/sources/shiboken2/ApiExtractor/graph.cpp b/sources/shiboken2/ApiExtractor/graph.cpp new file mode 100644 index 000000000..e6ee660dc --- /dev/null +++ b/sources/shiboken2/ApiExtractor/graph.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "graph.h" +#include +#include +#include +#include +#include +#include +#include +#include + +struct Graph::GraphPrivate +{ + enum Color { WHITE, GRAY, BLACK }; + typedef QVector > Edges; + typedef QSet::const_iterator EdgeIterator; + + Edges edges; + + GraphPrivate(int numNodes) : edges(numNodes) + { + } + + void dfsVisit(int node, QLinkedList& result, QVector& colors) const + { + colors[node] = GRAY; + EdgeIterator it = edges[node].begin(); + for (; it != edges[node].end(); ++it) { + if (colors[*it] == WHITE) + dfsVisit(*it, result, colors); + else if (colors[*it] == GRAY) // This is not a DAG! + return; + } + colors[node] = BLACK; + result.push_front(node); + } +}; + +Graph::Graph(int numNodes) : m_d(new GraphPrivate(numNodes)) +{ +} + +Graph::~Graph() +{ + delete m_d; +} + +int Graph::nodeCount() const +{ + return m_d->edges.size(); +} + +QLinkedList Graph::topologicalSort() const +{ + int nodeCount = Graph::nodeCount(); + QLinkedList result; + QVector colors(nodeCount, GraphPrivate::WHITE); + + for (int i = 0; i < nodeCount; ++i) { + if (colors[i] == GraphPrivate::WHITE) + m_d->dfsVisit(i, result, colors); + } + + // Not a DAG! + if (result.size() != nodeCount) + return QLinkedList(); + return result; +} + +bool Graph::containsEdge(int from, int to) +{ + return m_d->edges[from].contains(to); +} + +void Graph::addEdge(int from, int to) +{ + Q_ASSERT(to < (int)m_d->edges.size()); + m_d->edges[from].insert(to); +} + +void Graph::removeEdge(int from, int to) +{ + m_d->edges[from].remove(to); +} + +void Graph::dump() const +{ + for (int i = 0; i < m_d->edges.size(); ++i) { + std::cout << i << " -> "; + std::copy(m_d->edges[i].begin(), m_d->edges[i].end(), std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + } +} + +void Graph::dumpDot(const QHash< int, QString >& nodeNames, const QString& fileName) const +{ + QFile output(fileName); + if (!output.open(QIODevice::WriteOnly)) + return; + QTextStream s(&output); + s << "digraph D {\n"; + for (int i = 0; i < m_d->edges.size(); ++i) { + GraphPrivate::EdgeIterator it = m_d->edges[i].begin(); + for (;it != m_d->edges[i].end(); ++it) + s << '"' << nodeNames[i] << "\" -> \"" << nodeNames[*it] << "\"\n"; + } + s << "}\n"; +} diff --git a/sources/shiboken2/ApiExtractor/graph.h b/sources/shiboken2/ApiExtractor/graph.h new file mode 100644 index 000000000..78b931320 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/graph.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 GRAPH_H +#define GRAPH_H + +#include +#include +#include + +/// A graph that can have their nodes topologically sorted. +class Graph +{ +public: + /// Create a new graph with \p numNodes nodes. + Graph(int numNodes); + ~Graph(); + + /// Returns the numbed of nodes in this graph. + int nodeCount() const; + /// Returns true if the graph contains the edge from -> to + bool containsEdge(int from, int to); + /// Adds an edge to this graph. + void addEdge(int from, int to); + /// Removes an edge out of this graph. + void removeEdge(int from, int to); + /// Print this graph to stdout. + void dump() const; + /** + * Dumps a dot graph to a file named \p filename. + * \param nodeNames map used to translate node ids to human readable text. + * \param fileName file name where the output should be written. + */ + void dumpDot(const QHash& nodeNames, const QString& fileName) const; + + /** + * Topologically sort this graph. + * \return A collection with all nodes topologically sorted or an empty collection if a ciclic dependency was found. + */ + QLinkedList topologicalSort() const; +private: + + struct GraphPrivate; + GraphPrivate* m_d; +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/header_paths.h b/sources/shiboken2/ApiExtractor/header_paths.h new file mode 100644 index 000000000..3bc26efe0 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/header_paths.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 HEADER_PATHS_H +#define HEADER_PATHS_H + +#include +#include +#include + +class HeaderPath { +public: + explicit HeaderPath(const QByteArray &p = QByteArray()) : path(p), m_isFramework(false) {} + explicit HeaderPath(const QString &s = QString(), bool isFramework = false) : + path(s.toLatin1()), m_isFramework(isFramework) {} + + QByteArray path; + bool m_isFramework; // macOS framework path + + static QByteArray includeOption(const HeaderPath &p, bool systemInclude = false) + { + QByteArray option; + + if (p.m_isFramework) + option = QByteArrayLiteral("-F"); + else if (systemInclude) + option = QByteArrayLiteral("-isystem"); + else + option = QByteArrayLiteral("-I"); + + return option + p.path; + } +}; + +typedef QList HeaderPaths; + +#endif // HEADER_PATHS_H diff --git a/sources/shiboken2/ApiExtractor/icecc.cmake b/sources/shiboken2/ApiExtractor/icecc.cmake new file mode 100644 index 000000000..b2bf071aa --- /dev/null +++ b/sources/shiboken2/ApiExtractor/icecc.cmake @@ -0,0 +1,11 @@ +include (CMakeForceCompiler) +option(ENABLE_ICECC "Enable icecc checking, for distributed compilation") +if (ENABLE_ICECC) + find_program(ICECC icecc) + if (ICECC) + message(STATUS "icecc found! Distributed compilation for all!! huhuhu.") + cmake_force_cxx_compiler(${ICECC} icecc) + else(ICECC) + message(FATAL_ERROR "icecc NOT found! re-run cmake without -DENABLE_ICECC") + endif(ICECC) +endif(ENABLE_ICECC) diff --git a/sources/shiboken2/ApiExtractor/include.cpp b/sources/shiboken2/ApiExtractor/include.cpp new file mode 100644 index 000000000..deae2d2ac --- /dev/null +++ b/sources/shiboken2/ApiExtractor/include.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "include.h" +#include +#include +#include +#include + +QString Include::toString() const +{ + if (m_type == IncludePath) + return QLatin1String("#include <") + m_name + QLatin1Char('>'); + else if (m_type == LocalPath) + return QLatin1String("#include \"") + m_name + QLatin1Char('"'); + else + return QLatin1String("import ") + m_name + QLatin1Char(';'); +} + +uint qHash(const Include& inc) +{ + return qHash(inc.m_name); +} + +QTextStream& operator<<(QTextStream& out, const Include& include) +{ + if (include.isValid()) + out << include.toString() << endl; + return out; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const Include &i) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "Include("; + if (i.isValid()) + d << "type=" << i.type() << ", file=\"" << QDir::toNativeSeparators(i.name()) << '"'; + else + d << "invalid"; + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken2/ApiExtractor/include.h b/sources/shiboken2/ApiExtractor/include.h new file mode 100644 index 000000000..dc4965e1a --- /dev/null +++ b/sources/shiboken2/ApiExtractor/include.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 INCLUDE_H +#define INCLUDE_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QTextStream; +QT_END_NAMESPACE + +class Include +{ +public: + enum IncludeType { + IncludePath, + LocalPath, + TargetLangImport + }; + + Include() : m_type(IncludePath) {} + Include(IncludeType t, const QString &nam) : m_type(t), m_name(nam) {}; + + bool isValid() const + { + return !m_name.isEmpty(); + } + + IncludeType type() const + { + return m_type; + } + + QString name() const + { + return m_name; + } + + QString toString() const; + + bool operator<(const Include& other) const + { + return m_name < other.m_name; + } + + bool operator==(const Include& other) const + { + return m_type == other.m_type && m_name == other.m_name; + } + + friend uint qHash(const Include&); + private: + IncludeType m_type; + QString m_name; +}; + +uint qHash(const Include& inc); +QTextStream& operator<<(QTextStream& out, const Include& include); +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const Include &i); +#endif + +typedef QVector IncludeList; + +#endif diff --git a/sources/shiboken2/ApiExtractor/merge.xsl b/sources/shiboken2/ApiExtractor/merge.xsl new file mode 100644 index 000000000..d0b7eafa5 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/merge.xsl @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp new file mode 100644 index 000000000..667e27344 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp @@ -0,0 +1,1207 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2002-2005 Roberto Raggi +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "codemodel.h" +#include +#include +#include +#include +#include + +// Predicate to find an item by name in a list of QSharedPointer +template class ModelItemNamePredicate : public std::unary_function > +{ +public: + explicit ModelItemNamePredicate(const QString &name) : m_name(name) {} + bool operator()(const QSharedPointer &item) const { return item->name() == m_name; } + +private: + const QString m_name; +}; + +template +static QSharedPointer findModelItem(const QVector > &list, const QString &name) +{ + typedef typename QVector >::const_iterator It; + const It it = std::find_if(list.begin(), list.end(), ModelItemNamePredicate(name)); + return it != list.end() ? *it : QSharedPointer(); +} + +// --------------------------------------------------------------------------- + +CodeModel::CodeModel() : m_globalNamespace(new _NamespaceModelItem(this)) +{ +} + +CodeModel::~CodeModel() +{ +} + +NamespaceModelItem CodeModel::globalNamespace() const +{ + return m_globalNamespace; +} + +void CodeModel::addFile(FileModelItem item) +{ + m_files.append(item); +} + +FileModelItem CodeModel::findFile(const QString &name) const +{ + return findModelItem(m_files, name); +} + +CodeModelItem CodeModel::findItem(const QStringList &qualifiedName, CodeModelItem scope) const +{ + for (int i = 0; i < qualifiedName.size(); ++i) { + // ### Extend to look for members etc too. + const QString &name = qualifiedName.at(i); + + if (NamespaceModelItem ns = qSharedPointerDynamicCast<_NamespaceModelItem>(scope)) { + if (NamespaceModelItem tmp_ns = ns->findNamespace(name)) { + scope = tmp_ns; + continue; + } + } + + if (ScopeModelItem ss = qSharedPointerDynamicCast<_ScopeModelItem>(scope)) { + if (ClassModelItem cs = ss->findClass(name)) { + scope = cs; + } else if (EnumModelItem es = ss->findEnum(name)) { + if (i == qualifiedName.size() - 1) + return es; + } else if (TypeDefModelItem tp = ss->findTypeDef(name)) { + if (i == qualifiedName.size() - 1) + return tp; + } else { + // If we don't find the name in the scope chain we + // need to return an empty item to indicate failure... + return CodeModelItem(); + } + } + } + + return scope; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const CodeModel *m) +{ + QDebugStateSaver s(d); + d.noquote(); + d.nospace(); + d << "CodeModel("; + if (m) { + const NamespaceModelItem globalNamespaceP = m->globalNamespace(); + if (globalNamespaceP.data()) + globalNamespaceP->formatDebug(d); + } else { + d << '0'; + } + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +// --------------------------------------------------------------------------- +TypeInfo TypeInfo::combine(const TypeInfo &__lhs, const TypeInfo &__rhs) +{ + TypeInfo __result = __lhs; + + __result.setConstant(__result.isConstant() || __rhs.isConstant()); + __result.setVolatile(__result.isVolatile() || __rhs.isVolatile()); + if (__rhs.referenceType() > __result.referenceType()) + __result.setReferenceType(__rhs.referenceType()); + __result.setIndirections(__result.indirections() + __rhs.indirections()); + __result.setArrayElements(__result.arrayElements() + __rhs.arrayElements()); + + return __result; +} + +TypeInfo TypeInfo::resolveType(TypeInfo const &__type, CodeModelItem __scope) +{ + CodeModel *__model = __scope->model(); + Q_ASSERT(__model != 0); + + return TypeInfo::resolveType(__model->findItem(__type.qualifiedName(), __scope), __type, __scope); +} + +TypeInfo TypeInfo::resolveType(CodeModelItem __item, TypeInfo const &__type, CodeModelItem __scope) +{ + // Copy the type and replace with the proper qualified name. This + // only makes sence to do if we're actually getting a resolved + // type with a namespace. We only get this if the returned type + // has more than 2 entries in the qualified name... This test + // could be improved by returning if the type was found or not. + TypeInfo otherType(__type); + if (__item && __item->qualifiedName().size() > 1) { + otherType.setQualifiedName(__item->qualifiedName()); + } + + if (TypeDefModelItem __typedef = qSharedPointerDynamicCast<_TypeDefModelItem>(__item)) { + const TypeInfo combined = TypeInfo::combine(__typedef->type(), otherType); + const CodeModelItem nextItem = __scope->model()->findItem(combined.qualifiedName(), __scope); + if (!nextItem) + return combined; + // PYSIDE-362, prevent recursion on opaque structs like + // typedef struct xcb_connection_t xcb_connection_t; + if (nextItem.data() ==__item.data()) { + std::cerr << "** WARNING Bailing out recursion of " << __FUNCTION__ + << "() on " << qPrintable(__type.qualifiedName().join(QLatin1String("::"))) + << std::endl; + return otherType; + } + return resolveType(nextItem, combined, __scope); + } + + return otherType; +} + +QString TypeInfo::toString() const +{ + QString tmp; + + tmp += m_qualifiedName.join(QLatin1String("::")); + if (isConstant()) + tmp += QLatin1String(" const"); + + if (isVolatile()) + tmp += QLatin1String(" volatile"); + + if (indirections()) + tmp += QString(indirections(), QLatin1Char('*')); + + switch (referenceType()) { + case NoReference: + break; + case LValueReference: + tmp += QLatin1Char('&'); + break; + case RValueReference: + tmp += QLatin1String("&&"); + break; + } + + if (isFunctionPointer()) { + tmp += QLatin1String(" (*)("); + for (int i = 0; i < m_arguments.count(); ++i) { + if (i != 0) + tmp += QLatin1String(", "); + + tmp += m_arguments.at(i).toString(); + } + tmp += QLatin1Char(')'); + } + + for (const QString &elt : m_arrayElements) { + tmp += QLatin1Char('['); + tmp += elt; + tmp += QLatin1Char(']'); + } + + return tmp; +} + +bool TypeInfo::operator==(const TypeInfo &other) const +{ + if (arrayElements().count() != other.arrayElements().count()) + return false; + +#if defined (RXX_CHECK_ARRAY_ELEMENTS) // ### it'll break + for (int i = 0; i < arrayElements().count(); ++i) { + QString elt1 = arrayElements().at(i).trimmed(); + QString elt2 = other.arrayElements().at(i).trimmed(); + + if (elt1 != elt2) + return false; + } +#endif + + return flags == other.flags + && m_qualifiedName == other.m_qualifiedName + && (!m_functionPointer || m_arguments == other.m_arguments); +} + +#ifndef QT_NO_DEBUG_STREAM +template +void formatSequence(QDebug &d, It i1, It i2, const char *separator=", ") +{ + for (It i = i1; i != i2; ++i) { + if (i != i1) + d << separator; + d << *i; + } +} + +void TypeInfo::formatDebug(QDebug &d) const +{ + d << '"'; + formatSequence(d, m_qualifiedName.begin(), m_qualifiedName.end(), "\", \""); + d << '"'; + if (m_constant) + d << ", [const]"; + if (m_volatile) + d << ", [volatile]"; + if (m_indirections) + d << ", indirections=" << m_indirections; + switch (m_referenceType) { + case NoReference: + break; + case LValueReference: + d << ", [ref]"; + break; + case RValueReference: + d << ", [rvalref]"; + break; + } + if (m_functionPointer) { + d << ", function ptr("; + formatSequence(d, m_arguments.begin(), m_arguments.end()); + d << ')'; + } + if (!m_arrayElements.isEmpty()) { + d << ", array[" << m_arrayElements.size() << "]["; + formatSequence(d, m_arrayElements.begin(), m_arrayElements.end()); + d << ']'; + } +} + +QDebug operator<<(QDebug d, const TypeInfo &t) +{ + QDebugStateSaver s(d); +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) + const int verbosity = d.verbosity(); +#else + const int verbosity = 0; +#endif + d.noquote(); + d.nospace(); + d << "TypeInfo("; + if (verbosity > 2) + t.formatDebug(d); + else + d << t.toString(); + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +// --------------------------------------------------------------------------- +_CodeModelItem::_CodeModelItem(CodeModel *model, int kind) + : m_model(model), + m_kind(kind), + m_startLine(0), + m_startColumn(0), + m_endLine(0), + m_endColumn(0) +{ +} + +_CodeModelItem::_CodeModelItem(CodeModel *model, const QString &name, int kind) + : m_model(model), + m_kind(kind), + m_startLine(0), + m_startColumn(0), + m_endLine(0), + m_endColumn(0), + m_name(name) +{ +} + +_CodeModelItem::~_CodeModelItem() +{ +} + +int _CodeModelItem::kind() const +{ + return m_kind; +} + +QStringList _CodeModelItem::qualifiedName() const +{ + QStringList q = scope(); + + if (!name().isEmpty()) + q += name(); + + return q; +} + +QString _CodeModelItem::name() const +{ + return m_name; +} + +void _CodeModelItem::setName(const QString &name) +{ + m_name = name; +} + +QStringList _CodeModelItem::scope() const +{ + return m_scope; +} + +void _CodeModelItem::setScope(const QStringList &scope) +{ + m_scope = scope; +} + +QString _CodeModelItem::fileName() const +{ + return m_fileName; +} + +void _CodeModelItem::setFileName(const QString &fileName) +{ + m_fileName = fileName; +} + +FileModelItem _CodeModelItem::file() const +{ + return model()->findFile(fileName()); +} + +void _CodeModelItem::getStartPosition(int *line, int *column) +{ + *line = m_startLine; + *column = m_startColumn; +} + +void _CodeModelItem::setStartPosition(int line, int column) +{ + m_startLine = line; + m_startColumn = column; +} + +void _CodeModelItem::getEndPosition(int *line, int *column) +{ + *line = m_endLine; + *column = m_endColumn; +} + +void _CodeModelItem::setEndPosition(int line, int column) +{ + m_endLine = line; + m_endColumn = column; +} + +#ifndef QT_NO_DEBUG_STREAM +template +static void formatPtrSequence(QDebug &d, It i1, It i2, const char *separator=", ") +{ + for (It i = i1; i != i2; ++i) { + if (i != i1) + d << separator; + d << i->data(); + } +} + +void _CodeModelItem::formatKind(QDebug &d, int k) +{ + switch (k) { + case Kind_Argument: + d << "ArgumentModelItem"; + break; + case Kind_Class: + d << "ClassModelItem"; + break; + case Kind_Enum: + d << "EnumModelItem"; + break; + case Kind_Enumerator: + d << "EnumeratorModelItem"; + break; + case Kind_File: + d << "FileModelItem"; + break; + case Kind_Function: + d << "FunctionModelItem"; + break; + case Kind_Member: + d << "MemberModelItem"; + break; + case Kind_Namespace: + d << "NamespaceModelItem"; + break; + case Kind_Variable: + d << "VariableModelItem"; + break; + case Kind_Scope: + d << "ScopeModelItem"; + break; + case Kind_TemplateParameter: + d << "TemplateParameter"; + break; + case Kind_TypeDef: + d << "TypeDefModelItem"; + break; + default: + d << "CodeModelItem"; + break; + } +} + +void _CodeModelItem::formatDebug(QDebug &d) const +{ + d << "(\"" << name() << '"'; + if (!m_scope.isEmpty()) { + d << ", scope="; + formatSequence(d, m_scope.cbegin(), m_scope.cend(), "::"); + } + if (!m_fileName.isEmpty()) { + d << ", file=\"" << QDir::toNativeSeparators(m_fileName); + if (m_startLine > 0) + d << ':' << m_startLine; + d << '"'; + } +} + +QDebug operator<<(QDebug d, const _CodeModelItem *t) +{ + QDebugStateSaver s(d); + d.noquote(); + d.nospace(); + if (!t) { + d << "CodeModelItem(0)"; + return d; + } + _CodeModelItem::formatKind(d, t->kind()); + t->formatDebug(d); + switch (t->kind()) { + case _CodeModelItem::Kind_Class: + d << " /* class " << t->name() << " */"; + break; + case _CodeModelItem::Kind_Namespace: + d << " /* namespace " << t->name() << " */"; + break; + } + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +// --------------------------------------------------------------------------- +_ClassModelItem::~_ClassModelItem() +{ +} + +QStringList _ClassModelItem::baseClasses() const +{ + return m_baseClasses; +} + +void _ClassModelItem::setBaseClasses(const QStringList &baseClasses) +{ + m_baseClasses = baseClasses; +} + +TemplateParameterList _ClassModelItem::templateParameters() const +{ + return m_templateParameters; +} + +void _ClassModelItem::setTemplateParameters(const TemplateParameterList &templateParameters) +{ + m_templateParameters = templateParameters; +} + +void _ClassModelItem::addBaseClass(const QString &baseClass) +{ + m_baseClasses.append(baseClass); +} + +bool _ClassModelItem::extendsClass(const QString &name) const +{ + return m_baseClasses.contains(name); +} + +void _ClassModelItem::setClassType(CodeModel::ClassType type) +{ + m_classType = type; +} + +CodeModel::ClassType _ClassModelItem::classType() const +{ + return m_classType; +} + +void _ClassModelItem::addPropertyDeclaration(const QString &propertyDeclaration) +{ + m_propertyDeclarations << propertyDeclaration; +} + +#ifndef QT_NO_DEBUG_STREAM +template +static void formatModelItemList(QDebug &d, const char *prefix, const List &l, + const char *separator = ", ") +{ + if (const int size = l.size()) { + d << prefix << '[' << size << "]("; + for (int i = 0; i < size; ++i) { + if (i) + d << separator; + l.at(i)->formatDebug(d); + } + d << ')'; + } +} + +void _ClassModelItem::formatDebug(QDebug &d) const +{ + _CodeModelItem::formatDebug(d); + if (!m_baseClasses.isEmpty()) + d << ", inherits=" << m_baseClasses; + formatModelItemList(d, ", templateParameters=", m_templateParameters); + formatScopeItemsDebug(d); +} +#endif // !QT_NO_DEBUG_STREAM + +// --------------------------------------------------------------------------- +FunctionModelItem _ScopeModelItem::declaredFunction(FunctionModelItem item) +{ + for (const FunctionModelItem &fun : qAsConst(m_functions)) { + if (fun->name() == item->name() && fun->isSimilar(item)) + return fun; + + } + return FunctionModelItem(); +} + +_ScopeModelItem::~_ScopeModelItem() +{ +} + +void _ScopeModelItem::addEnumsDeclaration(const QString &enumsDeclaration) +{ + m_enumsDeclarations << enumsDeclaration; +} + +void _ScopeModelItem::addClass(ClassModelItem item) +{ + m_classes.append(item); +} + +void _ScopeModelItem::addFunction(FunctionModelItem item) +{ + m_functions.append(item); +} + +void _ScopeModelItem::addVariable(VariableModelItem item) +{ + m_variables.append(item); +} + +void _ScopeModelItem::addTypeDef(TypeDefModelItem item) +{ + m_typeDefs.append(item); +} + +void _ScopeModelItem::addEnum(EnumModelItem item) +{ + m_enums.append(item); +} + +#ifndef QT_NO_DEBUG_STREAM +template +static void formatScopeHash(QDebug &d, const char *prefix, const Hash &h, + const char *separator = ", ", + bool trailingNewLine = false) +{ + typedef typename Hash::ConstIterator HashIterator; + if (!h.isEmpty()) { + d << prefix << '[' << h.size() << "]("; + const HashIterator begin = h.begin(); + const HashIterator end = h.end(); + for (HashIterator it = begin; it != end; ++it) { // Omit the names as they are repeated + if (it != begin) + d << separator; + d << it.value().data(); + } + d << ')'; + if (trailingNewLine) + d << '\n'; + } +} + +template +static void formatScopeList(QDebug &d, const char *prefix, const List &l, + const char *separator = ", ", + bool trailingNewLine = false) +{ + if (!l.isEmpty()) { + d << prefix << '[' << l.size() << "]("; + formatPtrSequence(d, l.begin(), l.end(), separator); + d << ')'; + if (trailingNewLine) + d << '\n'; + } +} + +void _ScopeModelItem::formatScopeItemsDebug(QDebug &d) const +{ + formatScopeList(d, ", classes=", m_classes, "\n", true); + formatScopeList(d, ", enums=", m_enums, "\n", true); + formatScopeList(d, ", aliases=", m_typeDefs, "\n", true); + formatScopeList(d, ", functions=", m_functions, "\n", true); + formatScopeList(d, ", variables=", m_variables); +} + +void _ScopeModelItem::formatDebug(QDebug &d) const +{ + _CodeModelItem::formatDebug(d); + formatScopeItemsDebug(d); +} +#endif // !QT_NO_DEBUG_STREAM + +namespace { +// Predicate to match a non-template class name against the class list. +// "Vector" should match "Vector" as well as "Vector" (as seen for methods +// from within the class "Vector"). +class ClassNamePredicate : public std::unary_function +{ +public: + explicit ClassNamePredicate(const QString &name) : m_name(name) {} + bool operator()(const ClassModelItem &item) const + { + const QString &itemName = item->name(); + if (!itemName.startsWith(m_name)) + return false; + return itemName.size() == m_name.size() || itemName.at(m_name.size()) == QLatin1Char('<'); + } + +private: + const QString m_name; +}; +} // namespace + +ClassModelItem _ScopeModelItem::findClass(const QString &name) const +{ + // A fully qualified template is matched by name only + const ClassList::const_iterator it = name.contains(QLatin1Char('<')) + ? std::find_if(m_classes.begin(), m_classes.end(), ModelItemNamePredicate<_ClassModelItem>(name)) + : std::find_if(m_classes.begin(), m_classes.end(), ClassNamePredicate(name)); + return it != m_classes.end() ? *it : ClassModelItem(); +} + +VariableModelItem _ScopeModelItem::findVariable(const QString &name) const +{ + return findModelItem(m_variables, name); +} + +TypeDefModelItem _ScopeModelItem::findTypeDef(const QString &name) const +{ + return findModelItem(m_typeDefs, name); +} + +EnumModelItem _ScopeModelItem::findEnum(const QString &name) const +{ + return findModelItem(m_enums, name); +} + +FunctionList _ScopeModelItem::findFunctions(const QString &name) const +{ + FunctionList result; + for (const FunctionModelItem &func : m_functions) { + if (func->name() == name) + result.append(func); + } + return result; +} + +// --------------------------------------------------------------------------- +_NamespaceModelItem::~_NamespaceModelItem() +{ +} + +QSet _NamespaceModelItem::uniqueNamespaces() const +{ + QSet result; + for (const NamespaceModelItem &n : m_namespaces) + result.insert(n); + return result; +} + +void _NamespaceModelItem::addNamespace(NamespaceModelItem item) +{ + m_namespaces.append(item); +} + +NamespaceModelItem _NamespaceModelItem::findNamespace(const QString &name) const +{ + return findModelItem(m_namespaces, name); +} + +_FileModelItem::~_FileModelItem() +{ +} + +#ifndef QT_NO_DEBUG_STREAM +void _NamespaceModelItem::formatDebug(QDebug &d) const +{ + _ScopeModelItem::formatDebug(d); + formatScopeList(d, ", namespaces=", m_namespaces); +} +#endif // !QT_NO_DEBUG_STREAM + +// --------------------------------------------------------------------------- +_ArgumentModelItem::~_ArgumentModelItem() +{ +} + +TypeInfo _ArgumentModelItem::type() const +{ + return m_type; +} + +void _ArgumentModelItem::setType(const TypeInfo &type) +{ + m_type = type; +} + +bool _ArgumentModelItem::defaultValue() const +{ + return m_defaultValue; +} + +void _ArgumentModelItem::setDefaultValue(bool defaultValue) +{ + m_defaultValue = defaultValue; +} + +#ifndef QT_NO_DEBUG_STREAM +void _ArgumentModelItem::formatDebug(QDebug &d) const +{ + _CodeModelItem::formatDebug(d); + d << ", type=" << m_type; + if (m_defaultValue) + d << ", defaultValue=\"" << m_defaultValueExpression << '"'; +} +#endif // !QT_NO_DEBUG_STREAM +// --------------------------------------------------------------------------- +_FunctionModelItem::~_FunctionModelItem() +{ +} + +bool _FunctionModelItem::isSimilar(FunctionModelItem other) const +{ + if (name() != other->name()) + return false; + + if (isConstant() != other->isConstant()) + return false; + + if (isVariadics() != other->isVariadics()) + return false; + + if (arguments().count() != other->arguments().count()) + return false; + + // ### check the template parameters + + for (int i = 0; i < arguments().count(); ++i) { + ArgumentModelItem arg1 = arguments().at(i); + ArgumentModelItem arg2 = other->arguments().at(i); + + if (arg1->type() != arg2->type()) + return false; + } + + return true; +} + +ArgumentList _FunctionModelItem::arguments() const +{ + return m_arguments; +} + +void _FunctionModelItem::addArgument(ArgumentModelItem item) +{ + m_arguments.append(item); +} + +CodeModel::FunctionType _FunctionModelItem::functionType() const +{ + return m_functionType; +} + +void _FunctionModelItem::setFunctionType(CodeModel::FunctionType functionType) +{ + m_functionType = functionType; +} + +bool _FunctionModelItem::isVariadics() const +{ + return m_isVariadics; +} + +void _FunctionModelItem::setVariadics(bool isVariadics) +{ + m_isVariadics = isVariadics; +} + +bool _FunctionModelItem::isVirtual() const +{ + return m_isVirtual; +} + +void _FunctionModelItem::setVirtual(bool isVirtual) +{ + m_isVirtual = isVirtual; +} + +bool _FunctionModelItem::isInline() const +{ + return m_isInline; +} + +void _FunctionModelItem::setInline(bool isInline) +{ + m_isInline = isInline; +} + +bool _FunctionModelItem::isExplicit() const +{ + return m_isExplicit; +} + +void _FunctionModelItem::setExplicit(bool isExplicit) +{ + m_isExplicit = isExplicit; +} + +bool _FunctionModelItem::isAbstract() const +{ + return m_isAbstract; +} + +void _FunctionModelItem::setAbstract(bool isAbstract) +{ + m_isAbstract = isAbstract; +} + +// Qt +bool _FunctionModelItem::isInvokable() const +{ + return m_isInvokable; +} + +void _FunctionModelItem::setInvokable(bool isInvokable) +{ + m_isInvokable = isInvokable; +} + +#ifndef QT_NO_DEBUG_STREAM +void _FunctionModelItem::formatDebug(QDebug &d) const +{ + _MemberModelItem::formatDebug(d); + d << ", type=" << m_functionType; + if (m_isInline) + d << " [inline]"; + if (m_isAbstract) + d << " [abstract]"; + if (m_isExplicit) + d << " [explicit]"; + if (m_isInvokable) + d << " [invokable]"; + formatModelItemList(d, ", arguments=", m_arguments); + if (m_isVariadics) + d << ",..."; +} +#endif // !QT_NO_DEBUG_STREAM + +// --------------------------------------------------------------------------- +TypeInfo _TypeDefModelItem::type() const +{ + return m_type; +} + +void _TypeDefModelItem::setType(const TypeInfo &type) +{ + m_type = type; +} + +#ifndef QT_NO_DEBUG_STREAM +void _TypeDefModelItem::formatDebug(QDebug &d) const +{ + _CodeModelItem::formatDebug(d); + d << ", type=" << m_type; +} +#endif // !QT_NO_DEBUG_STREAM + +// --------------------------------------------------------------------------- +CodeModel::AccessPolicy _EnumModelItem::accessPolicy() const +{ + return m_accessPolicy; +} + +_EnumModelItem::~_EnumModelItem() +{ +} + +void _EnumModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy) +{ + m_accessPolicy = accessPolicy; +} + +EnumeratorList _EnumModelItem::enumerators() const +{ + return m_enumerators; +} + +void _EnumModelItem::addEnumerator(EnumeratorModelItem item) +{ + m_enumerators.append(item); +} + +bool _EnumModelItem::isAnonymous() const +{ + return m_anonymous; +} + +void _EnumModelItem::setAnonymous(bool anonymous) +{ + m_anonymous = anonymous; +} + +#ifndef QT_NO_DEBUG_STREAM +void _EnumModelItem::formatDebug(QDebug &d) const +{ + _CodeModelItem::formatDebug(d); + if (m_anonymous) + d << " (anonymous)"; + formatModelItemList(d, ", enumerators=", m_enumerators); +} +#endif // !QT_NO_DEBUG_STREAM + +// --------------------------------------------------------------------------- +_EnumeratorModelItem::~_EnumeratorModelItem() +{ +} + +QString _EnumeratorModelItem::value() const +{ + return m_value; +} + +void _EnumeratorModelItem::setValue(const QString &value) +{ + m_value = value; +} + +#ifndef QT_NO_DEBUG_STREAM +void _EnumeratorModelItem::formatDebug(QDebug &d) const +{ + _CodeModelItem::formatDebug(d); + if (!m_value.isEmpty()) + d << ", value=\"" << m_value << '"'; +} +#endif // !QT_NO_DEBUG_STREAM + +// --------------------------------------------------------------------------- +_TemplateParameterModelItem::~_TemplateParameterModelItem() +{ +} + +TypeInfo _TemplateParameterModelItem::type() const +{ + return m_type; +} + +void _TemplateParameterModelItem::setType(const TypeInfo &type) +{ + m_type = type; +} + +bool _TemplateParameterModelItem::defaultValue() const +{ + return m_defaultValue; +} + +void _TemplateParameterModelItem::setDefaultValue(bool defaultValue) +{ + m_defaultValue = defaultValue; +} + +#ifndef QT_NO_DEBUG_STREAM +void _TemplateParameterModelItem::formatDebug(QDebug &d) const +{ + _CodeModelItem::formatDebug(d); + d << ", type=" << m_type; + if (m_defaultValue) + d << " [defaultValue]"; +} +#endif // !QT_NO_DEBUG_STREAM + +// --------------------------------------------------------------------------- +TypeInfo _MemberModelItem::type() const +{ + return m_type; +} + +void _MemberModelItem::setType(const TypeInfo &type) +{ + m_type = type; +} + +CodeModel::AccessPolicy _MemberModelItem::accessPolicy() const +{ + return m_accessPolicy; +} + +_MemberModelItem::~_MemberModelItem() +{ +} + +void _MemberModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy) +{ + m_accessPolicy = accessPolicy; +} + +bool _MemberModelItem::isStatic() const +{ + return m_isStatic; +} + +void _MemberModelItem::setStatic(bool isStatic) +{ + m_isStatic = isStatic; +} + +bool _MemberModelItem::isConstant() const +{ + return m_isConstant; +} + +void _MemberModelItem::setConstant(bool isConstant) +{ + m_isConstant = isConstant; +} + +bool _MemberModelItem::isVolatile() const +{ + return m_isVolatile; +} + +void _MemberModelItem::setVolatile(bool isVolatile) +{ + m_isVolatile = isVolatile; +} + +bool _MemberModelItem::isAuto() const +{ + return m_isAuto; +} + +void _MemberModelItem::setAuto(bool isAuto) +{ + m_isAuto = isAuto; +} + +bool _MemberModelItem::isFriend() const +{ + return m_isFriend; +} + +void _MemberModelItem::setFriend(bool isFriend) +{ + m_isFriend = isFriend; +} + +bool _MemberModelItem::isRegister() const +{ + return m_isRegister; +} + +void _MemberModelItem::setRegister(bool isRegister) +{ + m_isRegister = isRegister; +} + +bool _MemberModelItem::isExtern() const +{ + return m_isExtern; +} + +void _MemberModelItem::setExtern(bool isExtern) +{ + m_isExtern = isExtern; +} + +bool _MemberModelItem::isMutable() const +{ + return m_isMutable; +} + +void _MemberModelItem::setMutable(bool isMutable) +{ + m_isMutable = isMutable; +} + +#ifndef QT_NO_DEBUG_STREAM +void _MemberModelItem::formatDebug(QDebug &d) const +{ + _CodeModelItem::formatDebug(d); + switch (m_accessPolicy) { + case CodeModel::Public: + d << ", public"; + break; + case CodeModel::Protected: + d << ", protected"; + break; + case CodeModel::Private: + d << ", private"; + break; + } + d << ", type="; + if (m_isConstant) + d << "const "; + if (m_isVolatile) + d << "volatile "; + if (m_isStatic) + d << "static "; + if (m_isAuto) + d << "auto "; + if (m_isFriend) + d << "friend "; + if (m_isRegister) + d << "register "; + if (m_isExtern) + d << "extern "; + if (m_isMutable) + d << "mutable "; + d << m_type; + formatScopeList(d, ", templateParameters", m_templateParameters); +} +#endif // !QT_NO_DEBUG_STREAM + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.h b/sources/shiboken2/ApiExtractor/parser/codemodel.h new file mode 100644 index 000000000..ea16e6912 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.h @@ -0,0 +1,687 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2002-2005 Roberto Raggi +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 CODEMODEL_H +#define CODEMODEL_H + +#include "codemodel_fwd.h" +#include "codemodel_enums.h" + +#include +#include +#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QDebug) + +#define DECLARE_MODEL_NODE(k) \ + enum { __node_kind = Kind_##k }; + +class CodeModel +{ +public: + enum AccessPolicy { + Public, + Protected, + Private + }; + + enum FunctionType { + Normal, + Signal, + Slot + }; + + enum ClassType { + Class, + Struct, + Union + }; + +public: + CodeModel(); + virtual ~CodeModel(); + + FileList files() const { return m_files; } + NamespaceModelItem globalNamespace() const; + + void addFile(FileModelItem item); + FileModelItem findFile(const QString &name) const; + + CodeModelItem findItem(const QStringList &qualifiedName, CodeModelItem scope) const; + +private: + FileList m_files; + NamespaceModelItem m_globalNamespace; + +private: + CodeModel(const CodeModel &other); + void operator = (const CodeModel &other); +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const CodeModel *m); +#endif + +class TypeInfo +{ +public: + TypeInfo() : flags(0), m_referenceType(NoReference) {} + + QStringList qualifiedName() const + { + return m_qualifiedName; + } + + void setQualifiedName(const QStringList &qualified_name) + { + m_qualifiedName = qualified_name; + } + + bool isConstant() const + { + return m_constant; + } + + void setConstant(bool is) + { + m_constant = is; + } + + bool isVolatile() const + { + return m_volatile; + } + + void setVolatile(bool is) + { + m_volatile = is; + } + + ReferenceType referenceType() const { return m_referenceType; } + void setReferenceType(ReferenceType r) { m_referenceType = r; } + + int indirections() const + { + return m_indirections; + } + + void setIndirections(int indirections) + { + m_indirections = indirections; + } + + bool isFunctionPointer() const + { + return m_functionPointer; + } + void setFunctionPointer(bool is) + { + m_functionPointer = is; + } + + QStringList arrayElements() const + { + return m_arrayElements; + } + void setArrayElements(const QStringList &arrayElements) + { + m_arrayElements = arrayElements; + } + + QVector arguments() const { return m_arguments; } + + void setArguments(const QVector &arguments); + + void addArgument(const TypeInfo &arg) + { + m_arguments.append(arg); + } + + bool operator==(const TypeInfo &other) const; + + bool operator!=(const TypeInfo &other) const + { + return !(*this == other); + } + + // ### arrays and templates?? + + QString toString() const; + + static TypeInfo combine(const TypeInfo &__lhs, const TypeInfo &__rhs); + static TypeInfo resolveType(TypeInfo const &__type, CodeModelItem __scope); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const; +#endif + +private: + static TypeInfo resolveType(CodeModelItem item, TypeInfo const &__type, CodeModelItem __scope); + + QStringList m_qualifiedName; + QStringList m_arrayElements; + QVector m_arguments; + + union { + uint flags; + + struct { + uint m_constant: 1; + uint m_volatile: 1; + uint m_functionPointer: 1; + uint m_indirections: 6; + uint m_padding: 23; + }; + }; + + ReferenceType m_referenceType; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const TypeInfo &t); +#endif + +class _CodeModelItem +{ + Q_DISABLE_COPY(_CodeModelItem) +public: + enum Kind { + /* These are bit-flags resembling inheritance */ + Kind_Scope = 0x1, + Kind_Namespace = 0x2 | Kind_Scope, + Kind_Member = 0x4, + Kind_Function = 0x8 | Kind_Member, + KindMask = 0xf, + + /* These are for classes that are not inherited from */ + FirstKind = 0x8, + Kind_Argument = 1 << FirstKind, + Kind_Class = 2 << FirstKind | Kind_Scope, + Kind_Enum = 3 << FirstKind, + Kind_Enumerator = 4 << FirstKind, + Kind_File = 5 << FirstKind | Kind_Namespace, + Kind_TemplateParameter = 7 << FirstKind, + Kind_TypeDef = 8 << FirstKind, + Kind_Variable = 9 << FirstKind | Kind_Member + }; + +public: + virtual ~_CodeModelItem(); + + int kind() const; + + QStringList qualifiedName() const; + + QString name() const; + void setName(const QString &name); + + QStringList scope() const; + void setScope(const QStringList &scope); + + QString fileName() const; + void setFileName(const QString &fileName); + + FileModelItem file() const; + + void getStartPosition(int *line, int *column); + void setStartPosition(int line, int column); + + void getEndPosition(int *line, int *column); + void setEndPosition(int line, int column); + + inline CodeModel *model() const { return m_model; } + +#ifndef QT_NO_DEBUG_STREAM + static void formatKind(QDebug &d, int k); + virtual void formatDebug(QDebug &d) const; +#endif + +protected: + explicit _CodeModelItem(CodeModel *model, int kind); + explicit _CodeModelItem(CodeModel *model, const QString &name, int kind); + +private: + CodeModel *m_model; + int m_kind; + int m_startLine; + int m_startColumn; + int m_endLine; + int m_endColumn; + QString m_name; + QString m_fileName; + QStringList m_scope; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const _CodeModelItem *t); +#endif + +class _ScopeModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(Scope) + + ~_ScopeModelItem(); + + ClassList classes() const { return m_classes; } + EnumList enums() const { return m_enums; } + inline FunctionList functions() const { return m_functions; } + TypeDefList typeDefs() const { return m_typeDefs; } + VariableList variables() const { return m_variables; } + + void addClass(ClassModelItem item); + void addEnum(EnumModelItem item); + void addFunction(FunctionModelItem item); + void addTypeDef(TypeDefModelItem item); + void addVariable(VariableModelItem item); + + ClassModelItem findClass(const QString &name) const; + EnumModelItem findEnum(const QString &name) const; + FunctionList findFunctions(const QString &name) const; + TypeDefModelItem findTypeDef(const QString &name) const; + VariableModelItem findVariable(const QString &name) const; + + void addEnumsDeclaration(const QString &enumsDeclaration); + QStringList enumsDeclarations() const { return m_enumsDeclarations; } + + FunctionModelItem declaredFunction(FunctionModelItem item); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +protected: + explicit _ScopeModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind) {} + explicit _ScopeModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _CodeModelItem(model, name, kind) {} + +#ifndef QT_NO_DEBUG_STREAM + void formatScopeItemsDebug(QDebug &d) const; +#endif + +private: + ClassList m_classes; + EnumList m_enums; + TypeDefList m_typeDefs; + VariableList m_variables; + FunctionList m_functions; + +private: + QStringList m_enumsDeclarations; +}; + +class _ClassModelItem: public _ScopeModelItem +{ +public: + DECLARE_MODEL_NODE(Class) + + explicit _ClassModelItem(CodeModel *model, int kind = __node_kind) + : _ScopeModelItem(model, kind), m_classType(CodeModel::Class) {} + explicit _ClassModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _ScopeModelItem(model, name, kind), m_classType(CodeModel::Class) {} + ~_ClassModelItem(); + + QStringList baseClasses() const; + + void setBaseClasses(const QStringList &baseClasses); + void addBaseClass(const QString &baseClass); + + TemplateParameterList templateParameters() const; + void setTemplateParameters(const TemplateParameterList &templateParameters); + + bool extendsClass(const QString &name) const; + + void setClassType(CodeModel::ClassType type); + CodeModel::ClassType classType() const; + + void addPropertyDeclaration(const QString &propertyDeclaration); + QStringList propertyDeclarations() const { return m_propertyDeclarations; } + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +private: + QStringList m_baseClasses; + TemplateParameterList m_templateParameters; + CodeModel::ClassType m_classType; + + QStringList m_propertyDeclarations; +}; + +class _NamespaceModelItem: public _ScopeModelItem +{ +public: + DECLARE_MODEL_NODE(Namespace) + + explicit _NamespaceModelItem(CodeModel *model, int kind = __node_kind) + : _ScopeModelItem(model, kind) {} + explicit _NamespaceModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _ScopeModelItem(model, name, kind) {} + ~_NamespaceModelItem(); + + NamespaceList namespaces() const { return m_namespaces; } + QSet uniqueNamespaces() const; + + void addNamespace(NamespaceModelItem item); + + NamespaceModelItem findNamespace(const QString &name) const; + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +private: + NamespaceList m_namespaces; +}; + +class _FileModelItem: public _NamespaceModelItem +{ +public: + DECLARE_MODEL_NODE(File) + + explicit _FileModelItem(CodeModel *model, int kind = __node_kind) + : _NamespaceModelItem(model, kind) {} + explicit _FileModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _NamespaceModelItem(model, name, kind) {} + ~_FileModelItem(); +}; + +class _ArgumentModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(Argument) + + explicit _ArgumentModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind), m_defaultValue(false) {} + explicit _ArgumentModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _CodeModelItem(model, name, kind), m_defaultValue(false) {} + ~_ArgumentModelItem(); + + TypeInfo type() const; + void setType(const TypeInfo &type); + + bool defaultValue() const; + void setDefaultValue(bool defaultValue); + + QString defaultValueExpression() const { return m_defaultValueExpression; } + void setDefaultValueExpression(const QString &expr) { m_defaultValueExpression = expr; } + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +private: + TypeInfo m_type; + QString m_defaultValueExpression; + bool m_defaultValue; +}; + +class _MemberModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(Member) + + explicit _MemberModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind), m_accessPolicy(CodeModel::Public), m_flags(0) {} + explicit _MemberModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _CodeModelItem(model, name, kind), m_accessPolicy(CodeModel::Public), m_flags(0) {} + ~_MemberModelItem(); + + bool isConstant() const; + void setConstant(bool isConstant); + + bool isVolatile() const; + void setVolatile(bool isVolatile); + + bool isStatic() const; + void setStatic(bool isStatic); + + bool isAuto() const; + void setAuto(bool isAuto); + + bool isFriend() const; + void setFriend(bool isFriend); + + bool isRegister() const; + void setRegister(bool isRegister); + + bool isExtern() const; + void setExtern(bool isExtern); + + bool isMutable() const; + void setMutable(bool isMutable); + + CodeModel::AccessPolicy accessPolicy() const; + void setAccessPolicy(CodeModel::AccessPolicy accessPolicy); + + TemplateParameterList templateParameters() const { return m_templateParameters; } + void setTemplateParameters(const TemplateParameterList &templateParameters) { m_templateParameters = templateParameters; } + + TypeInfo type() const; + void setType(const TypeInfo &type); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +private: + TemplateParameterList m_templateParameters; + TypeInfo m_type; + CodeModel::AccessPolicy m_accessPolicy; + union { + struct { + uint m_isConstant: 1; + uint m_isVolatile: 1; + uint m_isStatic: 1; + uint m_isAuto: 1; + uint m_isFriend: 1; + uint m_isRegister: 1; + uint m_isExtern: 1; + uint m_isMutable: 1; + }; + uint m_flags; + }; + +}; + +class _FunctionModelItem: public _MemberModelItem +{ +public: + DECLARE_MODEL_NODE(Function) + + explicit _FunctionModelItem(CodeModel *model, int kind = __node_kind) + : _MemberModelItem(model, kind), m_functionType(CodeModel::Normal), m_flags(0) {} + explicit _FunctionModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _MemberModelItem(model, name, kind), m_functionType(CodeModel::Normal), m_flags(0) {} + ~_FunctionModelItem(); + + ArgumentList arguments() const; + + void addArgument(ArgumentModelItem item); + + CodeModel::FunctionType functionType() const; + void setFunctionType(CodeModel::FunctionType functionType); + + bool isVirtual() const; + void setVirtual(bool isVirtual); + + bool isInline() const; + void setInline(bool isInline); + + bool isExplicit() const; + void setExplicit(bool isExplicit); + + bool isInvokable() const; // Qt + void setInvokable(bool isInvokable); // Qt + + bool isAbstract() const; + void setAbstract(bool isAbstract); + + bool isVariadics() const; + void setVariadics(bool isVariadics); + + bool isSimilar(FunctionModelItem other) const; + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +private: + ArgumentList m_arguments; + CodeModel::FunctionType m_functionType; + union { + struct { + uint m_isVirtual: 1; + uint m_isInline: 1; + uint m_isAbstract: 1; + uint m_isExplicit: 1; + uint m_isVariadics: 1; + uint m_isInvokable : 1; // Qt + }; + uint m_flags; + }; +}; + +class _VariableModelItem: public _MemberModelItem +{ +public: + DECLARE_MODEL_NODE(Variable) + + explicit _VariableModelItem(CodeModel *model, int kind = __node_kind) + : _MemberModelItem(model, kind) {} + explicit _VariableModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _MemberModelItem(model, name, kind) {} +}; + +class _TypeDefModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(TypeDef) + + explicit _TypeDefModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind) {} + explicit _TypeDefModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _CodeModelItem(model, name, kind) {} + + TypeInfo type() const; + void setType(const TypeInfo &type); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +private: + TypeInfo m_type; +}; + +class _EnumModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(Enum) + + explicit _EnumModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind), m_accessPolicy(CodeModel::Public), m_anonymous(false) {} + explicit _EnumModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _CodeModelItem(model, name, kind), m_accessPolicy(CodeModel::Public), m_anonymous(false) {} + ~_EnumModelItem(); + + CodeModel::AccessPolicy accessPolicy() const; + void setAccessPolicy(CodeModel::AccessPolicy accessPolicy); + + EnumeratorList enumerators() const; + void addEnumerator(EnumeratorModelItem item); + bool isAnonymous() const; + void setAnonymous(bool anonymous); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +private: + CodeModel::AccessPolicy m_accessPolicy; + EnumeratorList m_enumerators; + bool m_anonymous; +}; + +class _EnumeratorModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(Enumerator) + + explicit _EnumeratorModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind) {} + explicit _EnumeratorModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _CodeModelItem(model, name, kind) {} + ~_EnumeratorModelItem(); + + QString value() const; + void setValue(const QString &value); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +private: + QString m_value; +}; + +class _TemplateParameterModelItem: public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(TemplateParameter) + + explicit _TemplateParameterModelItem(CodeModel *model, int kind = __node_kind) + : _CodeModelItem(model, kind), m_defaultValue(false) {} + explicit _TemplateParameterModelItem(CodeModel *model, const QString &name, int kind = __node_kind) + : _CodeModelItem(model, name, kind), m_defaultValue(false) {} + ~_TemplateParameterModelItem(); + + TypeInfo type() const; + void setType(const TypeInfo &type); + + bool defaultValue() const; + void setDefaultValue(bool defaultValue); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +private: + TypeInfo m_type; + bool m_defaultValue; +}; + +#endif // CODEMODEL_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h b/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h new file mode 100644 index 000000000..aa8b051d8 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 CODEMODEL_ENUMS_H +#define CODEMODEL_ENUMS_H + +enum ReferenceType { + NoReference, + LValueReference, + RValueReference +}; + +#endif // CODEMODEL_ENUMS_H diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h b/sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h new file mode 100644 index 000000000..d5a9f2850 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2002-2005 Roberto Raggi +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 CODEMODEL_FWD_H +#define CODEMODEL_FWD_H + +#include +#include + +// forward declarations +class CodeModel; +class _ArgumentModelItem; +class _ClassModelItem; +class _CodeModelItem; +class _EnumModelItem; +class _EnumeratorModelItem; +class _FileModelItem; +class _FunctionModelItem; +class _NamespaceModelItem; +class _ScopeModelItem; +class _TemplateParameterModelItem; +class _TypeDefModelItem; +class _VariableModelItem; +class _MemberModelItem; +class TypeInfo; + +typedef QSharedPointer<_ArgumentModelItem> ArgumentModelItem; +typedef QSharedPointer<_ClassModelItem> ClassModelItem; +typedef QSharedPointer<_CodeModelItem> CodeModelItem; +typedef QSharedPointer<_EnumModelItem> EnumModelItem; +typedef QSharedPointer<_EnumeratorModelItem> EnumeratorModelItem; +typedef QSharedPointer<_FileModelItem> FileModelItem; +typedef QSharedPointer<_FunctionModelItem> FunctionModelItem; +typedef QSharedPointer<_NamespaceModelItem> NamespaceModelItem; +typedef QSharedPointer<_ScopeModelItem> ScopeModelItem; +typedef QSharedPointer<_TemplateParameterModelItem> TemplateParameterModelItem; +typedef QSharedPointer<_TypeDefModelItem> TypeDefModelItem; +typedef QSharedPointer<_VariableModelItem> VariableModelItem; +typedef QSharedPointer<_MemberModelItem> MemberModelItem; + +typedef QVector ArgumentList; +typedef QVector ClassList; +typedef QVector ItemList; +typedef QVector EnumList; +typedef QVector EnumeratorList; +typedef QVector FileList; +typedef QVector FunctionList; +typedef QVector NamespaceList; +typedef QVector ScopeList; +typedef QVector TemplateParameterList; +typedef QVector TypeDefList; +typedef QVector VariableList; +typedef QVector MemberList; + +#endif // CODEMODEL_FWD_H diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.cpp b/sources/shiboken2/ApiExtractor/qtdocparser.cpp new file mode 100644 index 000000000..00e2384f0 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/qtdocparser.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "qtdocparser.h" +#include "abstractmetalang.h" +#include "reporthandler.h" +#include "typesystem.h" + +#include +#include +#include +#include + +Documentation QtDocParser::retrieveModuleDocumentation() +{ + return retrieveModuleDocumentation(packageName()); +} + +void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) +{ + if (!metaClass) + return; + + QString scope = metaClass->name(); + const AbstractMetaClass* context = metaClass->enclosingClass(); + while(context) { + if (context->enclosingClass() == 0) + break; + context = context->enclosingClass(); + } + + QString filename = metaClass->qualifiedCppName().toLower(); + filename.replace(QLatin1String("::"), QLatin1String("-")); + QString sourceFile = documentationDataDirectory() + QLatin1Char('/') + + filename + QLatin1String(".xml"); + if (metaClass->enclosingClass()) + sourceFile.replace(QLatin1String("::"), QLatin1String("-")); + + if (!QFile::exists(sourceFile)) { + qCWarning(lcShiboken).noquote().nospace() + << "Can't find qdoc3 file for class " << metaClass->name() << ", tried: " + << QDir::toNativeSeparators(sourceFile); + return; + } + + QXmlQuery xquery; + xquery.setFocus(QUrl(sourceFile)); + + QString className = metaClass->name(); + + // Class/Namespace documentation + QString type = metaClass->isNamespace() ? QLatin1String("namespace") : QLatin1String("class"); + QString query = QLatin1String("/WebXML/document/") + type + QLatin1String("[@name=\"") + + className + QLatin1String("\"]/description"); + + DocModificationList signedModifs, classModifs; + const DocModificationList &mods = metaClass->typeEntry()->docModifications(); + for (const DocModification &docModif : mods) { + if (docModif.signature().isEmpty()) + classModifs.append(docModif); + else + signedModifs.append(docModif); + } + + Documentation doc(getDocumentation(xquery, query, classModifs)); + metaClass->setDocumentation(doc); + + + //Functions Documentation + const AbstractMetaFunctionList &funcs = metaClass->functionsInTargetLang(); + for (AbstractMetaFunction *func : funcs) { + if (!func || func->isPrivate()) + continue; + + QString query = QLatin1String("/WebXML/document/") + type + + QLatin1String("[@name=\"") + className + QLatin1String("\"]"); + // properties + if (func->isPropertyReader() || func->isPropertyWriter() || func->isPropertyResetter()) { + query += QLatin1String("/property[@name=\"") + func->propertySpec()->name() + + QLatin1String("\"]"); + } else { // normal methods + QString isConst = func->isConstant() ? QLatin1String("true") : QLatin1String("false"); + query += QLatin1String("/function[@name=\"") + func->originalName() + + QLatin1String("\" and count(parameter)=") + + QString::number(func->arguments().count()) + + QLatin1String(" and @const=\"") + isConst + QLatin1String("\"]"); + + const AbstractMetaArgumentList &arguments = func->arguments(); + for (int i = 0, size = arguments.size(); i < size; ++i) { + const AbstractMetaArgument *arg = arguments.at(i); + QString type = arg->type()->name(); + + if (arg->type()->isConstant()) + type.prepend(QLatin1String("const ")); + + if (arg->type()->referenceType() == LValueReference) { + type += QLatin1String(" &"); + } else if (arg->type()->referenceType() == RValueReference) { + type += QLatin1String(" &&"); + } else if (arg->type()->indirections()) { + type += QLatin1Char(' '); + for (int j = 0, max = arg->type()->indirections(); j < max; ++j) + type += QLatin1Char('*'); + } + query += QLatin1String("/parameter[") + QString::number(i + 1) + + QLatin1String("][@left=\"") + type + QLatin1String("\"]/.."); + } + } + query += QLatin1String("/description"); + DocModificationList funcModifs; + for (const DocModification &funcModif : qAsConst(signedModifs)) { + if (funcModif.signature() == func->minimalSignature()) + funcModifs.append(funcModif); + } + doc.setValue(getDocumentation(xquery, query, funcModifs)); + func->setDocumentation(doc); + } +#if 0 + // Fields + const AbstractMetaFieldList &fields = metaClass->fields(); + for (AbstractMetaField *field : fields) { + if (field->isPrivate()) + return; + + QString query = "/doxygen/compounddef/sectiondef/memberdef/name[text()=\"" + field->name() + "\"]/.."; + Documentation doc = getDocumentation(DocModificationList(), xquery, query); + field->setDocumentation(doc); + } +#endif + // Enums + const AbstractMetaEnumList &enums = metaClass->enums(); + for (AbstractMetaEnum *meta_enum : enums) { + QString query = QLatin1String("/WebXML/document/") + type + + QLatin1String("[@name=\"") + + className + QLatin1String("\"]/enum[@name=\"") + + meta_enum->name() + QLatin1String("\"]/description"); + doc.setValue(getDocumentation(xquery, query, DocModificationList())); + meta_enum->setDocumentation(doc); + } +} + +Documentation QtDocParser::retrieveModuleDocumentation(const QString& name) +{ + // TODO: This method of acquiring the module name supposes that the target language uses + // dots as module separators in package names. Improve this. + QString moduleName = name; + moduleName.remove(0, name.lastIndexOf(QLatin1Char('.')) + 1); + QString sourceFile = documentationDataDirectory() + QLatin1Char('/') + + moduleName.toLower() + QLatin1String(".xml"); + + if (!QFile::exists(sourceFile)) { + qCWarning(lcShiboken).noquote().nospace() + << "Can't find qdoc3 file for module " << name << ", tried: " + << QDir::toNativeSeparators(sourceFile); + return Documentation(); + } + + QXmlQuery xquery; + xquery.setFocus(QUrl(sourceFile)); + + // Module documentation + QString query = QLatin1String("/WebXML/document/page[@name=\"") + moduleName + QLatin1String("\"]/description"); + return Documentation(getDocumentation(xquery, query, DocModificationList())); +} diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.h b/sources/shiboken2/ApiExtractor/qtdocparser.h new file mode 100644 index 000000000..f6bd479cd --- /dev/null +++ b/sources/shiboken2/ApiExtractor/qtdocparser.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 QTDOCPARSER_H +#define QTDOCPARSER_H + +#include "docparser.h" + +class QtDocParser : public DocParser +{ +public: + QtDocParser() {} + void fillDocumentation(AbstractMetaClass* metaClass) override; + Documentation retrieveModuleDocumentation() override; + Documentation retrieveModuleDocumentation(const QString& name) override; +}; + +#endif // QTDOCPARSER_H + diff --git a/sources/shiboken2/ApiExtractor/reporthandler.cpp b/sources/shiboken2/ApiExtractor/reporthandler.cpp new file mode 100644 index 000000000..8abea42c6 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/reporthandler.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "reporthandler.h" +#include "typesystem.h" +#include "typedatabase.h" +#include +#include +#include +#include + +#if _WINDOWS || NOCOLOR + #define COLOR_END "" + #define COLOR_WHITE "" + #define COLOR_YELLOW "" + #define COLOR_GREEN "" +#else + #define COLOR_END "\033[0m" + #define COLOR_WHITE "\033[1;37m" + #define COLOR_YELLOW "\033[1;33m" + #define COLOR_GREEN "\033[0;32m" +#endif + +static bool m_silent = false; +static int m_warningCount = 0; +static int m_suppressedCount = 0; +static ReportHandler::DebugLevel m_debugLevel = ReportHandler::NoDebug; +static QSet m_reportedWarnings; +static QString m_progressBuffer; +static int m_step_size = 0; +static int m_step = -1; +static int m_step_warning = 0; + +Q_LOGGING_CATEGORY(lcShiboken, "qt.shiboken") + +static void printProgress() +{ + std::printf("%s", m_progressBuffer.toUtf8().data()); + std::fflush(stdout); + m_progressBuffer.clear(); +} + +void ReportHandler::install() +{ + qInstallMessageHandler(ReportHandler::messageOutput); +} + +ReportHandler::DebugLevel ReportHandler::debugLevel() +{ + return m_debugLevel; +} + +void ReportHandler::setDebugLevel(ReportHandler::DebugLevel level) +{ + m_debugLevel = level; +} + +int ReportHandler::suppressedCount() +{ + return m_suppressedCount; +} + +int ReportHandler::warningCount() +{ + return m_warningCount; +} + +void ReportHandler::setProgressReference(int max) +{ + m_step_size = max; + m_step = -1; +} + +bool ReportHandler::isSilent() +{ + return m_silent; +} + +void ReportHandler::setSilent(bool silent) +{ + m_silent = silent; +} + +void ReportHandler::messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &text) +{ + if (type == QtWarningMsg) { + if (m_silent || m_reportedWarnings.contains(text)) + return; + const TypeDatabase *db = TypeDatabase::instance(); + if (db && db->isSuppressedWarning(text)) { + ++m_suppressedCount; + return; + } + ++m_warningCount; + ++m_step_warning; + m_reportedWarnings.insert(text); + } + fprintf(stderr, "%s\n", qPrintable(qFormatLogMessage(type, context, text))); +} + +void ReportHandler::progress(const QString& str, ...) +{ + if (m_silent) + return; + + if (m_step == -1) { + QTextStream buf(&m_progressBuffer); + buf.setFieldWidth(45); + buf.setFieldAlignment(QTextStream::AlignLeft); + buf << str; + printProgress(); + m_step = 0; + } + m_step++; + if (m_step >= m_step_size) { + if (m_step_warning == 0) { + m_progressBuffer = QLatin1String("[" COLOR_GREEN "OK" COLOR_END "]\n"); + } else { + m_progressBuffer = QLatin1String("[" COLOR_YELLOW "WARNING" COLOR_END "]\n"); + } + printProgress(); + m_step_warning = 0; + } +} diff --git a/sources/shiboken2/ApiExtractor/reporthandler.h b/sources/shiboken2/ApiExtractor/reporthandler.h new file mode 100644 index 000000000..6896d6e86 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/reporthandler.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 REPORTHANDLER_H +#define REPORTHANDLER_H + +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(lcShiboken) + +class ReportHandler +{ +public: + enum DebugLevel { NoDebug, SparseDebug, MediumDebug, FullDebug }; + + static void install(); + + static DebugLevel debugLevel(); + static void setDebugLevel(DebugLevel level); + + static int warningCount(); + + static int suppressedCount(); + + template + static void setProgressReference(T collection) + { + setProgressReference(collection.count()); + } + + static void setProgressReference(int max); + + static void progress(const QString &str, ...); + + static bool isDebug(DebugLevel level) + { return debugLevel() >= level; } + + static bool isSilent(); + static void setSilent(bool silent); + +private: + static void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg); +}; + +#endif // REPORTHANDLER_H diff --git a/sources/shiboken2/ApiExtractor/symbols.filter b/sources/shiboken2/ApiExtractor/symbols.filter new file mode 100644 index 000000000..af6c744dd --- /dev/null +++ b/sources/shiboken2/ApiExtractor/symbols.filter @@ -0,0 +1,7 @@ +{ +local: +_ZSt*; +_ZNSt*; +_ZNSs*; +_ZNKSt*; +}; diff --git a/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt b/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt new file mode 100644 index 000000000..860a37d9d --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt @@ -0,0 +1,74 @@ +find_package(Qt5Core) +find_package(Qt5Gui) +find_package(Qt5Test) +find_package(Qt5Xml) +find_package(Qt5XmlPatterns) + +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") + endif () + include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${apiextractor_SOURCE_DIR} + ${Qt5Test_INCLUDE_DIRS} + ) + link_directories(${APIEXTRACTOR_EXTRA_LINK_DIRECTORIES}) + target_link_libraries(${testname} + ${Qt5XmlPatterns_LIBRARIES} + ${Qt5Test_LIBRARIES} + ${Qt5Core_LIBRARIES} + ${Qt5Gui_LIBRARIES} + apiextractor) + add_test(${testname} ${testname}) + if (INSTALL_TESTS) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${testname} + DESTINATION share/apiextractor${apiextractor_SUFFIX}/tests) + endif() +endmacro(declare_test testname) + +declare_test(testabstractmetaclass) +declare_test(testabstractmetatype) +declare_test(testaddfunction) +declare_test(testarrayargument) +declare_test(testcodeinjection) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/utf8code.txt" + "${CMAKE_CURRENT_BINARY_DIR}/utf8code.txt" COPYONLY) +declare_test(testcontainer) +declare_test(testconversionoperator) +declare_test(testconversionruletag) +declare_test(testctorinformation) +declare_test(testdroptypeentries) +declare_test(testdtorinformation) +declare_test(testenum) +declare_test(testextrainclude) +declare_test(testfunctiontag) +declare_test(testimplicitconversions) +declare_test(testinserttemplate) +declare_test(testmodifyfunction) +declare_test(testmultipleinheritance) +declare_test(testnamespace) +declare_test(testnestedtypes) +declare_test(testnumericaltypedef) +declare_test(testprimitivetypetag) +declare_test(testrefcounttag) +declare_test(testreferencetopointer) +declare_test(testremovefield) +declare_test(testremoveimplconv) +declare_test(testremoveoperatormethod) +declare_test(testresolvetype) +declare_test(testreverseoperators) +declare_test(testtemplates) +declare_test(testtoposort) +declare_test(testvaluetypedefaultctortag) +declare_test(testvoidarg) +declare_test(testtyperevision) +if (NOT DISABLE_DOCSTRINGS) + declare_test(testmodifydocumentation) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/a.xml" + "${CMAKE_CURRENT_BINARY_DIR}/a.xml" COPYONLY) +endif() + diff --git a/sources/shiboken2/ApiExtractor/tests/a.xml b/sources/shiboken2/ApiExtractor/tests/a.xml new file mode 100644 index 000000000..1c6d62a17 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/a.xml @@ -0,0 +1,13 @@ + + + + + + oi + Paragraph number 1 + Paragraph number 2 + Paragraph number 3 + + + + diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp new file mode 100644 index 000000000..423b8d9ff --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp @@ -0,0 +1,527 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testabstractmetaclass.h" +#include "abstractmetabuilder.h" +#include +#include "testutil.h" +#include +#include + +void TestAbstractMetaClass::testClassName() +{ + const char* cppCode ="class ClassName {};"; + const char* xmlCode = ""; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 1); + QCOMPARE(classes[0]->name(), QLatin1String("ClassName")); +} + +void TestAbstractMetaClass::testClassNameUnderNamespace() +{ + const char* cppCode ="namespace Namespace { class ClassName {}; }\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); // 1 namespace + 1 class + if (classes.first()->name() != QLatin1String("ClassName")) + qSwap(classes[0], classes[1]); + + QCOMPARE(classes[0]->name(), QLatin1String("ClassName")); + QCOMPARE(classes[0]->qualifiedCppName(), QLatin1String("Namespace::ClassName")); + QCOMPARE(classes[1]->name(), QLatin1String("Namespace")); + QVERIFY(classes[1]->isNamespace()); + + // Check ctors info + QVERIFY(classes[0]->hasConstructors()); + QCOMPARE(classes[0]->functions().size(), 2); // default ctor + copy ctor + + AbstractMetaFunctionList ctors = classes[0]->queryFunctions(AbstractMetaClass::Constructors); + QCOMPARE(ctors.size(), 2); + if (ctors.first()->minimalSignature() != QLatin1String("ClassName()")) + qSwap(ctors[0], ctors[1]); + + QCOMPARE(ctors[0]->arguments().size(), 0); + QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("ClassName()")); + QCOMPARE(ctors[1]->arguments().size(), 1); + QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("ClassName(Namespace::ClassName)")); + + QVERIFY(!classes[0]->hasPrivateDestructor()); + QVERIFY(classes[0]->hasCloneOperator()); // implicit default copy ctor + QVERIFY(!classes[0]->hasHashFunction()); + + // This method is buggy and nobody wants to fix it or needs it fixed :-/ + // QVERIFY(classes[0]->hasNonPrivateConstructor()); +} + +void TestAbstractMetaClass::testVirtualMethods() +{ + const char* cppCode ="\ + class A {\n\ + public:\n\ + virtual int pureVirtual() const = 0;\n\ + };\n\ + class B : public A {};\n\ + class C : public B {\n\ + public:\n\ + int pureVirtual() const { return 0; }\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 3); + AbstractMetaClass* a = AbstractMetaClass::findClass(classes, QLatin1String("A")); + AbstractMetaClass* b = AbstractMetaClass::findClass(classes, QLatin1String("B")); + AbstractMetaClass* c = AbstractMetaClass::findClass(classes, QLatin1String("C")); + + AbstractMetaClass* no_class = 0; + + QCOMPARE(a->baseClass(), no_class); + QCOMPARE(b->baseClass(), a); + QCOMPARE(c->baseClass(), b); + + QCOMPARE(a->functions().size(), 2); // default ctor + the pure virtual method + QCOMPARE(b->functions().size(), 2); + QCOMPARE(c->functions().size(), 2); + + // implementing class, ownclass, declaringclass + AbstractMetaFunction* ctorA = a->queryFunctions(AbstractMetaClass::Constructors).first(); + AbstractMetaFunction* ctorB = b->queryFunctions(AbstractMetaClass::Constructors).first(); + AbstractMetaFunction* ctorC = c->queryFunctions(AbstractMetaClass::Constructors).first(); + QVERIFY(ctorA->isConstructor()); + QVERIFY(!ctorA->isVirtual()); + QVERIFY(ctorB->isConstructor()); + QVERIFY(!ctorB->isVirtual()); + QVERIFY(ctorC->isConstructor()); + QVERIFY(!ctorC->isVirtual()); + QCOMPARE(ctorA->implementingClass(), a); + QCOMPARE(ctorA->ownerClass(), a); + QCOMPARE(ctorA->declaringClass(), a); + + QCOMPARE(a->virtualFunctions().size(), 1); // Add a pureVirtualMethods method !? + QCOMPARE(b->virtualFunctions().size(), 1); + QCOMPARE(c->virtualFunctions().size(), 1); + + AbstractMetaFunction* funcA = a->virtualFunctions().first(); + AbstractMetaFunction* funcB = b->virtualFunctions().first(); + AbstractMetaFunction* funcC = c->virtualFunctions().first(); + + QCOMPARE(funcA->ownerClass(), a); + QCOMPARE(funcB->ownerClass(), b); + QCOMPARE(funcC->ownerClass(), c); + + QCOMPARE(funcA->declaringClass(), a); + QCOMPARE(funcB->declaringClass(), a); + QCOMPARE(funcC->declaringClass(), a); + + // The next two tests could return null, because it makes more sense. + // But we have too many code written relying on this behaviour where + // implementingClass is equals to declaringClass on pure virtual functions + QCOMPARE(funcA->implementingClass(), a); + QCOMPARE(funcB->implementingClass(), a); + QCOMPARE(funcC->implementingClass(), c); +} + +void TestAbstractMetaClass::testDefaultValues() +{ + const char* cppCode ="\ + struct A {\n\ + class B {};\n\ + void method(B b = B());\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classA->queryFunctionsByName(QLatin1String("method")).count(), 1); + AbstractMetaFunction* method = classA->queryFunctionsByName(QLatin1String("method")).first(); + AbstractMetaArgument* arg = method->arguments().first(); + QCOMPARE(arg->defaultValueExpression(), arg->originalDefaultValueExpression()); +} + +void TestAbstractMetaClass::testModifiedDefaultValues() +{ + const char* cppCode ="\ + struct A {\n\ + class B {};\n\ + void method(B b = B());\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classA->queryFunctionsByName(QLatin1String("method")).count(), 1); + AbstractMetaFunction* method = classA->queryFunctionsByName(QLatin1String("method")).first(); + AbstractMetaArgument* arg = method->arguments().first(); + QCOMPARE(arg->defaultValueExpression(), QLatin1String("Hello")); + QCOMPARE(arg->originalDefaultValueExpression(), QLatin1String("A::B()")); +} + +void TestAbstractMetaClass::testInnerClassOfAPolymorphicOne() +{ + const char* cppCode ="\ + struct A {\n\ + class B {};\n\ + virtual void method();\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QVERIFY(classA->isPolymorphic()); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("A::B")); + QVERIFY(classB); + QVERIFY(!classB->isPolymorphic()); +} + +void TestAbstractMetaClass::testForwardDeclaredInnerClass() +{ + const char cppCode[] ="\ + class A {\n\ + class B;\n\ + };\n\ + class A::B {\n\ + public:\n\ + void foo();\n\ + };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("A::B")); + QVERIFY(classB); + const AbstractMetaFunction *fooF = classB->findFunction(QLatin1String("foo")); + QVERIFY(fooF); +} + +void TestAbstractMetaClass::testSpecialFunctions() +{ + const char cppCode[] ="\ + struct A {\n\ + A();\n\ + A(const A&);\n\ + A &operator=(const A&);\n\ + };\n\ + struct B {\n\ + B();\n\ + B(const B &);\n\ + B &operator=(B);\n\ + };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + AbstractMetaFunctionList ctors = classA->queryFunctions(AbstractMetaClass::Constructors); + QCOMPARE(ctors.size(), 2); + QCOMPARE(ctors.first()->functionType(), AbstractMetaFunction::ConstructorFunction); + QCOMPARE(ctors.at(1)->functionType(), AbstractMetaFunction::CopyConstructorFunction); + AbstractMetaFunctionList assigmentOps = classA->queryFunctionsByName(QLatin1String("operator=")); + QCOMPARE(assigmentOps.size(), 1); + QCOMPARE(assigmentOps.first()->functionType(), AbstractMetaFunction::AssignmentOperatorFunction); + + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + ctors = classB->queryFunctions(AbstractMetaClass::Constructors); + QCOMPARE(ctors.size(), 2); + QCOMPARE(ctors.first()->functionType(), AbstractMetaFunction::ConstructorFunction); + QCOMPARE(ctors.at(1)->functionType(), AbstractMetaFunction::CopyConstructorFunction); + assigmentOps = classA->queryFunctionsByName(QLatin1String("operator=")); + QCOMPARE(assigmentOps.size(), 1); + QCOMPARE(assigmentOps.first()->functionType(), AbstractMetaFunction::AssignmentOperatorFunction); +} + +void TestAbstractMetaClass::testClassDefaultConstructors() +{ + const char* cppCode ="\ + struct A {};\n\ + \n\ + struct B {\n\ + B();\n\ + private: \n\ + B(const B&);\n\ + };\n\ + \n\ + struct C {\n\ + C(const C&);\n\ + };\n\ + \n\ + struct D {\n\ + private: \n\ + D(const D&);\n\ + };\n\ + \n\ + struct E {\n\ + private: \n\ + ~E();\n\ + };\n\ + \n\ + struct F {\n\ + F(int, int);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 6); + + AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->functions().size(), 2); + + AbstractMetaFunctionList ctors = classA->queryFunctions(AbstractMetaClass::Constructors); + QCOMPARE(ctors.size(), 2); + if (ctors.first()->minimalSignature() != QLatin1String("A()")) + qSwap(ctors[0], ctors[1]); + + QCOMPARE(ctors[0]->arguments().size(), 0); + QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("A()")); + QCOMPARE(ctors[1]->arguments().size(), 1); + QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("A(A)")); + + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + QCOMPARE(classB->functions().size(), 2); + QCOMPARE(classB->functions().first()->minimalSignature(), QLatin1String("B()")); + + AbstractMetaClass* classC = AbstractMetaClass::findClass(classes, QLatin1String("C")); + QVERIFY(classC); + QCOMPARE(classC->functions().size(), 1); + QCOMPARE(classC->functions().first()->minimalSignature(), QLatin1String("C(C)")); + + AbstractMetaClass* classD = AbstractMetaClass::findClass(classes, QLatin1String("D")); + QVERIFY(classD); + QCOMPARE(classD->functions().size(), 1); + QCOMPARE(classD->functions().first()->minimalSignature(), QLatin1String("D(D)")); + QVERIFY(classD->functions().first()->isPrivate()); + + AbstractMetaClass* classE = AbstractMetaClass::findClass(classes, QLatin1String("E")); + QVERIFY(classE); + QVERIFY(classE->hasPrivateDestructor()); + QCOMPARE(classE->functions().size(), 0); + + AbstractMetaClass* classF = AbstractMetaClass::findClass(classes, QLatin1String("F")); + QVERIFY(classF); + + ctors = classF->queryFunctions(AbstractMetaClass::Constructors); + QCOMPARE(ctors.size(), 2); + if (ctors.first()->minimalSignature() != QLatin1String("F(int,int)")) + qSwap(ctors[0], ctors[1]); + + QCOMPARE(ctors[0]->arguments().size(), 2); + QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("F(int,int)")); + QCOMPARE(ctors[1]->arguments().size(), 1); + QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("F(F)")); +} + +void TestAbstractMetaClass::testClassInheritedDefaultConstructors() +{ + const char* cppCode ="\ + struct A {\n\ + A();\n\ + private: \n\ + A(const A&);\n\ + };\n\ + struct B : public A {};\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + + AbstractMetaFunctionList ctors = classA->queryFunctions(AbstractMetaClass::Constructors); + QCOMPARE(ctors.size(), 2); + if (ctors.first()->minimalSignature() != QLatin1String("A()")) + qSwap(ctors[0], ctors[1]); + + QCOMPARE(ctors[0]->arguments().size(), 0); + QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("A()")); + QCOMPARE(ctors[1]->arguments().size(), 1); + QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("A(A)")); + QVERIFY(ctors[1]->isPrivate()); + + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + + ctors = classB->queryFunctions(AbstractMetaClass::Constructors); + QCOMPARE(ctors.size(), 1); + QCOMPARE(ctors.first()->arguments().size(), 0); + QCOMPARE(ctors.first()->minimalSignature(), QLatin1String("B()")); +} + +void TestAbstractMetaClass::testAbstractClassDefaultConstructors() +{ + const char* cppCode ="\ + struct A {\n\ + virtual void method() = 0;\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 1); + AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + + AbstractMetaFunctionList ctors = classA->queryFunctions(AbstractMetaClass::Constructors); + QCOMPARE(ctors.size(), 1); + QCOMPARE(ctors.first()->arguments().size(), 0); + QCOMPARE(ctors.first()->minimalSignature(), QLatin1String("A()")); +} + +void TestAbstractMetaClass::testObjectTypesMustNotHaveCopyConstructors() +{ + const char* cppCode ="struct A {};\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 1); + AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + + AbstractMetaFunctionList ctors = classA->queryFunctions(AbstractMetaClass::Constructors); + QCOMPARE(ctors.size(), 1); + QCOMPARE(ctors.first()->arguments().size(), 0); + QCOMPARE(ctors.first()->minimalSignature(), QLatin1String("A()")); +} + +void TestAbstractMetaClass::testIsPolymorphic() +{ + const char* cppCode = "\ + class A\n\ + {\n\ + public:\n\ + A();\n\ + inline bool abc() const {}\n\ + };\n\ + \n\ + class B : public A\n\ + {\n\ + public:\n\ + B();\n\ + inline bool abc() const {}\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + AbstractMetaClass* b = AbstractMetaClass::findClass(classes, QLatin1String("A")); + + QVERIFY(!b->isPolymorphic()); + AbstractMetaClass* a = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(!a->isPolymorphic()); +} + +QTEST_APPLESS_MAIN(TestAbstractMetaClass) diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.h b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.h new file mode 100644 index 000000000..811bf5a10 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTABSTRACTMETACLASS_H +#define TESTABSTRACTMETACLASS_H + +#include + +class AbstractMetaBuilder; + +class TestAbstractMetaClass : public QObject +{ + Q_OBJECT +private slots: + void testClassName(); + void testClassNameUnderNamespace(); + void testVirtualMethods(); + void testDefaultValues(); + void testModifiedDefaultValues(); + void testInnerClassOfAPolymorphicOne(); + void testForwardDeclaredInnerClass(); + void testSpecialFunctions(); + void testClassDefaultConstructors(); + void testClassInheritedDefaultConstructors(); + void testAbstractClassDefaultConstructors(); + void testObjectTypesMustNotHaveCopyConstructors(); + void testIsPolymorphic(); +}; + +#endif // TESTABSTRACTMETACLASS_H diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp new file mode 100644 index 000000000..1d52c1e41 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testabstractmetatype.h" +#include +#include "testutil.h" +#include +#include + +void TestAbstractMetaType::testConstCharPtrType() +{ + const char* cppCode ="const char* justAtest();\n"; + const char* xmlCode = "\n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + QCOMPARE(builder->globalFunctions().size(), 1); + AbstractMetaFunction* func = builder->globalFunctions().first(); + AbstractMetaType* rtype = func->type(); + // Test properties of const char* + QVERIFY(rtype); + QCOMPARE(rtype->package(), QLatin1String("Foo")); + QCOMPARE(rtype->name(), QLatin1String("char")); + QVERIFY(rtype->isConstant()); + QVERIFY(!rtype->isArray()); + QVERIFY(!rtype->isContainer()); + QVERIFY(!rtype->isObject()); + QVERIFY(!rtype->isPrimitive()); // const char* differs from char, so it's not considered a primitive type by apiextractor + QVERIFY(rtype->isNativePointer()); + QVERIFY(!rtype->isQObject()); + QCOMPARE(rtype->referenceType(), NoReference); + QVERIFY(!rtype->isValue()); + QVERIFY(!rtype->isValuePointer()); +} + +void TestAbstractMetaType::testApiVersionSupported() +{ + const char* cppCode ="class foo {}; class foo2 {};\n\ + void justAtest(); void justAtest3();\n"; + const char* xmlCode = "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false, "1.0")); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.size(), 2); + + + AbstractMetaFunctionList functions = builder->globalFunctions(); + QCOMPARE(functions.size(), 2); +} + + +void TestAbstractMetaType::testApiVersionNotSupported() +{ + const char* cppCode ="class object {};\n"; + const char* xmlCode = "\n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, true, "0.1")); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.size(), 1); +} + +void TestAbstractMetaType::testCharType() +{ + const char* cppCode ="char justAtest(); class A {};\n"; + const char* xmlCode = "\n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.size(), 1); + QCOMPARE(classes.first()->package(), QLatin1String("Foo")); + + AbstractMetaFunctionList functions = builder->globalFunctions(); + QCOMPARE(functions.size(), 1); + AbstractMetaFunction* func = functions.first(); + AbstractMetaType* rtype = func->type(); + // Test properties of const char* + QVERIFY(rtype); + QCOMPARE(rtype->package(), QLatin1String("Foo")); + QCOMPARE(rtype->name(), QLatin1String("char")); + QVERIFY(!rtype->isConstant()); + QVERIFY(!rtype->isArray()); + QVERIFY(!rtype->isContainer()); + QVERIFY(!rtype->isObject()); + QVERIFY(rtype->isPrimitive()); + QVERIFY(!rtype->isNativePointer()); + QVERIFY(!rtype->isQObject()); + QCOMPARE(rtype->referenceType(), NoReference); + QVERIFY(!rtype->isValue()); + QVERIFY(!rtype->isValuePointer()); +} + +void TestAbstractMetaType::testTypedef() +{ + const char* cppCode ="\ + struct A {\n\ + void someMethod();\n\ + };\n\ + typedef A B;\n\ + typedef B C;\n"; + const char* xmlCode = "\n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.size(), 1); + const AbstractMetaClass *c = AbstractMetaClass::findClass(classes, QLatin1String("C")); + QVERIFY(c); + QVERIFY(c->isTypeDef()); +} + +void TestAbstractMetaType::testTypedefWithTemplates() +{ + const char* cppCode ="\ + template\n\ + class A {};\n\ + \n\ + class B {};\n\ + typedef A C;\n\ + \n\ + void func(C c);\n"; + const char* xmlCode = "\n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.size(), 1); + AbstractMetaFunctionList functions = builder->globalFunctions(); + QCOMPARE(functions.count(), 1); + AbstractMetaFunction* function = functions.first(); + AbstractMetaArgumentList args = function->arguments(); + QCOMPARE(args.count(), 1); + AbstractMetaArgument* arg = args.first(); + AbstractMetaType* metaType = arg->type(); + QCOMPARE(metaType->cppSignature(), QLatin1String("A")); +} + + +void TestAbstractMetaType::testObjectTypeUsedAsValue() +{ + const char* cppCode ="\ + class A {\n\ + void method(A);\n\ + };\n"; + const char* xmlCode = "\n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.size(), 1); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + AbstractMetaFunctionList overloads = classA->queryFunctionsByName(QLatin1String("method")); + QCOMPARE(overloads.count(), 1); + AbstractMetaFunction* method = overloads.first(); + QVERIFY(method); + AbstractMetaArgumentList args = method->arguments(); + QCOMPARE(args.count(), 1); + AbstractMetaArgument* arg = args.first(); + AbstractMetaType* metaType = arg->type(); + QCOMPARE(metaType->cppSignature(), QLatin1String("A")); + QVERIFY(metaType->isValue()); + QVERIFY(metaType->typeEntry()->isObject()); +} + +QTEST_APPLESS_MAIN(TestAbstractMetaType) diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h new file mode 100644 index 000000000..a806d36e3 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTABSTRACTMETATYPE_H +#define TESTABSTRACTMETATYPE_H + +#include + +class TestAbstractMetaType : public QObject +{ + Q_OBJECT +private slots: + void testConstCharPtrType(); + void testCharType(); + void testTypedef(); + void testTypedefWithTemplates(); + void testApiVersionSupported(); + void testApiVersionNotSupported(); + void testObjectTypeUsedAsValue(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp new file mode 100644 index 000000000..bcc5238bc --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp @@ -0,0 +1,453 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testaddfunction.h" +#include +#include "testutil.h" +#include +#include + +void TestAddFunction::testParsingFuncNameAndConstness() +{ + // generic test... + const char sig1[] = "func(type1, const type2, const type3* const)"; + AddedFunction f1(QLatin1String(sig1), QLatin1String("void"), 0); + QCOMPARE(f1.name(), QLatin1String("func")); + QCOMPARE(f1.arguments().count(), 3); + AddedFunction::TypeInfo retval = f1.returnType(); + QCOMPARE(retval.name, QLatin1String("void")); + QCOMPARE(retval.indirections, 0); + QCOMPARE(retval.isConstant, false); + QCOMPARE(retval.isReference, false); + + // test with a ugly template as argument and other ugly stuff + const char sig2[] = " _fu__nc_ ( type1, const type2, const Abc * > * *, const type3* const ) const "; + AddedFunction f2(QLatin1String(sig2), QLatin1String("const Abc * > * *"), 0); + QCOMPARE(f2.name(), QLatin1String("_fu__nc_")); + QVector< AddedFunction::TypeInfo > args = f2.arguments(); + QCOMPARE(args.count(), 4); + retval = f2.returnType(); + QCOMPARE(retval.name, QLatin1String("Abc * >")); + QCOMPARE(retval.indirections, 2); + QCOMPARE(retval.isConstant, true); + QCOMPARE(retval.isReference, false); + retval = args[2]; + QCOMPARE(retval.name, QLatin1String("Abc * >")); + QCOMPARE(retval.indirections, 2); + QCOMPARE(retval.isConstant, true); + QCOMPARE(retval.isReference, false); + + // function with no args. + const char sig3[] = "func()"; + AddedFunction f3(QLatin1String(sig3), QLatin1String("void"), 0); + QCOMPARE(f3.name(), QLatin1String("func")); + QCOMPARE(f3.arguments().count(), 0); +} + +void TestAddFunction::testAddFunction() +{ + const char cppCode[] = "struct B {}; struct A { void a(int); };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + TypeDatabase* typeDb = TypeDatabase::instance(); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->functions().count(), 4); // default ctor, default copy ctor, func a() and the added function + + AbstractMetaFunction* addedFunc = classA->functions().last(); + QCOMPARE(addedFunc->visibility(), AbstractMetaFunction::Protected); + QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction); + QVERIFY(addedFunc->isUserAdded()); + QCOMPARE(addedFunc->ownerClass(), classA); + QCOMPARE(addedFunc->implementingClass(), classA); + QCOMPARE(addedFunc->declaringClass(), classA); + QVERIFY(!addedFunc->isVirtual()); + QVERIFY(!addedFunc->isSignal()); + QVERIFY(!addedFunc->isSlot()); + QVERIFY(!addedFunc->isStatic()); + + AbstractMetaType* returnType = addedFunc->type(); + QCOMPARE(returnType->typeEntry(), typeDb->findPrimitiveType(QLatin1String("int"))); + AbstractMetaArgumentList args = addedFunc->arguments(); + QCOMPARE(args.count(), 3); + QCOMPARE(args[0]->type()->typeEntry(), returnType->typeEntry()); + QCOMPARE(args[1]->defaultValueExpression(), QLatin1String("4.6")); + QCOMPARE(args[2]->type()->typeEntry(), typeDb->findType(QLatin1String("B"))); +} + +void TestAddFunction::testAddFunctionConstructor() +{ + const char cppCode[] = "struct A { A() {} };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->functions().count(), 3); // default and added ctors + AbstractMetaFunction* addedFunc = classA->functions().last(); + QCOMPARE(addedFunc->visibility(), AbstractMetaFunction::Public); + QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::ConstructorFunction); + QCOMPARE(addedFunc->arguments().size(), 1); + QVERIFY(addedFunc->isUserAdded()); + QVERIFY(!addedFunc->type()); +} + +void TestAddFunction::testAddFunctionTagDefaultValues() +{ + const char cppCode[] = "struct A {};\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->functions().count(), 3); // default ctor, default copy ctor and the added function + AbstractMetaFunction* addedFunc = classA->functions().last(); + QCOMPARE(addedFunc->visibility(), AbstractMetaFunction::Public); + QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction); + QVERIFY(addedFunc->isUserAdded()); + QVERIFY(!addedFunc->type()); +} + +void TestAddFunction::testAddFunctionCodeSnippets() +{ + const char cppCode[] = "struct A {};\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + Hi!, I am the code.\n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + AbstractMetaFunction* addedFunc = classA->functions().last(); + QVERIFY(addedFunc->hasInjectedCode()); +} + +void TestAddFunction::testAddFunctionWithoutParenteses() +{ + const char sig1[] = "func"; + AddedFunction f1(QLatin1String(sig1), QLatin1String("void"), 0); + + QCOMPARE(f1.name(), QLatin1String("func")); + QCOMPARE(f1.arguments().count(), 0); + QCOMPARE(f1.isConstant(), false); + + const char cppCode[] = "struct A {};\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + Hi!, I am the code.\n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("func")); + QVERIFY(addedFunc); + QVERIFY(addedFunc->hasInjectedCode()); + QCOMPARE(addedFunc->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode).count(), 1); +} + +void TestAddFunction::testAddFunctionWithDefaultArgs() +{ + const char sig1[] = "func"; + AddedFunction f1(QLatin1String(sig1), QLatin1String("void"), 0); + + QCOMPARE(f1.name(), QLatin1String("func")); + QCOMPARE(f1.arguments().count(), 0); + QCOMPARE(f1.isConstant(), false); + + const char cppCode[] = "struct A { };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("func")); + QVERIFY(addedFunc); + AbstractMetaArgument *arg = addedFunc->arguments()[1]; + QCOMPARE(arg->defaultValueExpression(), QLatin1String("2")); +} + +void TestAddFunction::testAddFunctionAtModuleLevel() +{ + const char cppCode[] = "struct A { };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + custom_code();\n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + + TypeDatabase* typeDb = TypeDatabase::instance(); + + AddedFunctionList addedFuncs = typeDb->findGlobalUserFunctions(QLatin1String("func")); + + QCOMPARE(addedFuncs.size(), 1); + + FunctionModificationList mods = typeDb->functionModifications(QLatin1String("func(int,int)")); + + QCOMPARE(mods.size(), 1); + QVERIFY(mods.first().isCodeInjection()); + CodeSnip snip = mods.first().snips.first(); + QCOMPARE(snip.code(), QLatin1String("custom_code();")); +} + +void TestAddFunction::testAddFunctionWithVarargs() +{ + const char sig1[] = "func(int,char,...)"; + AddedFunction f1( QLatin1String(sig1), QLatin1String("void"), 0); + + QCOMPARE(f1.name(), QLatin1String("func")); + QCOMPARE(f1.arguments().count(), 3); + QVERIFY(!f1.isConstant()); + + const char cppCode[] = "struct A {};\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("func")); + QVERIFY(addedFunc); + const AbstractMetaArgument* arg = addedFunc->arguments().last(); + QVERIFY(arg->type()->isVarargs()); + QVERIFY(arg->type()->typeEntry()->isVarargs()); +} + +void TestAddFunction::testAddStaticFunction() +{ + const char cppCode[] = "struct A { };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + custom_code();\n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("func")); + QVERIFY(addedFunc); + QVERIFY(addedFunc->isStatic()); +} + +void TestAddFunction::testAddGlobalFunction() +{ + const char cppCode[] = "struct A { };struct B {};\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + custom_code();\n\ + \n\ + \n\ + custom_code();\n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaFunctionList globalFuncs = builder->globalFunctions(); + QCOMPARE(globalFuncs.count(), 2); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(builder->classes(), QLatin1String("B")); + QVERIFY(classB); + QVERIFY(!classB->findFunction(QLatin1String("globalFunc"))); + QVERIFY(!classB->findFunction(QLatin1String("globalFunc2"))); + QVERIFY(!globalFuncs[0]->injectedCodeSnips().isEmpty()); + QVERIFY(!globalFuncs[1]->injectedCodeSnips().isEmpty()); +} + +void TestAddFunction::testAddFunctionWithApiVersion() +{ + const char cppCode[] = ""; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + custom_code();\n\ + \n\ + \n\ + custom_code();\n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, true, "0.1")); + QVERIFY(!builder.isNull()); + AbstractMetaFunctionList globalFuncs = builder->globalFunctions(); + QCOMPARE(globalFuncs.count(), 1); +} + +void TestAddFunction::testModifyAddedFunction() +{ + const char cppCode[] = "class Foo { };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + custom_code();\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + AbstractMetaClass* foo = AbstractMetaClass::findClass(classes, QLatin1String("Foo")); + const AbstractMetaFunction* method = foo->findFunction(QLatin1String("method")); + QCOMPARE(method->arguments().size(), 2); + AbstractMetaArgument* arg = method->arguments().at(1); + QCOMPARE(arg->defaultValueExpression(), QLatin1String("0")); + QCOMPARE(arg->name(), QLatin1String("varName")); + QCOMPARE(method->argumentName(2), QLatin1String("varName")); +} + +void TestAddFunction::testAddFunctionOnTypedef() +{ + const char cppCode[] = "template class Foo { }; typedef Foo FooInt;\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + custom_code();\n\ + \n\ + \n\ + custom_code();\n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + AbstractMetaClass* foo = AbstractMetaClass::findClass(classes, QLatin1String("FooInt")); + QVERIFY(foo); + QVERIFY(foo->hasNonPrivateConstructor()); + const AbstractMetaFunctionList &lst = foo->queryFunctions(AbstractMetaClass::Constructors); + for (const AbstractMetaFunction *f : lst) + QVERIFY(f->signature().startsWith(f->name())); + QCOMPARE(lst.size(), 2); + const AbstractMetaFunction* method = foo->findFunction(QLatin1String("method")); + QVERIFY(method); +} + +void TestAddFunction::testAddFunctionWithTemplateArg() +{ + const char cppCode[] = "template class Foo { };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + QCOMPARE(builder->globalFunctions().size(), 1); + AbstractMetaFunction* func = builder->globalFunctions().first(); + AbstractMetaArgument* arg = func->arguments().first(); + QCOMPARE(arg->type()->instantiations().count(), 1); +} + +QTEST_APPLESS_MAIN(TestAddFunction) + diff --git a/sources/shiboken2/ApiExtractor/tests/testaddfunction.h b/sources/shiboken2/ApiExtractor/tests/testaddfunction.h new file mode 100644 index 000000000..16a4ede09 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testaddfunction.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTADDFUNCTION_H +#define TESTADDFUNCTION_H +#include + +class TestAddFunction : public QObject +{ + Q_OBJECT +private slots: + void testParsingFuncNameAndConstness(); + void testAddFunction(); + void testAddFunctionConstructor(); + void testAddFunctionTagDefaultValues(); + void testAddFunctionCodeSnippets(); + void testAddFunctionWithoutParenteses(); + void testAddFunctionWithDefaultArgs(); + void testAddFunctionAtModuleLevel(); + void testAddFunctionWithVarargs(); + void testAddStaticFunction(); + void testAddGlobalFunction(); + void testAddFunctionWithApiVersion(); + void testModifyAddedFunction(); + void testAddFunctionOnTypedef(); + void testAddFunctionWithTemplateArg(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testarrayargument.cpp b/sources/shiboken2/ApiExtractor/tests/testarrayargument.cpp new file mode 100644 index 000000000..4d46d44bc --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testarrayargument.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testarrayargument.h" +#include +#include "testutil.h" +#include +#include + +void TestArrayArgument::testArrayArgumentWithSizeDefinedByInteger() +{ + const char* cppCode ="\ + struct A {\n\ + enum SomeEnum { Value0, Value1, NValues };\n\ + void method(double[3]);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + QVERIFY(classA); + + const AbstractMetaArgument* arg = classA->functions().last()->arguments().first(); + QVERIFY(arg->type()->isArray()); + QCOMPARE(arg->type()->arrayElementCount(), 3); + QCOMPARE(arg->type()->arrayElementType()->name(), QLatin1String("double")); +} + +void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValue() +{ + const char* cppCode ="\ + struct A {\n\ + enum SomeEnum { Value0, Value1, NValues };\n\ + void method(double[NValues]);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + QVERIFY(classA); + + AbstractMetaEnum* someEnum = classA->findEnum(QLatin1String("SomeEnum")); + QVERIFY(someEnum); + AbstractMetaEnumValue* nvalues = classA->findEnumValue(QLatin1String("NValues"), someEnum); + QVERIFY(nvalues); + + const AbstractMetaArgument* arg = classA->functions().last()->arguments().first(); + QVERIFY(arg->type()->isArray()); + QCOMPARE(arg->type()->arrayElementCount(), nvalues->value()); + QCOMPARE(arg->type()->arrayElementType()->name(), QLatin1String("double")); +}; + +void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnum() +{ + const char* cppCode ="\ + enum SomeEnum { Value0, Value1, NValues };\n\ + struct A {\n\ + void method(double[NValues]);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + QVERIFY(classA); + + AbstractMetaEnum* someEnum = builder->globalEnums().first(); + QVERIFY(someEnum); + AbstractMetaEnumValue* nvalues = 0; + const AbstractMetaEnumValueList &values = someEnum->values(); + for (AbstractMetaEnumValue *enumValue : values) { + if (enumValue->name() == QLatin1String("NValues")) { + nvalues = enumValue; + break; + } + } + QVERIFY(nvalues); + + const AbstractMetaArgument* arg = classA->functions().last()->arguments().first(); + QVERIFY(arg->type()->isArray()); + QCOMPARE(arg->type()->arrayElementCount(), nvalues->value()); + QCOMPARE(arg->type()->arrayElementType()->name(), QLatin1String("double")); +}; + +QTEST_APPLESS_MAIN(TestArrayArgument) diff --git a/sources/shiboken2/ApiExtractor/tests/testarrayargument.h b/sources/shiboken2/ApiExtractor/tests/testarrayargument.h new file mode 100644 index 000000000..b50232ef4 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testarrayargument.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTARRAYARGUMENT_H +#define TESTARRAYARGUMENT_H +#include + +class TestArrayArgument : public QObject +{ + Q_OBJECT +private slots: + void testArrayArgumentWithSizeDefinedByInteger(); + void testArrayArgumentWithSizeDefinedByEnumValue(); + void testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnum(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp new file mode 100644 index 000000000..ad245633e --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testcodeinjection.h" +#include +#include +#include +#include "testutil.h" +#include +#include + +void TestCodeInjections::testReadFileUtf8() +{ + const char* cppCode ="struct A {};\n"; + int argc = 0; + char *argv[] = {NULL}; + QCoreApplication app(argc, argv); + QString filePath = QDir::currentPath(); + QString xmlCode = QLatin1String("\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"); + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().constData())); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + 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); + code = classA->typeEntry()->conversionRule(); + QVERIFY(code.indexOf(utf8Data) != -1); +} + +void TestCodeInjections::testInjectWithValidApiVersion() +{ + const char* cppCode ="struct A {};\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + test Inject code\n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, true, "1.0")); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classA->typeEntry()->codeSnips().count(), 1); +} + +void TestCodeInjections::testInjectWithInvalidApiVersion() +{ + const char* cppCode ="struct A {};\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + test Inject code\n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, true, "0.1")); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classA->typeEntry()->codeSnips().count(), 0); +} + + + +QTEST_APPLESS_MAIN(TestCodeInjections) diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h new file mode 100644 index 000000000..56c1c7cba --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTCODEINJECTIONS_H +#define TESTCODEINJECTIONS_H + +#include + +class AbstractMetaBuilder; + +class TestCodeInjections : public QObject +{ + Q_OBJECT +private slots: + void testReadFileUtf8(); + void testInjectWithValidApiVersion(); + void testInjectWithInvalidApiVersion(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testcontainer.cpp b/sources/shiboken2/ApiExtractor/tests/testcontainer.cpp new file mode 100644 index 000000000..1c79a5a7a --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testcontainer.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testcontainer.h" +#include +#include "testutil.h" +#include +#include + +void TestContainer::testContainerType() +{ + const char* cppCode ="\ + namespace std {\n\ + template\n\ + class list {\n\ + T get(int x) { return 0; }\n\ + };\n\ + }\n\ + class A : public std::list {\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, true)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + //search for class A + AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QVERIFY(classA->typeEntry()->baseContainerType()); + QCOMPARE(reinterpret_cast(classA->typeEntry()->baseContainerType())->type(), ContainerTypeEntry::ListContainer); +} + +void TestContainer::testListOfValueType() +{ + const char* cppCode ="\ + namespace std {\n\ + template\n\ + class list {\n\ + T get(int x) { return 0; }\n\ + };\n\ + }\n\ + class ValueType {};\n\ + class A : public std::list {\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, true)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 3); + + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->templateBaseClassInstantiations().count(), 1); + const AbstractMetaType* templateInstanceType = classA->templateBaseClassInstantiations().first(); + QVERIFY(templateInstanceType); + + QCOMPARE(templateInstanceType->indirections(), 0); + QVERIFY(!templateInstanceType->typeEntry()->isObject()); + QVERIFY(templateInstanceType->typeEntry()->isValue()); + QCOMPARE(templateInstanceType->referenceType(), NoReference); + QVERIFY(!templateInstanceType->isObject()); + QVERIFY(!templateInstanceType->isValuePointer()); + QVERIFY(templateInstanceType->isValue()); +} + +QTEST_APPLESS_MAIN(TestContainer) + diff --git a/sources/shiboken2/ApiExtractor/tests/testcontainer.h b/sources/shiboken2/ApiExtractor/tests/testcontainer.h new file mode 100644 index 000000000..f154ea212 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testcontainer.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTCONTAINER_H +#define TESTCONTAINER_H +#include + +class TestContainer : public QObject +{ + Q_OBJECT +private slots: + void testContainerType(); + void testListOfValueType(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testconversionoperator.cpp b/sources/shiboken2/ApiExtractor/tests/testconversionoperator.cpp new file mode 100644 index 000000000..86f571328 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testconversionoperator.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testconversionoperator.h" +#include +#include "testutil.h" +#include +#include + +void TestConversionOperator::testConversionOperator() +{ + const char cppCode[] = "\ + struct A {\n\ + };\n\ + struct B {\n\ + operator A() const;\n\ + };\n\ + struct C {\n\ + operator A() const;\n\ + };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C")); + QVERIFY(classA); + QVERIFY(classB); + QVERIFY(classC); + QCOMPARE(classA->functions().count(), 2); + QCOMPARE(classB->functions().count(), 3); + QCOMPARE(classC->functions().count(), 3); + QCOMPARE(classA->externalConversionOperators().count(), 2); + + AbstractMetaFunction* convOp = 0; + for (AbstractMetaFunction *func : classB->functions()) { + if (func->isConversionOperator()) { + convOp = func; + break; + } + } + QVERIFY(convOp); + QVERIFY(classA->externalConversionOperators().contains(convOp)); +} + +void TestConversionOperator::testConversionOperatorOfDiscardedClass() +{ + const char cppCode[] = "\ + struct A {\n\ + };\n\ + struct B {\n\ + operator A() const;\n\ + };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->externalConversionOperators().count(), 0); +} + +void TestConversionOperator::testRemovedConversionOperator() +{ + const char cppCode[] = "\ + struct A {\n\ + };\n\ + struct B {\n\ + operator A() const;\n\ + };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classA); + QVERIFY(classB); + QCOMPARE(classA->functions().count(), 2); + QCOMPARE(classB->functions().count(), 3); + QCOMPARE(classA->externalConversionOperators().count(), 0); + QCOMPARE(classA->implicitConversions().count(), 0); +} + +void TestConversionOperator::testConversionOperatorReturningReference() +{ + const char cppCode[] = "\ + struct A {};\n\ + struct B {\n\ + operator A&() const;\n\ + };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classA); + QVERIFY(classB); + QCOMPARE(classA->functions().count(), 2); + QCOMPARE(classB->functions().count(), 3); + QCOMPARE(classA->externalConversionOperators().count(), 1); + QCOMPARE(classA->externalConversionOperators().first()->type()->cppSignature(), QLatin1String("A")); + QCOMPARE(classA->externalConversionOperators().first()->ownerClass()->name(), QLatin1String("B")); + QCOMPARE(classA->implicitConversions().count(), 1); + QCOMPARE(classA->implicitConversions().first()->type()->cppSignature(), QLatin1String("A")); + QCOMPARE(classA->implicitConversions().first()->ownerClass()->name(), QLatin1String("B")); +} + +void TestConversionOperator::testConversionOperatorReturningConstReference() +{ + const char cppCode[] = "\ + struct A {};\n\ + struct B {\n\ + operator const A&() const;\n\ + };\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classA); + QVERIFY(classB); + QCOMPARE(classA->functions().count(), 2); + QCOMPARE(classB->functions().count(), 3); + QCOMPARE(classA->externalConversionOperators().count(), 1); + QCOMPARE(classA->externalConversionOperators().first()->type()->cppSignature(), QLatin1String("A")); + QCOMPARE(classA->externalConversionOperators().first()->ownerClass()->name(), QLatin1String("B")); + QCOMPARE(classA->implicitConversions().count(), 1); + QCOMPARE(classA->implicitConversions().first()->type()->cppSignature(), QLatin1String("A")); + QCOMPARE(classA->implicitConversions().first()->ownerClass()->name(), QLatin1String("B")); +} + +QTEST_APPLESS_MAIN(TestConversionOperator) diff --git a/sources/shiboken2/ApiExtractor/tests/testconversionoperator.h b/sources/shiboken2/ApiExtractor/tests/testconversionoperator.h new file mode 100644 index 000000000..f28747ab5 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testconversionoperator.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTCONVERSIONOPERATOR_H +#define TESTCONVERSIONOPERATOR_H +#include + +class TestConversionOperator : public QObject +{ + Q_OBJECT +private slots: + void testConversionOperator(); + void testConversionOperatorOfDiscardedClass(); + void testRemovedConversionOperator(); + void testConversionOperatorReturningReference(); + void testConversionOperatorReturningConstReference(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testconversionruletag.cpp b/sources/shiboken2/ApiExtractor/tests/testconversionruletag.cpp new file mode 100644 index 000000000..fb9290795 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testconversionruletag.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testconversionruletag.h" +#include +#include "testutil.h" +#include +#include +#include +#include + +void TestConversionRuleTag::testConversionRuleTagWithFile() +{ + // temp file used later + const char conversionData[] = "Hi! I'm a conversion rule."; + QTemporaryFile file; + file.open(); + QCOMPARE(file.write(conversionData), qint64(sizeof(conversionData)-1)); + file.close(); + + const char cppCode[] = "struct A {};\n"; + QString xmlCode = QLatin1String("\ + \n\ + \n\ + \n\ + \n\ + \n"); + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().data())); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + const ComplexTypeEntry* typeEntry = classA->typeEntry(); + QVERIFY(typeEntry->hasConversionRule()); + QCOMPARE(typeEntry->conversionRule(), QLatin1String(conversionData)); +} + +void TestConversionRuleTag::testConversionRuleTagReplace() +{ + const char cppCode[] = "\ + struct A {\n\ + A();\n\ + A(const char*, int);\n\ + };\n\ + struct B {\n\ + A createA();\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + DoThis();\n\ + return ConvertFromCppToPython(%IN);\n\ + \n\ + \n\ + \n\ + DoThat();\n\ + DoSomething();\n\ + %OUT = A();\n\ + \n\ + \n\ + %OUT = %IN.createA();\n\ + \n\ + \n\ + %OUT = new A(String_AsString(%IN), String_GetSize(%IN));\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + TypeDatabase* typeDb = TypeDatabase::instance(); + PrimitiveTypeEntry* typeA = typeDb->findPrimitiveType(QLatin1String("A")); + QVERIFY(typeA); + + CustomConversion* conversion = typeA->customConversion(); + QVERIFY(conversion); + + QCOMPARE(typeA, conversion->ownerType()); + QCOMPARE(conversion->nativeToTargetConversion().simplified(), + QLatin1String("DoThis(); return ConvertFromCppToPython(%IN);")); + + QVERIFY(conversion->replaceOriginalTargetToNativeConversions()); + QVERIFY(conversion->hasTargetToNativeConversions()); + QCOMPARE(conversion->targetToNativeConversions().size(), 3); + + CustomConversion::TargetToNativeConversion* toNative = conversion->targetToNativeConversions().at(0); + QVERIFY(toNative); + QCOMPARE(toNative->sourceTypeName(), QLatin1String("TargetNone")); + QVERIFY(toNative->isCustomType()); + QCOMPARE(toNative->sourceType(), (const TypeEntry*)0); + QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("%IN == Target_None")); + QCOMPARE(toNative->conversion().simplified(), + QLatin1String("DoThat(); DoSomething(); %OUT = A();")); + + toNative = conversion->targetToNativeConversions().at(1); + QVERIFY(toNative); + QCOMPARE(toNative->sourceTypeName(), QLatin1String("B")); + QVERIFY(!toNative->isCustomType()); + TypeEntry* typeB = typeDb->findType(QLatin1String("B")); + QVERIFY(typeB); + QCOMPARE(toNative->sourceType(), typeB); + QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("CheckIfInputObjectIsB(%IN)")); + QCOMPARE(toNative->conversion().trimmed(), QLatin1String("%OUT = %IN.createA();")); + + toNative = conversion->targetToNativeConversions().at(2); + QVERIFY(toNative); + QCOMPARE(toNative->sourceTypeName(), QLatin1String("String")); + QVERIFY(toNative->isCustomType()); + QCOMPARE(toNative->sourceType(), (const TypeEntry*)0); + QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("String_Check(%IN)")); + QCOMPARE(toNative->conversion().trimmed(), QLatin1String("%OUT = new A(String_AsString(%IN), String_GetSize(%IN));")); +} + +void TestConversionRuleTag::testConversionRuleTagAdd() +{ + const char cppCode[] = "\ + struct Date {\n\ + Date();\n\ + Date(int, int, int);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ +if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\n\ +%OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));\n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("Date")); + QVERIFY(classA); + + CustomConversion* conversion = classA->typeEntry()->customConversion(); + QVERIFY(conversion); + + QCOMPARE(conversion->nativeToTargetConversion(), QString()); + + QVERIFY(!conversion->replaceOriginalTargetToNativeConversions()); + QVERIFY(conversion->hasTargetToNativeConversions()); + QCOMPARE(conversion->targetToNativeConversions().size(), 1); + + CustomConversion::TargetToNativeConversion* toNative = conversion->targetToNativeConversions().first(); + QVERIFY(toNative); + QCOMPARE(toNative->sourceTypeName(), QLatin1String("TargetDate")); + QVERIFY(toNative->isCustomType()); + QCOMPARE(toNative->sourceType(), (const TypeEntry*)0); + QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("TargetDate_Check(%IN)")); + QCOMPARE(toNative->conversion().trimmed(), + QLatin1String("if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\n%OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));")); +} + +void TestConversionRuleTag::testConversionRuleTagWithInsertTemplate() +{ + const char cppCode[] = "struct A {};"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + const char nativeToTargetExpected[] = + "// TEMPLATE - native_to_target - START\n" + "return ConvertFromCppToPython(%IN);\n" + "// TEMPLATE - native_to_target - END"; + + const char targetToNativeExpected[] = + "// TEMPLATE - target_to_native - START\n" + "%OUT = %IN.createA();\n" + "// TEMPLATE - target_to_native - END"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + TypeDatabase* typeDb = TypeDatabase::instance(); + PrimitiveTypeEntry* typeA = typeDb->findPrimitiveType(QLatin1String("A")); + QVERIFY(typeA); + + CustomConversion* conversion = typeA->customConversion(); + QVERIFY(conversion); + + QCOMPARE(typeA, conversion->ownerType()); + QCOMPARE(conversion->nativeToTargetConversion().trimmed(), + QLatin1String(nativeToTargetExpected)); + + QVERIFY(conversion->hasTargetToNativeConversions()); + QCOMPARE(conversion->targetToNativeConversions().size(), 1); + + CustomConversion::TargetToNativeConversion* toNative = conversion->targetToNativeConversions().first(); + QVERIFY(toNative); + QCOMPARE(toNative->conversion().trimmed(), + QLatin1String(targetToNativeExpected)); +} + +QTEST_APPLESS_MAIN(TestConversionRuleTag) diff --git a/sources/shiboken2/ApiExtractor/tests/testconversionruletag.h b/sources/shiboken2/ApiExtractor/tests/testconversionruletag.h new file mode 100644 index 000000000..c02a9708b --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testconversionruletag.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTCONVERSIONRULE_H +#define TESTCONVERSIONRULE_H +#include + +class TestConversionRuleTag : public QObject +{ + Q_OBJECT +private slots: + void testConversionRuleTagWithFile(); + void testConversionRuleTagReplace(); + void testConversionRuleTagAdd(); + void testConversionRuleTagWithInsertTemplate(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testctorinformation.cpp b/sources/shiboken2/ApiExtractor/tests/testctorinformation.cpp new file mode 100644 index 000000000..a4b4c2388 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testctorinformation.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testctorinformation.h" +#include "abstractmetabuilder.h" +#include +#include "testutil.h" +#include +#include + +void TestCtorInformation::testCtorIsPrivate() +{ + const char* cppCode = "class Control { public: Control() {} };\n\ + class Subject { private: Subject() {} };\n\ + class CtorLess { };\n"; + const char* xmlCode = "\n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 3); + QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasNonPrivateConstructor(), true); + QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasNonPrivateConstructor(), false); + QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("CtorLess"))->hasNonPrivateConstructor(), true); +} + +void TestCtorInformation::testHasNonPrivateCtor() +{ + const char* cppCode = "template\n\ + struct Base { Base(double) {} };\n\ + typedef Base Derived;\n"; + const char* xmlCode = "\n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + const AbstractMetaClass *base = AbstractMetaClass::findClass(classes, QLatin1String("Base")); + QCOMPARE(base->hasNonPrivateConstructor(), true); + const AbstractMetaClass *derived = AbstractMetaClass::findClass(classes, QLatin1String("Derived")); + QCOMPARE(derived->hasNonPrivateConstructor(), true); +} + +QTEST_APPLESS_MAIN(TestCtorInformation) diff --git a/sources/shiboken2/ApiExtractor/tests/testctorinformation.h b/sources/shiboken2/ApiExtractor/tests/testctorinformation.h new file mode 100644 index 000000000..f5ffe5501 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testctorinformation.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTCTORINFORMATION_H +#define TESTCTORINFORMATION_H + +#include + +class AbstractMetaBuilder; + +class TestCtorInformation: public QObject +{ + Q_OBJECT +private slots: + void testCtorIsPrivate(); + void testHasNonPrivateCtor(); +}; + +#endif // TESTCTORINFORMATION_H diff --git a/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp new file mode 100644 index 000000000..6b6c5d011 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testdroptypeentries.h" +#include +#include "testutil.h" +#include +#include + +static const char* cppCode ="\ + struct ValueA {};\n\ + struct ValueB {};\n\ + struct ObjectA {};\n\ + struct ObjectB {};\n\ + namespace NamespaceA {\n\ + struct InnerClassA {};\n\ + namespace InnerNamespaceA {}\n\ + }\n\ + namespace NamespaceB {}\n\ + enum EnumA { Value0 };\n\ + enum EnumB { Value1 };\n\ + void funcA();\n\ + void funcB();\n"; + +static const char* xmlCode = "\ +\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ +\n"; + +void TestDropTypeEntries::testDropEntries() +{ + QStringList droppedEntries(QLatin1String("Foo.ValueB")); + droppedEntries << QLatin1String("Foo.ObjectB") << QLatin1String("Foo.NamespaceA.InnerClassA"); + droppedEntries << QLatin1String("Foo.NamespaceB") << QLatin1String("Foo.EnumB") << QLatin1String("Foo.funcB()"); + droppedEntries << QLatin1String("Foo.NamespaceA.InnerNamespaceA"); + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false, Q_NULLPTR, droppedEntries)); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ValueA"))); + QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("ValueB"))); + QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ObjectA"))); + QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("ObjectB"))); + QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA"))); + QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA::InnerClassA"))); + QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("NamespaceB"))); + + AbstractMetaEnumList globalEnums = builder->globalEnums(); + QCOMPARE(globalEnums.count(), 1); + QCOMPARE(globalEnums.first()->name(), QLatin1String("EnumA")); + + TypeDatabase* td = TypeDatabase::instance(); + QVERIFY(td->findType(QLatin1String("funcA"))); + QVERIFY(!td->findType(QLatin1String("funcB"))); +} + +void TestDropTypeEntries::testDontDropEntries() +{ + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ValueA"))); + QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ValueB"))); + QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ObjectA"))); + QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ObjectB"))); + QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA"))); + QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA::InnerClassA"))); + QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceB"))); + + QCOMPARE(builder->globalEnums().size(), 2); + + TypeDatabase* td = TypeDatabase::instance(); + QVERIFY(td->findType(QLatin1String("funcA"))); + QVERIFY(td->findType(QLatin1String("funcB"))); +} + +static const char* cppCode2 ="\ + struct ValueA {\n\ + void func();\n\ + };\n"; + +static const char* xmlCode2 = "\ +\n\ + \n\ + \n\ + \n\ + \n\ + \n\ +\n"; + +void TestDropTypeEntries::testDropEntryWithChildTags() +{ + QStringList droppedEntries(QLatin1String("Foo.ValueA")); + QScopedPointer builder(TestUtil::parse(cppCode2, xmlCode2, false, Q_NULLPTR, droppedEntries)); + QVERIFY(!builder.isNull()); + QVERIFY(!AbstractMetaClass::findClass(builder->classes(), QLatin1String("ValueA"))); +} + + +void TestDropTypeEntries::testDontDropEntryWithChildTags() +{ + QScopedPointer builder(TestUtil::parse(cppCode2, xmlCode2, false)); + QVERIFY(!builder.isNull()); + QVERIFY(AbstractMetaClass::findClass(builder->classes(), QLatin1String("ValueA"))); +} + +QTEST_APPLESS_MAIN(TestDropTypeEntries) diff --git a/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.h b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.h new file mode 100644 index 000000000..d04c6dc92 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTDROPTYPEENTRIES_H +#define TESTDROPTYPEENTRIES_H + +#include + +class TestDropTypeEntries : public QObject +{ + Q_OBJECT + private slots: + void testDropEntries(); + void testDontDropEntries(); + void testDropEntryWithChildTags(); + void testDontDropEntryWithChildTags(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp new file mode 100644 index 000000000..63b745c12 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testdtorinformation.h" +#include "abstractmetabuilder.h" +#include +#include "testutil.h" +#include +#include + +void TestDtorInformation::testDtorIsPrivate() +{ + const char* cppCode ="class Control { public: ~Control() {} }; class Subject { private: ~Subject() {} };"; + const char* xmlCode = ""; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasPrivateDestructor(), false); + QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasPrivateDestructor(), true); +} + +void TestDtorInformation::testDtorIsProtected() +{ + const char* cppCode ="class Control { public: ~Control() {} }; class Subject { protected: ~Subject() {} };"; + const char* xmlCode = ""; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasProtectedDestructor(), false); + QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasProtectedDestructor(), true); +} + +void TestDtorInformation::testDtorIsVirtual() +{ + const char* cppCode ="class Control { public: ~Control() {} }; class Subject { protected: virtual ~Subject() {} };"; + const char* xmlCode = ""; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasVirtualDestructor(), false); + QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasVirtualDestructor(), true); +} + +void TestDtorInformation::testClassWithVirtualDtorIsPolymorphic() +{ + const char* cppCode ="class Control { public: virtual ~Control() {} }; class Subject { protected: virtual ~Subject() {} };"; + const char* xmlCode = ""; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->isPolymorphic(), true); + QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->isPolymorphic(), true); +} + +QTEST_APPLESS_MAIN(TestDtorInformation) + + diff --git a/sources/shiboken2/ApiExtractor/tests/testdtorinformation.h b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.h new file mode 100644 index 000000000..21a3b1822 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTDTORINFORMATION_H +#define TESTDTORINFORMATION_H + +#include + +class AbstractMetaBuilder; + +class TestDtorInformation: public QObject +{ + Q_OBJECT +private slots: + void testDtorIsPrivate(); + void testDtorIsProtected(); + void testDtorIsVirtual(); + void testClassWithVirtualDtorIsPolymorphic(); +}; + +#endif // TESTDTORINFORMATION_H diff --git a/sources/shiboken2/ApiExtractor/tests/testenum.cpp b/sources/shiboken2/ApiExtractor/tests/testenum.cpp new file mode 100644 index 000000000..98e56b86e --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testenum.cpp @@ -0,0 +1,416 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testenum.h" +#include +#include "testutil.h" +#include +#include + +void TestEnum::testEnumCppSignature() +{ + const char* cppCode ="\ + enum GlobalEnum { A, B };\n\ + \n\ + struct A {\n\ + enum ClassEnum { CA, CB };\n\ + void method(ClassEnum);\n\ + };\n\ + void func(A::ClassEnum);\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 1); + + AbstractMetaEnumList globalEnums = builder->globalEnums(); + QCOMPARE(globalEnums.count(), 1); + QCOMPARE(globalEnums.first()->name(), QLatin1String("GlobalEnum")); + + // enum as parameter of a function + AbstractMetaFunctionList functions = builder->globalFunctions(); + QCOMPARE(functions.count(), 1); + QCOMPARE(functions.first()->arguments().count(), 1); + QCOMPARE(functions.first()->arguments().first()->type()->cppSignature(), QLatin1String("A::ClassEnum")); + + // enum as parameter of a method + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classA->enums().count(), 1); + AbstractMetaFunctionList funcs = classA->queryFunctionsByName(QLatin1String("method")); + QVERIFY(!funcs.isEmpty()); + AbstractMetaFunction* method = funcs.first(); + QVERIFY(method); + AbstractMetaArgument* arg = method->arguments().first(); + QCOMPARE(arg->type()->name(), QLatin1String("ClassEnum")); + QCOMPARE(arg->type()->cppSignature(), QLatin1String("A::ClassEnum")); + QCOMPARE(functions.first()->arguments().count(), 1); + arg = functions.first()->arguments().first(); + QCOMPARE(arg->type()->name(), QLatin1String("ClassEnum")); + QCOMPARE(arg->type()->cppSignature(), QLatin1String("A::ClassEnum")); + + AbstractMetaEnumList classEnums = classA->enums(); + QCOMPARE(classEnums.first()->name(), QLatin1String("ClassEnum")); +} + +void TestEnum::testEnumWithApiVersion() +{ + const char* cppCode ="\ + struct A {\n\ + enum ClassEnum { EnumA, EnumB };\n\ + enum ClassEnum2 { EnumC, EnumD };\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, true, "0.1")); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 1); + QCOMPARE(classes[0]->enums().count(), 1); +} + +void TestEnum::testAnonymousEnum() +{ + const char* cppCode ="\ + enum { Global0, Global1 };\n\ + struct A {\n\ + enum { A0, A1 };\n\ + enum { isThis = true, isThat = false };\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + AbstractMetaEnumList globalEnums = builder->globalEnums(); + QCOMPARE(globalEnums.count(), 1); + QCOMPARE(globalEnums.first()->typeEntry()->qualifiedCppName(), QLatin1String("Global0")); + QVERIFY(globalEnums.first()->isAnonymous()); + + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 1); + QCOMPARE(classes[0]->enums().count(), 2); + + AbstractMetaEnum* anonEnumA1 = classes[0]->findEnum(QLatin1String("A1")); + QVERIFY(anonEnumA1); + QVERIFY(anonEnumA1->isAnonymous()); + QCOMPARE(anonEnumA1->typeEntry()->qualifiedCppName(), QLatin1String("A::A1")); + + AbstractMetaEnumValue* enumValueA0 = anonEnumA1->values().first(); + QCOMPARE(enumValueA0->name(), QLatin1String("A0")); + QCOMPARE(enumValueA0->value(), 0); + QCOMPARE(enumValueA0->stringValue(), QString()); + + AbstractMetaEnumValue* enumValueA1 = anonEnumA1->values().last(); + QCOMPARE(enumValueA1->name(), QLatin1String("A1")); + QCOMPARE(enumValueA1->value(), 1); + QCOMPARE(enumValueA1->stringValue(), QString()); + + AbstractMetaEnum* anonEnumIsThis = classes[0]->findEnum(QLatin1String("isThis")); + QVERIFY(anonEnumIsThis); + QVERIFY(anonEnumIsThis->isAnonymous()); + QCOMPARE(anonEnumIsThis->typeEntry()->qualifiedCppName(), QLatin1String("A::isThis")); + + AbstractMetaEnumValue* enumValueIsThis = anonEnumIsThis->values().first(); + QCOMPARE(enumValueIsThis->name(), QLatin1String("isThis")); + QCOMPARE(enumValueIsThis->value(), static_cast(true)); + QCOMPARE(enumValueIsThis->stringValue(), QLatin1String("true")); + + AbstractMetaEnumValue* enumValueIsThat = anonEnumIsThis->values().last(); + QCOMPARE(enumValueIsThat->name(), QLatin1String("isThat")); + QCOMPARE(enumValueIsThat->value(), static_cast(false)); + QCOMPARE(enumValueIsThat->stringValue(), QLatin1String("false")); +} + +void TestEnum::testGlobalEnums() +{ + const char* cppCode ="\ + enum EnumA { A0, A1 };\n\ + enum EnumB { B0 = 2, B1 = 0x4 };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + AbstractMetaEnumList globalEnums = builder->globalEnums(); + QCOMPARE(globalEnums.count(), 2); + + AbstractMetaEnum* enumA = globalEnums.first(); + QCOMPARE(enumA->typeEntry()->qualifiedCppName(), QLatin1String("EnumA")); + + AbstractMetaEnumValue* enumValueA0 = enumA->values().first(); + QCOMPARE(enumValueA0->name(), QLatin1String("A0")); + QCOMPARE(enumValueA0->value(), 0); + QCOMPARE(enumValueA0->stringValue(), QString()); + + AbstractMetaEnumValue* enumValueA1 = enumA->values().last(); + QCOMPARE(enumValueA1->name(), QLatin1String("A1")); + QCOMPARE(enumValueA1->value(), 1); + QCOMPARE(enumValueA1->stringValue(), QString()); + + AbstractMetaEnum* enumB = globalEnums.last(); + QCOMPARE(enumB->typeEntry()->qualifiedCppName(), QLatin1String("EnumB")); + + AbstractMetaEnumValue* enumValueB0 = enumB->values().first(); + QCOMPARE(enumValueB0->name(), QLatin1String("B0")); + QCOMPARE(enumValueB0->value(), 2); + QCOMPARE(enumValueB0->stringValue(), QLatin1String("2")); + + AbstractMetaEnumValue* enumValueB1 = enumB->values().last(); + QCOMPARE(enumValueB1->name(), QLatin1String("B1")); + QCOMPARE(enumValueB1->value(), 4); + QCOMPARE(enumValueB1->stringValue(), QLatin1String("0x4")); +} + +void TestEnum::testEnumValueFromNeighbourEnum() +{ + const char* cppCode ="\ + namespace A {\n\ + enum EnumA { ValueA0, ValueA1 };\n\ + enum EnumB { ValueB0 = A::ValueA1, ValueB1 = ValueA0 };\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 1); + QCOMPARE(classes[0]->enums().count(), 2); + + AbstractMetaEnum* enumA = classes[0]->findEnum(QLatin1String("EnumA")); + QVERIFY(enumA); + QCOMPARE(enumA->typeEntry()->qualifiedCppName(), QLatin1String("A::EnumA")); + + AbstractMetaEnumValue* enumValueA0 = enumA->values().first(); + QCOMPARE(enumValueA0->name(), QLatin1String("ValueA0")); + QCOMPARE(enumValueA0->value(), 0); + QCOMPARE(enumValueA0->stringValue(), QString()); + + AbstractMetaEnumValue* enumValueA1 = enumA->values().last(); + QCOMPARE(enumValueA1->name(), QLatin1String("ValueA1")); + QCOMPARE(enumValueA1->value(), 1); + QCOMPARE(enumValueA1->stringValue(), QString()); + + AbstractMetaEnum* enumB = classes[0]->findEnum(QLatin1String("EnumB")); + QVERIFY(enumB); + QCOMPARE(enumB->typeEntry()->qualifiedCppName(), QLatin1String("A::EnumB")); + + AbstractMetaEnumValue* enumValueB0 = enumB->values().first(); + QCOMPARE(enumValueB0->name(), QLatin1String("ValueB0")); + QCOMPARE(enumValueB0->value(), 1); + QCOMPARE(enumValueB0->stringValue(), QLatin1String("A::ValueA1")); + + AbstractMetaEnumValue* enumValueB1 = enumB->values().last(); + QCOMPARE(enumValueB1->name(), QLatin1String("ValueB1")); + QCOMPARE(enumValueB1->value(), 0); + QCOMPARE(enumValueB1->stringValue(), QLatin1String("ValueA0")); +} + +void TestEnum::testEnumValueFromExpression() +{ + const char* cppCode ="\ + struct A {\n\ + enum EnumA {\n\ + ValueA0 = 3u,\n\ + ValueA1 = ~3u,\n\ + ValueA2 = ~3,\n\ + ValueA3 = 0xf0,\n\ + ValueA4 = 8 |ValueA3,\n\ + ValueA5 = ValueA3|32,\n\ + ValueA6 = ValueA3 >> 1,\n\ + ValueA7 = ValueA3 << 1\n\ + };\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + QVERIFY(classA); + + AbstractMetaEnum* enumA = classA->findEnum(QLatin1String("EnumA")); + QVERIFY(enumA); + QCOMPARE(enumA->typeEntry()->qualifiedCppName(), QLatin1String("A::EnumA")); + + AbstractMetaEnumValue* valueA0 = enumA->values().at(0); + QCOMPARE(valueA0->name(), QLatin1String("ValueA0")); + QCOMPARE(valueA0->stringValue(), QLatin1String("3u")); + QCOMPARE(valueA0->value(), (int) 3u); + + AbstractMetaEnumValue* valueA1 = enumA->values().at(1); + QCOMPARE(valueA1->name(), QLatin1String("ValueA1")); + QCOMPARE(valueA1->stringValue(), QLatin1String("~3u")); + QCOMPARE(valueA1->value(), (int) ~3u); + + AbstractMetaEnumValue* valueA2 = enumA->values().at(2); + QCOMPARE(valueA2->name(), QLatin1String("ValueA2")); + QCOMPARE(valueA2->stringValue(), QLatin1String("~3")); + QCOMPARE(valueA2->value(), ~3); + + AbstractMetaEnumValue* valueA3 = enumA->values().at(3); + QCOMPARE(valueA3->name(), QLatin1String("ValueA3")); + QCOMPARE(valueA3->stringValue(), QLatin1String("0xf0")); + QCOMPARE(valueA3->value(), 0xf0); + + AbstractMetaEnumValue* valueA4 = enumA->values().at(4); + QCOMPARE(valueA4->name(), QLatin1String("ValueA4")); + QCOMPARE(valueA4->stringValue(), QLatin1String("8 |ValueA3")); + QCOMPARE(valueA4->value(), 8|0xf0); + + AbstractMetaEnumValue* valueA5 = enumA->values().at(5); + QCOMPARE(valueA5->name(), QLatin1String("ValueA5")); + QCOMPARE(valueA5->stringValue(), QLatin1String("ValueA3|32")); + QCOMPARE(valueA5->value(), 0xf0|32); + + AbstractMetaEnumValue* valueA6 = enumA->values().at(6); + QCOMPARE(valueA6->name(), QLatin1String("ValueA6")); + QCOMPARE(valueA6->stringValue(), QLatin1String("ValueA3 >> 1")); + QCOMPARE(valueA6->value(), 0xf0 >> 1); + + AbstractMetaEnumValue* valueA7 = enumA->values().at(7); + QCOMPARE(valueA7->name(), QLatin1String("ValueA7")); + QCOMPARE(valueA7->stringValue(), QLatin1String("ValueA3 << 1")); + QCOMPARE(valueA7->value(), 0xf0 << 1); +} + +void TestEnum::testPrivateEnum() +{ + const char* cppCode ="\ + class A {\n\ + private:\n\ + enum PrivateEnum { Priv0 = 0x0f, Priv1 = 0xf0 };\n\ + public:\n\ + enum PublicEnum { Pub0 = Priv0, Pub1 = A::Priv1 };\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->enums().count(), 2); + + AbstractMetaEnum* privateEnum = classA->findEnum(QLatin1String("PrivateEnum")); + QVERIFY(privateEnum); + QVERIFY(privateEnum->isPrivate()); + QCOMPARE(privateEnum->typeEntry()->qualifiedCppName(), QLatin1String("A::PrivateEnum")); + + AbstractMetaEnum* publicEnum = classA->findEnum(QLatin1String("PublicEnum")); + QVERIFY(publicEnum); + QCOMPARE(publicEnum->typeEntry()->qualifiedCppName(), QLatin1String("A::PublicEnum")); + + AbstractMetaEnumValue* pub0 = publicEnum->values().first(); + QCOMPARE(pub0->name(), QLatin1String("Pub0")); + QCOMPARE(pub0->value(), 0x0f); + QCOMPARE(pub0->stringValue(), QLatin1String("Priv0")); + + AbstractMetaEnumValue* pub1 = publicEnum->values().last(); + QCOMPARE(pub1->name(), QLatin1String("Pub1")); + QCOMPARE(pub1->value(), 0xf0); + QCOMPARE(pub1->stringValue(), QLatin1String("A::Priv1")); +} + +void TestEnum::testTypedefEnum() +{ + const char* cppCode ="\ + typedef enum EnumA {\n\ + A0,\n\ + A1,\n\ + } EnumA;\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + AbstractMetaEnumList globalEnums = builder->globalEnums(); + QEXPECT_FAIL("", "APIExtractor does not handle typedef enum correctly yet", Abort); + QCOMPARE(globalEnums.count(), 1); + + AbstractMetaEnum* enumA = globalEnums.first(); + QCOMPARE(enumA->typeEntry()->qualifiedCppName(), QLatin1String("EnumA")); + + AbstractMetaEnumValue* enumValueA0 = enumA->values().first(); + QCOMPARE(enumValueA0->name(), QLatin1String("A0")); + QCOMPARE(enumValueA0->value(), 0); + QCOMPARE(enumValueA0->stringValue(), QLatin1String("")); + + AbstractMetaEnumValue* enumValueA1 = enumA->values().last(); + QCOMPARE(enumValueA1->name(), QLatin1String("A1")); + QCOMPARE(enumValueA1->value(), 1); + QCOMPARE(enumValueA1->stringValue(), QString()); +} + +QTEST_APPLESS_MAIN(TestEnum) diff --git a/sources/shiboken2/ApiExtractor/tests/testenum.h b/sources/shiboken2/ApiExtractor/tests/testenum.h new file mode 100644 index 000000000..8b46b1bd6 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testenum.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTENUM_H +#define TESTENUM_H +#include + +class TestEnum : public QObject +{ + Q_OBJECT +private slots: + void testEnumCppSignature(); + void testEnumWithApiVersion(); + void testAnonymousEnum(); + void testGlobalEnums(); + void testEnumValueFromNeighbourEnum(); + void testEnumValueFromExpression(); + void testPrivateEnum(); + void testTypedefEnum(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testextrainclude.cpp b/sources/shiboken2/ApiExtractor/tests/testextrainclude.cpp new file mode 100644 index 000000000..97f0d568e --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testextrainclude.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testextrainclude.h" +#include +#include "testutil.h" +#include +#include + +void TestExtraInclude::testClassExtraInclude() +{ + const char* cppCode ="struct A {};\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + + QVector includes = classA->typeEntry()->extraIncludes(); + QCOMPARE(includes.count(), 1); + QCOMPARE(includes.first().name(), QLatin1String("header.h")); +} + +void TestExtraInclude::testGlobalExtraIncludes() +{ + const char* cppCode ="struct A {};\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("A"))); + + TypeDatabase* td = TypeDatabase::instance(); + TypeEntry* module = td->findType(QLatin1String("Foo")); + QVERIFY(module); + + QVector includes = module->extraIncludes(); + QCOMPARE(includes.count(), 2); + QCOMPARE(includes.first().name(), QLatin1String("header1.h")); + QCOMPARE(includes.last().name(), QLatin1String("header2.h")); +} + +QTEST_APPLESS_MAIN(TestExtraInclude) diff --git a/sources/shiboken2/ApiExtractor/tests/testextrainclude.h b/sources/shiboken2/ApiExtractor/tests/testextrainclude.h new file mode 100644 index 000000000..c569901e1 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testextrainclude.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTEXTRAINCLUDE_H +#define TESTEXTRAINCLUDE_H + +#include + +class TestExtraInclude : public QObject +{ + Q_OBJECT + private slots: + void testClassExtraInclude(); + void testGlobalExtraIncludes(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testfunctiontag.cpp b/sources/shiboken2/ApiExtractor/tests/testfunctiontag.cpp new file mode 100644 index 000000000..a29d740bf --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testfunctiontag.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testfunctiontag.h" +#include +#include "testutil.h" +#include +#include + +void TestFunctionTag::testFunctionTagForSpecificSignature() +{ + const char cppCode[] = "void globalFunction(int); void globalFunction(float); void dummy();\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + const TypeEntry *func = TypeDatabase::instance()->findType(QLatin1String("globalFunction")); + QVERIFY(func); + QCOMPARE(builder->globalFunctions().size(), 1); +} + +void TestFunctionTag::testFunctionTagForAllSignatures() +{ + const char cppCode[] = "void globalFunction(int); void globalFunction(float); void dummy();\n"; + const char xmlCode[] = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + const TypeEntry *func = TypeDatabase::instance()->findType(QLatin1String("globalFunction")); + QVERIFY(func); + QCOMPARE(builder->globalFunctions().size(), 2); +} + +void TestFunctionTag::testRenameGlobalFunction() +{ + const char* cppCode ="void global_function_with_ugly_name();\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + const TypeEntry *func = TypeDatabase::instance()->findType(QLatin1String("global_function_with_ugly_name")); + QVERIFY(func); + + QCOMPARE(builder->globalFunctions().size(), 1); + const AbstractMetaFunction* metaFunc = builder->globalFunctions().first(); + + QVERIFY(metaFunc); + QCOMPARE(metaFunc->modifications().size(), 1); + QVERIFY(metaFunc->modifications().first().isRenameModifier()); + QCOMPARE(metaFunc->modifications().first().renamedTo(), QLatin1String("smooth")); + + QCOMPARE(metaFunc->name(), QLatin1String("smooth")); + QCOMPARE(metaFunc->originalName(), QLatin1String("global_function_with_ugly_name")); + QCOMPARE(metaFunc->minimalSignature(), QLatin1String("global_function_with_ugly_name()")); +} + +QTEST_APPLESS_MAIN(TestFunctionTag) + diff --git a/sources/shiboken2/ApiExtractor/tests/testfunctiontag.h b/sources/shiboken2/ApiExtractor/tests/testfunctiontag.h new file mode 100644 index 000000000..d4b6c7d2c --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testfunctiontag.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTFUNCTIONTAG_H +#define TESTFUNCTIONTAG_H +#include + +class TestFunctionTag : public QObject +{ + Q_OBJECT +private slots: + void testFunctionTagForSpecificSignature(); + void testFunctionTagForAllSignatures(); + void testRenameGlobalFunction(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.cpp b/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.cpp new file mode 100644 index 000000000..7e8db42f3 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testimplicitconversions.h" +#include "testutil.h" +#include +#include +#include + +void TestImplicitConversions::testWithPrivateCtors() +{ + const char* cppCode ="\ + class B;\n\ + class C;\n\ + class A {\n\ + A(const B&);\n\ + public:\n\ + A(const C&);\n\ + };\n\ + class B {};\n\ + class C {};\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 3); + + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C")); + AbstractMetaFunctionList implicitConvs = classA->implicitConversions(); + QCOMPARE(implicitConvs.count(), 1); + QCOMPARE(implicitConvs.first()->arguments().first()->type()->typeEntry(), classC->typeEntry()); +} + +void TestImplicitConversions::testWithModifiedVisibility() +{ + const char* cppCode ="\ + class B;\n\ + class A {\n\ + public:\n\ + A(const B&);\n\ + };\n\ + class B {};\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + AbstractMetaFunctionList implicitConvs = classA->implicitConversions(); + QCOMPARE(implicitConvs.count(), 1); + QCOMPARE(implicitConvs.first()->arguments().first()->type()->typeEntry(), classB->typeEntry()); +} + + +void TestImplicitConversions::testWithAddedCtor() +{ + const char* cppCode ="\ + class B;\n\ + class A {\n\ + public:\n\ + A(const B&);\n\ + };\n\ + class B {};\n\ + class C {};\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 3); + + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + AbstractMetaFunctionList implicitConvs = classA->implicitConversions(); + QCOMPARE(implicitConvs.count(), 2); + + // Added constructors with custom types should never result in implicit converters. + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + implicitConvs = classB->implicitConversions(); + QCOMPARE(implicitConvs.count(), 0); +} + +void TestImplicitConversions::testWithExternalConversionOperator() +{ + const char* cppCode ="\ + class A {};\n\ + struct B {\n\ + operator A() const;\n\ + };\n"; + const char* xmlCode = "\n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + AbstractMetaFunctionList implicitConvs = classA->implicitConversions(); + QCOMPARE(implicitConvs.count(), 1); + AbstractMetaFunctionList externalConvOps = classA->externalConversionOperators(); + QCOMPARE(externalConvOps.count(), 1); + + const AbstractMetaFunction* convOp = 0; + for (const AbstractMetaFunction *func : classB->functions()) { + if (func->isConversionOperator()) + convOp = func; + } + QVERIFY(convOp); + QCOMPARE(implicitConvs.first(), convOp); +} + +QTEST_APPLESS_MAIN(TestImplicitConversions) diff --git a/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.h b/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.h new file mode 100644 index 000000000..657c1a558 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTIMPLICITCONVERSIONS_H +#define TESTIMPLICITCONVERSIONS_H + +#include + +class AbstractMetaBuilder; + +class TestImplicitConversions : public QObject +{ + Q_OBJECT +private slots: + void testWithPrivateCtors(); + void testWithModifiedVisibility(); + void testWithAddedCtor(); + void testWithExternalConversionOperator(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testinserttemplate.cpp b/sources/shiboken2/ApiExtractor/tests/testinserttemplate.cpp new file mode 100644 index 000000000..ecadf311b --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testinserttemplate.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testinserttemplate.h" +#include +#include "testutil.h" +#include +#include + +void TestInsertTemplate::testInsertTemplateOnClassInjectCode() +{ + const char* cppCode ="struct A{};\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 1); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->typeEntry()->codeSnips().count(), 1); + QString code = classA->typeEntry()->codeSnips().first().code(); + QVERIFY(code.contains(QLatin1String("code template content"))); +} + +void TestInsertTemplate::testInsertTemplateOnModuleInjectCode() +{ + const char* cppCode =""; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QVERIFY(classes.isEmpty()); + + TypeEntry* module = TypeDatabase::instance()->findType(QLatin1String("Foo")); + QVERIFY(module); + QCOMPARE(module->codeSnips().count(), 1); + QString code = module->codeSnips().first().code().trimmed(); + QVERIFY(code.contains(QLatin1String("code template content"))); +} + +void TestInsertTemplate::testInvalidTypeSystemTemplate() +{ + const char* cppCode =""; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QVERIFY(classes.isEmpty()); + + TypeEntry* module = TypeDatabase::instance()->findType(QLatin1String("Foo")); + QVERIFY(module); + QCOMPARE(module->codeSnips().count(), 1); + QString code = module->codeSnips().first().code().trimmed(); + QVERIFY(code.isEmpty()); +} + +void TestInsertTemplate::testValidAndInvalidTypeSystemTemplate() +{ + const char* cppCode =""; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QVERIFY(classes.isEmpty()); + + TypeEntry* module = TypeDatabase::instance()->findType(QLatin1String("Foo")); + QVERIFY(module); + QCOMPARE(module->codeSnips().count(), 1); + QString code = module->codeSnips().first().code().trimmed(); + QVERIFY(code.contains(QLatin1String("code template content"))); +} + +QTEST_APPLESS_MAIN(TestInsertTemplate) diff --git a/sources/shiboken2/ApiExtractor/tests/testinserttemplate.h b/sources/shiboken2/ApiExtractor/tests/testinserttemplate.h new file mode 100644 index 000000000..0e2a882fe --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testinserttemplate.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTINSERTTEMPLATE_H +#define TESTINSERTTEMPLATE_H + +#include + +class TestInsertTemplate : public QObject +{ + Q_OBJECT + private slots: + void testInsertTemplateOnClassInjectCode(); + void testInsertTemplateOnModuleInjectCode(); + void testInvalidTypeSystemTemplate(); + void testValidAndInvalidTypeSystemTemplate(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp new file mode 100644 index 000000000..96bd0251b --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testmodifydocumentation.h" + +#include +#include +#include "testutil.h" +#include +#include +#include + +void TestModifyDocumentation::testModifyDocumentation() +{ + const char* cppCode ="struct B { void b(); }; class A {};\n"; + const char* xmlCode = "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + <para>Some changed contents here</para>\n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + QVERIFY(classA); + DocModificationList docMods = classA->typeEntry()->docModifications(); + QCOMPARE(docMods.count(), 1); + QCOMPARE(docMods[0].code().trimmed(), QLatin1String("Some changed contents here")); + QCOMPARE(docMods[0].signature(), QString()); + QtDocParser docParser; + docParser.setDocumentationDataDirectory(QDir::currentPath()); + docParser.fillDocumentation(classA); + + QVERIFY(!classA->documentation().value().trimmed().isEmpty()); + QCOMPARE(classA->documentation().value(), QLatin1String("\n\ +oi\n\ + Paragraph number 1\n\ + Paragraph number 2\n\ + Some changed contents here\n\ +\n")); +} + +// We expand QTEST_MAIN macro but using QCoreApplication instead of QApplication +// because this test needs an event loop but can't use QApplication to avoid a crash +// on our ARMEL/FRAMANTLE buildbot +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + TestModifyDocumentation tc; + return QTest::qExec(&tc, argc, argv); +} diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.h b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.h new file mode 100644 index 000000000..fb8f6fc01 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTMODIFYDOCUMENTATION_H +#define TESTMODIFYDOCUMENTATION_H + +#include + +class TestModifyDocumentation : public QObject +{ +Q_OBJECT +private slots: + void testModifyDocumentation(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp new file mode 100644 index 000000000..3d4ef9c89 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testmodifyfunction.h" +#include +#include "testutil.h" +#include +#include + +void TestModifyFunction::testRenameArgument() +{ + const char* cppCode ="\ + struct A {\n\ + void method(int=0);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const AbstractMetaFunction* func = classA->findFunction(QLatin1String("method")); + Q_ASSERT(func); + + QCOMPARE(func->argumentName(1), QLatin1String("otherArg")); +} + +void TestModifyFunction::testOwnershipTransfer() +{ + const char* cppCode ="\ + struct A {};\n\ + struct B {\n\ + virtual A* method();\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const AbstractMetaFunction* func = classB->findFunction(QLatin1String("method")); + + QCOMPARE(func->ownership(func->ownerClass(), TypeSystem::TargetLangCode, 0), TypeSystem::CppOwnership); +} + + +void TestModifyFunction::invalidateAfterUse() +{ + const char* cppCode ="\ + struct A {\n\ + virtual void call(int *a);\n\ + };\n\ + struct B : A {\n\ + };\n\ + struct C : B {\n\ + virtual void call2(int *a);\n\ + };\n\ + struct D : C {\n\ + virtual void call2(int *a);\n\ + };\n\ + struct E : D {\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false, "0.1")); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const AbstractMetaFunction* func = classB->findFunction(QLatin1String("call")); + QCOMPARE(func->modifications().size(), 1); + QCOMPARE(func->modifications().at(0).argument_mods.size(), 1); + QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse); + + const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C")); + QVERIFY(classC); + func = classC->findFunction(QLatin1String("call")); + QCOMPARE(func->modifications().size(), 1); + QCOMPARE(func->modifications().at(0).argument_mods.size(), 1); + QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse); + + func = classC->findFunction(QLatin1String("call2")); + QCOMPARE(func->modifications().size(), 1); + QCOMPARE(func->modifications().at(0).argument_mods.size(), 1); + QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse); + + const AbstractMetaClass *classD = AbstractMetaClass::findClass(classes, QLatin1String("D")); + QVERIFY(classD); + func = classD->findFunction(QLatin1String("call")); + QCOMPARE(func->modifications().size(), 1); + QCOMPARE(func->modifications().at(0).argument_mods.size(), 1); + QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse); + + func = classD->findFunction(QLatin1String("call2")); + QCOMPARE(func->modifications().size(), 1); + QCOMPARE(func->modifications().at(0).argument_mods.size(), 1); + QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse); + + const AbstractMetaClass *classE = AbstractMetaClass::findClass(classes, QLatin1String("E")); + QVERIFY(classE); + func = classE->findFunction(QLatin1String("call")); + QVERIFY(func); + QCOMPARE(func->modifications().size(), 1); + QCOMPARE(func->modifications().at(0).argument_mods.size(), 1); + QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse); + + func = classE->findFunction(QLatin1String("call2")); + QVERIFY(func); + QCOMPARE(func->modifications().size(), 1); + QCOMPARE(func->modifications().at(0).argument_mods.size(), 1); + QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse); +} + +void TestModifyFunction::testWithApiVersion() +{ + const char* cppCode ="\ + struct A {};\n\ + struct B {\n\ + virtual A* method();\n\ + virtual B* methodB();\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false, "0.1")); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const AbstractMetaFunction* func = classB->findFunction(QLatin1String("method")); + + QCOMPARE(func->ownership(func->ownerClass(), TypeSystem::TargetLangCode, 0), TypeSystem::CppOwnership); + + func = classB->findFunction(QLatin1String("methodB")); + QVERIFY(func->ownership(func->ownerClass(), TypeSystem::TargetLangCode, 0) != TypeSystem::CppOwnership); +} + +void TestModifyFunction::testGlobalFunctionModification() +{ + const char* cppCode ="\ + struct A {};\n\ + void function(A* a = 0);\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + QCOMPARE(builder->globalFunctions().size(), 1); + + FunctionModificationList mods = TypeDatabase::instance()->functionModifications(QLatin1String("function(A*)")); + QCOMPARE(mods.count(), 1); + QVector argMods = mods.first().argument_mods; + QCOMPARE(argMods.count(), 1); + ArgumentModification argMod = argMods.first(); + QCOMPARE(argMod.replacedDefaultExpression, QLatin1String("A()")); + + const AbstractMetaFunction* func = builder->globalFunctions().first(); + QVERIFY(func); + QCOMPARE(func->arguments().count(), 1); + const AbstractMetaArgument* arg = func->arguments().first(); + QCOMPARE(arg->type()->cppSignature(), QLatin1String("A *")); + QCOMPARE(arg->originalDefaultValueExpression(), QLatin1String("0")); + QCOMPARE(arg->defaultValueExpression(), QLatin1String("A()")); +} + +QTEST_APPLESS_MAIN(TestModifyFunction) diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h new file mode 100644 index 000000000..fcaa0f9db --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTABSTRACTMETACLASS_H +#define TESTABSTRACTMETACLASS_H + +#include + +class TestModifyFunction : public QObject +{ + Q_OBJECT + private slots: + void testOwnershipTransfer(); + void testWithApiVersion(); + void testRenameArgument(); + void invalidateAfterUse(); + void testGlobalFunctionModification(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.cpp b/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.cpp new file mode 100644 index 000000000..b78e6ec01 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testmultipleinheritance.h" +#include +#include "testutil.h" +#include +#include + +void TestMultipleInheritance::testVirtualClass() +{ + const char* cppCode ="\ + struct A {\n\ + virtual ~A();\n\ + virtual void theBug();\n\ + };\n\ + struct B {\n\ + virtual ~B();\n\ + };\n\ + struct C : A, B {\n\ + };\n\ + struct D : C {\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 4); + + const AbstractMetaClass *classD = AbstractMetaClass::findClass(classes, QLatin1String("D")); + bool functionFound = false; + const AbstractMetaFunctionList &functions = classD->functions(); + for (AbstractMetaFunction *f : functions) { + if (f->name() == QLatin1String("theBug")) { + functionFound = true; + break; + } + } + QVERIFY(functionFound); + +} + +QTEST_APPLESS_MAIN(TestMultipleInheritance) diff --git a/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.h b/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.h new file mode 100644 index 000000000..2313073bb --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTMULTIPLEINHERITANCE_H +#define TESTMULTIPLEINHERITANCE_H + +#include + +class AbstractMetaBuilder; + +class TestMultipleInheritance : public QObject +{ + Q_OBJECT + private slots: + void testVirtualClass(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testnamespace.cpp b/sources/shiboken2/ApiExtractor/tests/testnamespace.cpp new file mode 100644 index 000000000..ca6ce0589 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testnamespace.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testnamespace.h" +#include +#include "testutil.h" +#include +#include + +void NamespaceTest::testNamespaceMembers() +{ + const char* cppCode = "\ + namespace Namespace\n\ + {\n\ + enum Option {\n\ + OpZero,\n\ + OpOne\n\ + };\n\ + void foo(Option opt);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + AbstractMetaClass *ns = AbstractMetaClass::findClass(classes, QLatin1String("Namespace")); + QVERIFY(ns); + const AbstractMetaEnum* metaEnum = ns->findEnum(QLatin1String("Option")); + QVERIFY(metaEnum); + const AbstractMetaFunction* func = ns->findFunction(QLatin1String("foo")); + QVERIFY(func); +} + +void NamespaceTest::testNamespaceInnerClassMembers() +{ + const char* cppCode = "\ + namespace OuterNamespace\n\ + {\n\ + namespace InnerNamespace {\n\ + struct SomeClass {\n\ + void method();\n\ + };\n\ + };\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *ons = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace")); + QVERIFY(ons); + const AbstractMetaClass *ins = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace")); + QVERIFY(ins); + const AbstractMetaClass *sc = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace::SomeClass")); + QVERIFY(sc); + const AbstractMetaFunction* meth = sc->findFunction(QLatin1String("method")); + QVERIFY(meth); +} + +QTEST_APPLESS_MAIN(NamespaceTest) + diff --git a/sources/shiboken2/ApiExtractor/tests/testnamespace.h b/sources/shiboken2/ApiExtractor/tests/testnamespace.h new file mode 100644 index 000000000..d4451a938 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testnamespace.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTNAMESPACE_H +#define TESTNAMESPACE_H + +#include + +// The class is named 'NamespaceTest' to avoid clashes with Qt COIN using +// '-qtnamespace TestNamespace'. +class NamespaceTest : public QObject +{ + Q_OBJECT + private slots: + void testNamespaceMembers(); + void testNamespaceInnerClassMembers(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testnestedtypes.cpp b/sources/shiboken2/ApiExtractor/tests/testnestedtypes.cpp new file mode 100644 index 000000000..296aa4385 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testnestedtypes.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testnestedtypes.h" +#include +#include "testutil.h" +#include +#include + +void TestNestedTypes::testNestedTypesModifications() +{ + const char* cppCode ="\ + namespace OuterNamespace {\n\ + namespace InnerNamespace {\n\ + struct SomeClass {\n\ + void method() {}\n\ + };\n\ + };\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + custom_code1();\n\ + \n\ + custom_code2();\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + + const AbstractMetaClass *ons = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace")); + QVERIFY(ons); + + const AbstractMetaClass *ins = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace")); + QVERIFY(ins); + QCOMPARE(ins->functions().count(), 1); + QCOMPARE(ins->typeEntry()->codeSnips().count(), 1); + CodeSnip snip = ins->typeEntry()->codeSnips().first(); + QCOMPARE(snip.code(), QLatin1String("custom_code1();")); + + AbstractMetaFunction* addedFunc = ins->functions().first(); + QVERIFY(addedFunc->isUserAdded()); + QCOMPARE(addedFunc->visibility(), AbstractMetaFunction::Public); + QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction); + QCOMPARE(addedFunc->type()->minimalSignature(), QLatin1String("OuterNamespace::InnerNamespace::SomeClass")); + + QCOMPARE(addedFunc->modifications().size(), 1); + QVERIFY(addedFunc->modifications().first().isCodeInjection()); + snip = addedFunc->modifications().first().snips.first(); + QCOMPARE(snip.code(), QLatin1String("custom_code2();")); + + const AbstractMetaClass *sc = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace::SomeClass")); + QVERIFY(ins); + QCOMPARE(sc->functions().count(), 2); // default constructor and removed method + AbstractMetaFunction* removedFunc = sc->functions().last(); + QVERIFY(removedFunc->isModifiedRemoved()); +} + + +void TestNestedTypes::testDuplicationOfNestedTypes() +{ + const char* cppCode ="\ + namespace Namespace {\n\ + class SomeClass {};\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 2); + const AbstractMetaClass *nspace = AbstractMetaClass::findClass(classes, QLatin1String("Namespace")); + QVERIFY(nspace); + const AbstractMetaClass *cls1 = AbstractMetaClass::findClass(classes, QLatin1String("SomeClass")); + QVERIFY(cls1); + const AbstractMetaClass *cls2 = AbstractMetaClass::findClass(classes, QLatin1String("Namespace::SomeClass")); + QVERIFY(cls2); + QCOMPARE(cls1, cls2); + QCOMPARE(cls1->name(), QLatin1String("SomeClass")); + QCOMPARE(cls1->qualifiedCppName(), QLatin1String("Namespace::SomeClass")); + + TypeEntry* t1 = TypeDatabase::instance()->findType(QLatin1String("Namespace::SomeClass")); + QVERIFY(t1); + TypeEntry* t2 = TypeDatabase::instance()->findType(QLatin1String("SomeClass")); + QVERIFY(!t2); +} + +QTEST_APPLESS_MAIN(TestNestedTypes) diff --git a/sources/shiboken2/ApiExtractor/tests/testnestedtypes.h b/sources/shiboken2/ApiExtractor/tests/testnestedtypes.h new file mode 100644 index 000000000..737e81fab --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testnestedtypes.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTNESTEDTYPES_H +#define TESTNESTEDTYPES_H +#include + +class TestNestedTypes : public QObject +{ + Q_OBJECT +private slots: + void testNestedTypesModifications(); + void testDuplicationOfNestedTypes(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.cpp b/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.cpp new file mode 100644 index 000000000..3491d5cb4 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testnumericaltypedef.h" +#include +#include "testutil.h" +#include +#include + +void TestNumericalTypedef::testNumericalTypedef() +{ + const char* cppCode ="\ + typedef double real;\n\ + void funcDouble(double);\n\ + void funcReal(real);\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + QCOMPARE(builder->globalFunctions().size(), 2); + const AbstractMetaFunction* funcDouble = builder->globalFunctions().first(); + QVERIFY(funcDouble); + const AbstractMetaFunction* funcReal = builder->globalFunctions().last(); + QVERIFY(funcReal); + + if (funcDouble->name() == QLatin1String("funcReal")) + std::swap(funcDouble, funcReal); + + QCOMPARE(funcDouble->minimalSignature(), QLatin1String("funcDouble(double)")); + QCOMPARE(funcReal->minimalSignature(), QLatin1String("funcReal(real)")); + + const AbstractMetaType* doubleType = funcDouble->arguments().first()->type(); + QVERIFY(doubleType); + QCOMPARE(doubleType->cppSignature(), QLatin1String("double")); + QVERIFY(doubleType->isPrimitive()); + QVERIFY(doubleType->typeEntry()->isCppPrimitive()); + + const AbstractMetaType* realType = funcReal->arguments().first()->type(); + QVERIFY(realType); + QCOMPARE(realType->cppSignature(), QLatin1String("real")); + QVERIFY(realType->isPrimitive()); + QVERIFY(realType->typeEntry()->isCppPrimitive()); +} + +void TestNumericalTypedef::testUnsignedNumericalTypedef() +{ + const char* cppCode ="\ + typedef unsigned short ushort;\n\ + void funcUnsignedShort(unsigned short);\n\ + void funcUShort(ushort);\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + QCOMPARE(builder->globalFunctions().size(), 2); + const AbstractMetaFunction* funcUnsignedShort = builder->globalFunctions().first(); + QVERIFY(funcUnsignedShort); + const AbstractMetaFunction* funcUShort = builder->globalFunctions().last(); + QVERIFY(funcUShort); + + if (funcUnsignedShort->name() == QLatin1String("funcUShort")) + std::swap(funcUnsignedShort, funcUShort); + + QCOMPARE(funcUnsignedShort->minimalSignature(), QLatin1String("funcUnsignedShort(unsigned short)")); + QCOMPARE(funcUShort->minimalSignature(), QLatin1String("funcUShort(ushort)")); + + const AbstractMetaType* unsignedShortType = funcUnsignedShort->arguments().first()->type(); + QVERIFY(unsignedShortType); + QCOMPARE(unsignedShortType->cppSignature(), QLatin1String("unsigned short")); + QVERIFY(unsignedShortType->isPrimitive()); + QVERIFY(unsignedShortType->typeEntry()->isCppPrimitive()); + + const AbstractMetaType* ushortType = funcUShort->arguments().first()->type(); + QVERIFY(ushortType); + QCOMPARE(ushortType->cppSignature(), QLatin1String("ushort")); + QVERIFY(ushortType->isPrimitive()); + QVERIFY(ushortType->typeEntry()->isCppPrimitive()); +} + +QTEST_APPLESS_MAIN(TestNumericalTypedef) + diff --git a/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.h b/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.h new file mode 100644 index 000000000..e8af1fa8e --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTNUMERICALTYPEDEF_H +#define TESTNUMERICALTYPEDEF_H + +#include + +class TestNumericalTypedef : public QObject +{ + Q_OBJECT + private slots: + void testNumericalTypedef(); + void testUnsignedNumericalTypedef(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.cpp b/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.cpp new file mode 100644 index 000000000..7646dd23a --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testprimitivetypetag.h" +#include +#include "testutil.h" +#include +#include + +void TestPrimitiveTypeTag::testPrimitiveTypeDefaultConstructor() +{ + const char* cppCode ="\ + struct A {};\n\ + struct B {};\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 1); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + + PrimitiveTypeEntry* typeEntry = TypeDatabase::instance()->findPrimitiveType(QLatin1String("A")); + QVERIFY(typeEntry); + QVERIFY(typeEntry->hasDefaultConstructor()); + QCOMPARE(typeEntry->defaultConstructor(), QLatin1String("A()")); +} + +QTEST_APPLESS_MAIN(TestPrimitiveTypeTag) + diff --git a/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.h b/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.h new file mode 100644 index 000000000..ea9276de3 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTPRIMITIVETYPETAG_H +#define TESTPRIMITIVETYPETAG_H + +#include + +class TestPrimitiveTypeTag : public QObject +{ + Q_OBJECT + private slots: + void testPrimitiveTypeDefaultConstructor(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp new file mode 100644 index 000000000..e9f9f0ab7 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testrefcounttag.h" +#include +#include "testutil.h" +#include +#include + +void TestRefCountTag::testReferenceCountTag() +{ + const char* cppCode ="\ + struct A {};\n\ + struct B {\n\ + void keepObject(B* b);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const AbstractMetaFunction* func = classB->findFunction(QLatin1String("keepObject")); + QVERIFY(func); + ReferenceCount refCount = func->modifications().first().argument_mods.first().referenceCounts.first(); + QCOMPARE(refCount.action, ReferenceCount::Add); +} + +void TestRefCountTag::testWithApiVersion() +{ + const char* cppCode ="\ + struct A {};\n\ + struct B {\n\ + void keepObject(B*, B*);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false, "0.1")); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const AbstractMetaFunction* func = classB->findFunction(QLatin1String("keepObject")); + QVERIFY(func); + ReferenceCount refCount = func->modifications().first().argument_mods.first().referenceCounts.first(); + QCOMPARE(refCount.action, ReferenceCount::Add); + + QCOMPARE(func->modifications().size(), 1); +} + + +QTEST_APPLESS_MAIN(TestRefCountTag) + + diff --git a/sources/shiboken2/ApiExtractor/tests/testrefcounttag.h b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.h new file mode 100644 index 000000000..a95661293 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTREFCOUNTTAG_H +#define TESTREFCOUNTTAG_H + +#include + +class TestRefCountTag : public QObject +{ + Q_OBJECT + private slots: + void testReferenceCountTag(); + void testWithApiVersion(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.cpp b/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.cpp new file mode 100644 index 000000000..f594cdd25 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testreferencetopointer.h" +#include +#include "testutil.h" +#include +#include + +void TestReferenceToPointer::testReferenceToPointerArgument() +{ + const char* cppCode ="\ + struct A {};\n\ + struct B {\n\ + void dummy(A*&);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + const AbstractMetaFunction* func = classB->findFunction(QLatin1String("dummy")); + QVERIFY(func); + QCOMPARE(func->arguments().first()->type()->minimalSignature(), QLatin1String("A*&")); +} + +QTEST_APPLESS_MAIN(TestReferenceToPointer) + + diff --git a/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.h b/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.h new file mode 100644 index 000000000..83b0b6fad --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTREFERENCETOPOINTER_H +#define TESTREFERENCETOPOINTER_H + +#include + +class TestReferenceToPointer : public QObject +{ + Q_OBJECT + private slots: + void testReferenceToPointerArgument(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testremovefield.cpp b/sources/shiboken2/ApiExtractor/tests/testremovefield.cpp new file mode 100644 index 000000000..7ebe49160 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testremovefield.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testremovefield.h" +#include +#include "testutil.h" +#include +#include + +void TestRemoveField::testRemoveField() +{ + const char* cppCode ="\ + struct A {\n\ + int fieldA;\n\ + int fieldB;\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->fields().size(), 1); + const AbstractMetaField* fieldA = classA->fields().first(); + QVERIFY(fieldA); + QCOMPARE(fieldA->name(), QLatin1String("fieldA")); +} + +QTEST_APPLESS_MAIN(TestRemoveField) + + diff --git a/sources/shiboken2/ApiExtractor/tests/testremovefield.h b/sources/shiboken2/ApiExtractor/tests/testremovefield.h new file mode 100644 index 000000000..ea103e0cc --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testremovefield.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTREMOVEFIELD_H +#define TESTREMOVEFIELD_H + +#include + +class TestRemoveField : public QObject +{ + Q_OBJECT + private slots: + void testRemoveField(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.cpp b/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.cpp new file mode 100644 index 000000000..a81380873 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testremoveimplconv.h" +#include "testutil.h" +#include +#include +#include + +// When a constructor able to trigger implicity conversions is removed +// it should not appear in the implicity conversion list. +void TestRemoveImplConv::testRemoveImplConv() +{ + const char* cppCode ="\ + struct A {};\n\ + struct B {};\n\ + struct C {\n\ + C(const A&);\n\ + C(const B&);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 3); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C")); + QVERIFY(classC); + AbstractMetaFunctionList implConv = classC->implicitConversions(); + QCOMPARE(implConv.count(), 1); + QCOMPARE(implConv.first()->arguments().first()->type()->typeEntry(), classB->typeEntry()); +} + +QTEST_APPLESS_MAIN(TestRemoveImplConv) diff --git a/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.h b/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.h new file mode 100644 index 000000000..62d5f74e6 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTREMOVEIMPLCONV_H +#define TESTREMOVEIMPLCONV_H + +#include + +class TestRemoveImplConv : public QObject +{ +Q_OBJECT +private slots: + void testRemoveImplConv(); +}; + +#endif // TESTREMOVEIMPLCONV_H diff --git a/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.cpp b/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.cpp new file mode 100644 index 000000000..508cff586 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testremoveoperatormethod.h" +#include +#include "testutil.h" +#include +#include + +void TestRemoveOperatorMethod::testRemoveOperatorMethod() +{ + const char* cppCode ="\ + #include \n\ + \n\ + struct Char {};\n\ + struct ByteArray {};\n\ + struct String {};\n\ + \n\ + struct A {\n\ + A& operator>>(char&);\n\ + A& operator>>(char*);\n\ + A& operator>>(short&);\n\ + A& operator>>(unsigned short&);\n\ + A& operator>>(int&);\n\ + A& operator>>(unsigned int&);\n\ + A& operator>>(int64_t&);\n\ + A& operator>>(uint64_t&);\n\ + A& operator>>(float&);\n\ + A& operator>>(double&);\n\ + A& operator>>(Char&);\n\ + A& operator>>(ByteArray&);\n\ + A& operator>>(String&);\n\ + };\n"; + const char* xmlCode = "\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n"; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->functions().size(), 14); + QStringList removedSignatures; + removedSignatures.append(QLatin1String("operator>>(char&)")); + removedSignatures.append(QLatin1String("operator>>(char*)")); + removedSignatures.append(QLatin1String("operator>>(short&)")); + removedSignatures.append(QLatin1String("operator>>(unsigned short&)")); + removedSignatures.append(QLatin1String("operator>>(int&)")); + removedSignatures.append(QLatin1String("operator>>(unsigned int&)")); + removedSignatures.append(QLatin1String("operator>>(int64_t&)")); + removedSignatures.append(QLatin1String("operator>>(uint64_t&)")); + removedSignatures.append(QLatin1String("operator>>(float&)")); + removedSignatures.append(QLatin1String("operator>>(double&)")); + removedSignatures.append(QLatin1String("operator>>(Char&)")); + removedSignatures.append(QLatin1String("operator>>(String&)")); + int notRemoved = classA->functions().size(); + const AbstractMetaFunctionList &functions = classA->functions(); + for (const AbstractMetaFunction *f : functions) { + QCOMPARE(f->isModifiedRemoved(), bool(removedSignatures.contains(f->minimalSignature()))); + notRemoved -= int(f->isModifiedRemoved()); + } + QCOMPARE(notRemoved, 2); +} + +QTEST_APPLESS_MAIN(TestRemoveOperatorMethod) + diff --git a/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.h b/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.h new file mode 100644 index 000000000..17ff75d74 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTREMOVEOPERATORMETHOD_H +#define TESTREMOVEOPERATORMETHOD_H + +#include + +class TestRemoveOperatorMethod : public QObject +{ + Q_OBJECT + private slots: + void testRemoveOperatorMethod(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp b/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp new file mode 100644 index 000000000..69691e860 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testresolvetype.h" +#include +#include "testutil.h" +#include +#include + +void TestResolveType::testResolveReturnTypeFromParentScope() +{ + const char* cppCode = "\n\ + namespace A {\n\ + struct B {\n\ + struct C {};\n\ + };\n\ + struct D : public B::C {\n\ + C* foo = 0;\n\ + C* method();\n\ + };\n\ + };"; + const char* xmlCode = "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + "; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classD = AbstractMetaClass::findClass(classes, QLatin1String("A::D")); + QVERIFY(classD); + const AbstractMetaFunction* meth = classD->findFunction(QLatin1String("method")); + QVERIFY(meth); +} + +QTEST_APPLESS_MAIN(TestResolveType) + diff --git a/sources/shiboken2/ApiExtractor/tests/testresolvetype.h b/sources/shiboken2/ApiExtractor/tests/testresolvetype.h new file mode 100644 index 000000000..6164d0074 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testresolvetype.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTRESOLVETYPE_H +#define TESTRESOLVETYPE_H + +#include + +class TestResolveType : public QObject +{ + Q_OBJECT + private slots: + void testResolveReturnTypeFromParentScope(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testreverseoperators.cpp b/sources/shiboken2/ApiExtractor/tests/testreverseoperators.cpp new file mode 100644 index 000000000..18d6902c2 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testreverseoperators.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testreverseoperators.h" +#include +#include "testutil.h" +#include +#include + +void TestReverseOperators::testReverseSum() +{ + const char cppCode[] = "struct A {\n\ + A& operator+(int);\n\ + };\n\ + A& operator+(int, const A&);"; + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + "; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->functions().count(), 4); + + const AbstractMetaFunction* reverseOp = 0; + const AbstractMetaFunction* normalOp = 0; + for (const AbstractMetaFunction *func : classA->functions()) { + if (func->name() == QLatin1String("operator+")) { + if (func->isReverseOperator()) + reverseOp = func; + else + normalOp = func; + } + } + + QVERIFY(normalOp); + QVERIFY(!normalOp->isReverseOperator()); + QCOMPARE(normalOp->arguments().count(), 1); + QVERIFY(reverseOp); + QVERIFY(reverseOp->isReverseOperator()); + QCOMPARE(reverseOp->arguments().count(), 1); +} + +void TestReverseOperators::testReverseSumWithAmbiguity() +{ + const char cppCode[] = "\n\ + struct A { A operator+(int); };\n\ + A operator+(int, const A&);\n\ + struct B {};\n\ + B operator+(const A&, const B&);\n\ + B operator+(const B&, const A&);\n\ + int operator-(int, const A*);\n\ + int operator/(const A*, int);\n\ + "; + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + \n\ + "; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QEXPECT_FAIL("", "Clang: Does not compile", Abort); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QCOMPARE(classA->functions().count(), 6); + + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + QCOMPARE(classB->functions().count(), 4); + + const AbstractMetaFunction* reverseOp = 0; + const AbstractMetaFunction* normalOp = 0; + for (const AbstractMetaFunction *func : classB->functions()) { + if (func->name() == QLatin1String("operator+")) { + if (func->isReverseOperator()) + reverseOp = func; + else + normalOp = func; + } + } + QVERIFY(normalOp); + QVERIFY(!normalOp->isReverseOperator()); + QCOMPARE(normalOp->arguments().count(), 1); + QCOMPARE(normalOp->minimalSignature(), QLatin1String("operator+(B,A)")); + QVERIFY(reverseOp); + QVERIFY(reverseOp->isReverseOperator()); + QCOMPARE(reverseOp->arguments().count(), 1); + QCOMPARE(reverseOp->minimalSignature(), QLatin1String("operator+(A,B)")); + + reverseOp = classA->findFunction(QLatin1String("operator-")); + QVERIFY(reverseOp); + QCOMPARE(reverseOp->arguments().count(), 1); + QVERIFY(reverseOp->isPointerOperator()); + QVERIFY(reverseOp->isReverseOperator()); + + normalOp = classA->findFunction(QLatin1String("operator/")); + QVERIFY(normalOp); + QCOMPARE(normalOp->arguments().count(), 1); + QVERIFY(normalOp->isPointerOperator()); + QVERIFY(!normalOp->isReverseOperator()); + +} + + + +QTEST_APPLESS_MAIN(TestReverseOperators) + diff --git a/sources/shiboken2/ApiExtractor/tests/testreverseoperators.h b/sources/shiboken2/ApiExtractor/tests/testreverseoperators.h new file mode 100644 index 000000000..3bd65fb85 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testreverseoperators.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTREVERSEOPERATORS_H +#define TESTREVERSEOPERATORS_H +#include + +class TestReverseOperators : public QObject +{ + Q_OBJECT +private slots: + void testReverseSum(); + void testReverseSumWithAmbiguity(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp new file mode 100644 index 000000000..4a66264d8 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp @@ -0,0 +1,439 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testtemplates.h" +#include +#include +#include "testutil.h" +#include +#include + +void TestTemplates::testTemplateWithNamespace() +{ + const char cppCode[] = "\n\ + template struct QList {}; \n\ + struct Url {\n\ + void name();\n\ + };\n\ + namespace Internet {\n\ + struct Url{};\n\ + struct Bookmarks {\n\ + QList list();\n\ + };\n\ + }"; + const char xmlCode0[] = "\n\ + \n\ + \n\ + "; + + QTemporaryFile file; + QVERIFY(file.open()); + file.write(xmlCode0); + file.close(); + + QString xmlCode1 = QString::fromLatin1("\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + ").arg(file.fileName()); + + QScopedPointer builder(TestUtil::parse(cppCode, qPrintable(xmlCode1), false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("Bookmarks")); + QVERIFY(classB); + const AbstractMetaFunction* func = classB->findFunction(QLatin1String("list")); + AbstractMetaType* funcType = func->type(); + QVERIFY(funcType); + QCOMPARE(funcType->cppSignature(), QLatin1String("QList")); +} + +void TestTemplates::testTemplateOnContainers() +{ + const char cppCode[] = "\n\ + struct Base {};\n\ + template struct QList {}; \n\ + namespace Namespace {\n\ + enum SomeEnum { E1, E2 };\n\ + template struct A {\n\ + A foo(const QList >& a);\n\ + };\n\ + typedef A B;\n\ + }\n\ + "; + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + "; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + QVERIFY(!classB->baseClass()); + QVERIFY(classB->baseClassName().isNull()); + const AbstractMetaFunction* func = classB->findFunction(QLatin1String("foo")); + AbstractMetaType* argType = func->arguments().first()->type(); + QCOMPARE(argType->instantiations().count(), 1); + QCOMPARE(argType->typeEntry()->qualifiedCppName(), QLatin1String("QList")); + + const AbstractMetaType* instance1 = argType->instantiations().first(); + QCOMPARE(instance1->instantiations().count(), 1); + QCOMPARE(instance1->typeEntry()->qualifiedCppName(), QLatin1String("Namespace::A")); + + const AbstractMetaType* instance2 = instance1->instantiations().first(); + QCOMPARE(instance2->instantiations().count(), 0); + QCOMPARE(instance2->typeEntry()->qualifiedCppName(), QLatin1String("Namespace::E1")); +} + +void TestTemplates::testTemplateValueAsArgument() +{ + const char cppCode[] = "\n\ + template struct List {};\n\ + void func(List arg) {}\n\ + "; + + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + "; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaFunctionList globalFuncs = builder->globalFunctions(); + QCOMPARE(globalFuncs.count(), 1); + + AbstractMetaFunction* func = globalFuncs.first(); + QCOMPARE(func->minimalSignature(), QLatin1String("func(List)")); + QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List")); +} + +void TestTemplates::testTemplatePointerAsArgument() +{ + const char cppCode[] = "\n\ + template struct List {};\n\ + void func(List* arg) {}\n\ + "; + + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + "; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaFunctionList globalFuncs = builder->globalFunctions(); + QCOMPARE(globalFuncs.count(), 1); + + AbstractMetaFunction* func = globalFuncs.first(); + QCOMPARE(func->minimalSignature(), QLatin1String("func(List*)")); + QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List *")); +} + +void TestTemplates::testTemplateReferenceAsArgument() +{ + const char cppCode[] = "\n\ + template struct List {};\n\ + void func(List& arg) {}\n\ + "; + + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + "; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaFunctionList globalFuncs = builder->globalFunctions(); + QCOMPARE(globalFuncs.count(), 1); + + AbstractMetaFunction* func = globalFuncs.first(); + QCOMPARE(func->minimalSignature(), QLatin1String("func(List&)")); + QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List &")); +} + +void TestTemplates::testTemplateParameterFixup() +{ + const char cppCode[] = "\n\ + template\n\ + struct List {\n\ + struct Iterator {};\n\ + void append(List l);\n\ + void erase(List::Iterator it);\n\ + };\n"; + + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + \n"; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + const AbstractMetaClassList templates = builder->templates(); + + QCOMPARE(templates.count(), 1); + const AbstractMetaClass *list = templates.first(); + // Verify that the parameter of "void append(List l)" gets fixed to "List" + const AbstractMetaFunction *append = list->findFunction(QStringLiteral("append")); + QVERIFY(append); + QCOMPARE(append->arguments().size(), 1); + QCOMPARE(append->arguments().at(0)->type()->cppSignature(), QLatin1String("List")); + // Verify that the parameter of "void erase(Iterator)" is not modified + const AbstractMetaFunction *erase = list->findFunction(QStringLiteral("erase")); + QVERIFY(erase); + QCOMPARE(erase->arguments().size(), 1); + QEXPECT_FAIL("", "Clang: Some other code changes the parameter type", Abort); + QCOMPARE(erase->arguments().at(0)->type()->cppSignature(), QLatin1String("List::Iterator")); +} + +void TestTemplates::testInheritanceFromContainterTemplate() +{ + const char cppCode[] = "\n\ + template\n\ + struct ListContainer {\n\ + inline void push_front(const T& t);\n\ + inline T& front();\n\ + };\n\ + struct FooBar {};\n\ + struct FooBars : public ListContainer {};\n\ + "; + + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + "; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + AbstractMetaClassList templates = builder->templates(); + QCOMPARE(classes.count(), 2); + QCOMPARE(templates.count(), 1); + + const AbstractMetaClass* foobars = AbstractMetaClass::findClass(classes, QLatin1String("FooBars")); + QCOMPARE(foobars->functions().count(), 4); + + const AbstractMetaClass* lc = templates.first(); + QCOMPARE(lc->functions().count(), 2); +} + +void TestTemplates::testTemplateInheritanceMixedWithForwardDeclaration() +{ + const char cppCode[] = "\n\ + enum SomeEnum { E1, E2 };\n\ + template struct Future;\n\ + template\n\ + struct A {\n\ + A();\n\ + void method();\n\ + friend struct Future;\n\ + };\n\ + typedef A B;\n\ + template struct Future {};\n\ + "; + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + "; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + QVERIFY(!classB->baseClass()); + QVERIFY(classB->baseClassName().isNull()); + // 3 functions: simple constructor, copy constructor and "method()". + QCOMPARE(classB->functions().count(), 3); +} + +void TestTemplates::testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration() +{ + const char cppCode[] = "\n\ + namespace Namespace {\n\ + enum SomeEnum { E1, E2 };\n\ + template struct Future;\n\ + template\n\ + struct A {\n\ + A();\n\ + void method();\n\ + friend struct Future;\n\ + };\n\ + typedef A B;\n\ + template struct Future {};\n\ + };\n\ + "; + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + "; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("Namespace::B")); + QVERIFY(classB); + QVERIFY(!classB->baseClass()); + QVERIFY(classB->baseClassName().isNull()); + // 3 functions: simple constructor, copy constructor and "method()". + QCOMPARE(classB->functions().count(), 3); +} + +void TestTemplates::testTypedefOfInstantiationOfTemplateClass() +{ + const char cppCode[] = "\n\ + namespace NSpace {\n\ + enum ClassType {\n\ + TypeOne\n\ + };\n\ + template\n\ + struct BaseTemplateClass {\n\ + inline ClassType getClassType() const { CLASS_TYPE; }\n\ + };\n\ + typedef BaseTemplateClass TypeOneClass;\n\ + }\n\ + "; + + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + "; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 3); + + const AbstractMetaClass* base = AbstractMetaClass::findClass(classes, QLatin1String("BaseTemplateClass")); + QVERIFY(base); + const AbstractMetaClass* one = AbstractMetaClass::findClass(classes, QLatin1String("TypeOneClass")); + QVERIFY(one); + QCOMPARE(one->templateBaseClass(), base); + QCOMPARE(one->functions().count(), base->functions().count()); + QVERIFY(one->isTypeDef()); + const ComplexTypeEntry* oneType = one->typeEntry(); + const ComplexTypeEntry* baseType = base->typeEntry(); + QCOMPARE(oneType->baseContainerType(), baseType); + QCOMPARE(one->baseClassNames(), QStringList(QLatin1String("BaseTemplateClass"))); + + QVERIFY(one->hasTemplateBaseClassInstantiations()); + AbstractMetaTypeList instantiations = one->templateBaseClassInstantiations(); + QCOMPARE(instantiations.count(), 1); + const AbstractMetaType* inst = instantiations.first(); + QVERIFY(inst); + QVERIFY(!inst->isEnum()); + QVERIFY(!inst->typeEntry()->isEnum()); + QVERIFY(inst->typeEntry()->isEnumValue()); + QCOMPARE(inst->cppSignature(), QLatin1String("NSpace::TypeOne")); +} + +void TestTemplates::testContainerTypeIncompleteArgument() +{ + const char* cppCode ="\n\ + template\n\ + class Vector {\n\ + void method(const Vector& vector);\n\ + Vector otherMethod();\n\ + };\n\ + template \n\ + void Vector::method(const Vector& vector) {}\n\ + template \n\ + Vector Vector::otherMethod() { return Vector(); }\n\ + typedef Vector IntVector;\n\ + "; + const char* xmlCode = "\n\ + \n\ + \n\ + \n\ + \n\ + "; + + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, true)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 1); + + AbstractMetaClass* vector = AbstractMetaClass::findClass(classes, QLatin1String("IntVector")); + QVERIFY(vector); + QVERIFY(vector->typeEntry()->baseContainerType()); + QCOMPARE(reinterpret_cast(vector->typeEntry()->baseContainerType())->type(), ContainerTypeEntry::VectorContainer); + QCOMPARE(vector->functions().count(), 4); + + const AbstractMetaFunction* method = vector->findFunction(QLatin1String("method")); + QVERIFY(method); + QCOMPARE(method->signature(), QLatin1String("method(const Vector & vector)")); + + const AbstractMetaFunction* otherMethod = vector->findFunction(QLatin1String("otherMethod")); + QVERIFY(otherMethod); + QCOMPARE(otherMethod->signature(), QLatin1String("otherMethod()")); + QVERIFY(otherMethod->type()); + QCOMPARE(otherMethod->type()->cppSignature(), QLatin1String("Vector")); +} + +QTEST_APPLESS_MAIN(TestTemplates) diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.h b/sources/shiboken2/ApiExtractor/tests/testtemplates.h new file mode 100644 index 000000000..7b0d0f3b3 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTTEMPLATES_H +#define TESTTEMPLATES_H + +#include + +class TestTemplates : public QObject +{ + Q_OBJECT +private slots: + void testTemplateOnContainers(); + void testTemplateWithNamespace(); + void testTemplateValueAsArgument(); + void testTemplatePointerAsArgument(); + void testTemplateReferenceAsArgument(); + void testTemplateParameterFixup(); + void testInheritanceFromContainterTemplate(); + void testTemplateInheritanceMixedWithForwardDeclaration(); + void testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration(); + void testTypedefOfInstantiationOfTemplateClass(); + void testContainerTypeIncompleteArgument(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testtoposort.cpp b/sources/shiboken2/ApiExtractor/tests/testtoposort.cpp new file mode 100644 index 000000000..30d368a8a --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testtoposort.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testtoposort.h" +#include +#include "graph.h" +#include + +void TestTopoSort::testTopoSort() +{ + QLinkedList result; + { + Graph g(3); + g.addEdge(1, 2); + g.addEdge(0, 1); + result = g.topologicalSort(); + QCOMPARE(result.size(), 3); + QLinkedList::iterator it = result.begin(); + QCOMPARE(*it, 0); + QCOMPARE(*(++it), 1); + QCOMPARE(*(++it), 2); + } + { + Graph g(2); + result = g.topologicalSort(); + QCOMPARE(result.size(), 2); + QLinkedList::iterator it = result.begin(); + QCOMPARE(*it, 1); + QCOMPARE(*(++it), 0); + } +} + +void TestTopoSort::testCiclicGraph() +{ + Graph g(3); + g.addEdge(0, 1); + g.addEdge(1, 2); + g.addEdge(2, 0); + QLinkedList result = g.topologicalSort(); + QVERIFY(result.isEmpty()); +} + +QTEST_APPLESS_MAIN(TestTopoSort) + diff --git a/sources/shiboken2/ApiExtractor/tests/testtoposort.h b/sources/shiboken2/ApiExtractor/tests/testtoposort.h new file mode 100644 index 000000000..ae8a2bab8 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testtoposort.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTTOPOSORT_H +#define TESTTOPOSORT_H + +#include + +class TestTopoSort : public QObject +{ +Q_OBJECT +private slots: + void testTopoSort(); + void testCiclicGraph(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp b/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp new file mode 100644 index 000000000..804683140 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testtyperevision.h" +#include +#include "testutil.h" +#include +#include + +void TestTypeRevision::testRevisionAttr() +{ + const char* cppCode = "class Rev_0 {};" + "class Rev_1 {};" + "class Rev_2 { public: enum Rev_3 { X }; enum Rev_5 { Y }; };"; + const char* xmlCode = "" + "" + "" + "" + " " + " " + "" + ""; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *rev0 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_0")); + QCOMPARE(getTypeRevision(rev0->typeEntry()), 0); + + const AbstractMetaClass *rev1 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_1")); + QCOMPARE(getTypeRevision(rev1->typeEntry()), 1); + + AbstractMetaClass *rev2 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_2")); + QCOMPARE(getTypeRevision(rev2->typeEntry()), 2); + + AbstractMetaEnum* rev3 = rev2->findEnum(QLatin1String("Rev_3")); + QCOMPARE(getTypeRevision(rev3->typeEntry()), 3); + FlagsTypeEntry* rev4 = rev3->typeEntry()->flags(); + QCOMPARE(getTypeRevision(rev4), 4); + AbstractMetaEnum* rev5 = rev2->findEnum(QLatin1String("Rev_5")); + QCOMPARE(getTypeRevision(rev5->typeEntry()), 5); + QCOMPARE(getTypeRevision(rev5->typeEntry()->flags()), 5); +} + +QTEST_APPLESS_MAIN(TestTypeRevision) + + diff --git a/sources/shiboken2/ApiExtractor/tests/testtyperevision.h b/sources/shiboken2/ApiExtractor/tests/testtyperevision.h new file mode 100644 index 000000000..dcb2d8794 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testtyperevision.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTTYPEREVISION_H +#define TESTTYPEREVISION_H + +#include + +class TestTypeRevision : public QObject +{ + Q_OBJECT + +private slots: + void testRevisionAttr(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testutil.h b/sources/shiboken2/ApiExtractor/tests/testutil.h new file mode 100644 index 000000000..200fdb104 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testutil.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTUTIL_H +#define TESTUTIL_H +#include +#include +#include +#include +#include "abstractmetabuilder.h" +#include "reporthandler.h" +#include "typedatabase.h" + +namespace TestUtil +{ + static AbstractMetaBuilder *parse(const char *cppCode, const char *xmlCode, + bool silent = true, + const char *apiVersion = Q_NULLPTR, + const QStringList &dropTypeEntries = QStringList()) + { + ReportHandler::setSilent(silent); + TypeDatabase* td = TypeDatabase::instance(true); + if (apiVersion && !td->setApiVersion(QLatin1String("*"), QLatin1String(apiVersion))) + return Q_NULLPTR; + td->setDropTypeEntries(dropTypeEntries); + QBuffer buffer; + // parse typesystem + buffer.setData(xmlCode); + if (!buffer.open(QIODevice::ReadOnly)) + return Q_NULLPTR; + td->parseFile(&buffer); + buffer.close(); + // parse C++ code + QTemporaryFile tempSource(QDir::tempPath() + QLatin1String("/st_XXXXXX_main.cpp")); + if (!tempSource.open()) { + qWarning().noquote().nospace() << "Creation of temporary file failed: " + << tempSource.errorString(); + return nullptr; + } + QByteArrayList arguments; + arguments.append(QFile::encodeName(tempSource.fileName())); + tempSource.write(cppCode, qint64(strlen(cppCode))); + tempSource.close(); + AbstractMetaBuilder *builder = new AbstractMetaBuilder; + if (!builder->build(arguments, 0)) { + delete builder; + return Q_NULLPTR; + } + return builder; + } +} // namespace TestUtil + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.cpp b/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.cpp new file mode 100644 index 000000000..627255d37 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testvaluetypedefaultctortag.h" +#include +#include "testutil.h" +#include +#include + +void TestValueTypeDefaultCtorTag::testValueTypeDefaultCtorTagArgument() +{ + const char* cppCode ="\n\ + struct A {\n\ + A(int,int);\n\ + };\n\ + struct B {};\n\ + "; + const char* xmlCode = "\n\ + \n\ + \n\ + \n\ + \n\ + "; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + QVERIFY(classA->typeEntry()->hasDefaultConstructor()); + QCOMPARE(classA->typeEntry()->defaultConstructor(), QLatin1String("A(0, 0)")); + + const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + QVERIFY(!classB->typeEntry()->hasDefaultConstructor()); +} + +QTEST_APPLESS_MAIN(TestValueTypeDefaultCtorTag) diff --git a/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.h b/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.h new file mode 100644 index 000000000..2d2efe79d --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTVALUETYPEDEFAULTCTORTAG_H +#define TESTVALUETYPEDEFAULTCTORTAG_H + +#include + +class TestValueTypeDefaultCtorTag : public QObject +{ + Q_OBJECT + private slots: + void testValueTypeDefaultCtorTagArgument(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/testvoidarg.cpp b/sources/shiboken2/ApiExtractor/tests/testvoidarg.cpp new file mode 100644 index 000000000..5f0b47389 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testvoidarg.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "testvoidarg.h" +#include +#include "testutil.h" +#include +#include + +void TestVoidArg::testVoidParsedFunction() +{ + const char cppCode[] = "struct A { void a(void); };"; + const char xmlCode[] = "\n\ + \n\ + \n\ + "; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("a")); + QCOMPARE(addedFunc->arguments().count(), 0); +} + +void TestVoidArg::testVoidAddedFunction() +{ + const char cppCode[] = "struct A { };"; + const char xmlCode[] = "\n\ + \n\ + \n\ + \n\ + \n\ + "; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("a")); + QCOMPARE(addedFunc->arguments().count(), 0); + +} + +void TestVoidArg::testVoidPointerParsedFunction() +{ + const char cppCode[] = "struct A { void a(void*); };"; + const char xmlCode[] = "\n\ + \n\ + \n\ + "; + QScopedPointer builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QVERIFY(classA); + const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("a")); + QCOMPARE(addedFunc->arguments().count(), 1); + +} + +QTEST_APPLESS_MAIN(TestVoidArg) diff --git a/sources/shiboken2/ApiExtractor/tests/testvoidarg.h b/sources/shiboken2/ApiExtractor/tests/testvoidarg.h new file mode 100644 index 000000000..40d96a4ff --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testvoidarg.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TESTVOIDARG_H +#define TESTVOIDARG_H +#include + +class TestVoidArg : public QObject +{ + Q_OBJECT +private slots: + void testVoidParsedFunction(); + void testVoidPointerParsedFunction(); + void testVoidAddedFunction(); +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/tests/utf8code.txt b/sources/shiboken2/ApiExtractor/tests/utf8code.txt new file mode 100644 index 000000000..6d5fa9dcf --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/utf8code.txt @@ -0,0 +1 @@ +áéíóú \ No newline at end of file diff --git a/sources/shiboken2/ApiExtractor/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp new file mode 100644 index 000000000..a1b28070b --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp @@ -0,0 +1,745 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "typedatabase.h" +#include "typesystem.h" +#include "typesystem_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "reporthandler.h" +// #include +#include + +// package -> api-version + +static QString wildcardToRegExp(QString w) +{ + w.replace(QLatin1Char('?'), QLatin1Char('.')); + w.replace(QLatin1Char('*'), QStringLiteral(".*")); + return w; +} + +typedef QPair ApiVersion; +typedef QVector ApiVersions; + +Q_GLOBAL_STATIC(ApiVersions, apiVersions) + +TypeDatabase::TypeDatabase() : m_suppressWarnings(true) +{ + addType(new VoidTypeEntry()); + addType(new VarargsTypeEntry()); +} + +TypeDatabase::~TypeDatabase() +{ +} + +TypeDatabase* TypeDatabase::instance(bool newInstance) +{ + static TypeDatabase* db = 0; + if (!db || newInstance) { + if (db) + delete db; + db = new TypeDatabase; + } + return db; +} + +// A list of regex/replacements to fix int types like "ushort" to "unsigned short" +// unless present in TypeDatabase +struct IntTypeNormalizationEntry +{ + QRegularExpression regex; + QString replacement; +}; + +typedef QVector IntTypeNormalizationEntries; + +static const IntTypeNormalizationEntries &intTypeNormalizationEntries() +{ + static IntTypeNormalizationEntries result; + static bool firstTime = true; + if (firstTime) { + firstTime = false; + static const char *intTypes[] = {"char", "short", "int", "long"}; + const size_t size = sizeof(intTypes) / sizeof(intTypes[0]); + for (size_t i = 0; i < size; ++i) { + const QString intType = QLatin1String(intTypes[i]); + if (!TypeDatabase::instance()->findType(QLatin1Char('u') + intType)) { + IntTypeNormalizationEntry entry; + entry.replacement = QStringLiteral("unsigned ") + intType; + entry.regex.setPattern(QStringLiteral("\\bu") + intType + QStringLiteral("\\b")); + Q_ASSERT(entry.regex.isValid()); + result.append(entry); + } + } + } + return result; +} + +QString TypeDatabase::normalizedSignature(const QString &signature) +{ + QString normalized = QLatin1String(QMetaObject::normalizedSignature(signature.toUtf8().constData())); + + if (instance() && signature.contains(QLatin1String("unsigned"))) { + const IntTypeNormalizationEntries &entries = intTypeNormalizationEntries(); + for (int i = 0, size = entries.size(); i < size; ++i) + normalized.replace(entries.at(i).regex, entries.at(i).replacement); + } + + return normalized; +} + +QStringList TypeDatabase::requiredTargetImports() const +{ + return m_requiredTargetImports; +} + +void TypeDatabase::addRequiredTargetImport(const QString& moduleName) +{ + if (!m_requiredTargetImports.contains(moduleName)) + m_requiredTargetImports << moduleName; +} + +void TypeDatabase::addTypesystemPath(const QString& typesystem_paths) +{ + #if defined(Q_OS_WIN32) + const char path_splitter = ';'; + #else + const char path_splitter = ':'; + #endif + m_typesystemPaths += typesystem_paths.split(QLatin1Char(path_splitter)); +} + +IncludeList TypeDatabase::extraIncludes(const QString& className) const +{ + ComplexTypeEntry* typeEntry = findComplexType(className); + if (typeEntry) + return typeEntry->extraIncludes(); + else + return IncludeList(); +} + +ContainerTypeEntry* TypeDatabase::findContainerType(const QString &name) const +{ + QString template_name = name; + + int pos = name.indexOf(QLatin1Char('<')); + if (pos > 0) + template_name = name.left(pos); + + TypeEntry* type_entry = findType(template_name); + if (type_entry && type_entry->isContainer()) + return static_cast(type_entry); + return 0; +} + +FunctionTypeEntry* TypeDatabase::findFunctionType(const QString& name) const +{ + TypeEntry* entry = findType(name); + if (entry && entry->type() == TypeEntry::FunctionType) + return static_cast(entry); + return 0; +} + +TypeEntry* TypeDatabase::findType(const QString& name) const +{ + const TypeEntryList &entries = findTypes(name); + for (TypeEntry *entry : entries) { + if (entry && + (!entry->isPrimitive() || static_cast(entry)->preferredTargetLangType())) { + return entry; + } + } + return 0; +} + +TypeEntryList TypeDatabase::findTypes(const QString &name) const +{ + return m_entries.value(name); +} + +SingleTypeEntryHash TypeDatabase::entries() 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())); + + return returned; +} + +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(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(typeEntry)); + } + } + return returned; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const TypeRejection &r) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "TypeRejection(type=" << r.matchType << ", class=" + << r.className.pattern() << ", pattern=" << r.pattern.pattern() << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +void TypeDatabase::addRejection(const TypeRejection &r) +{ + m_rejections << r; +} + +static inline QString msgRejectReason(const TypeRejection &r, const QString &needle = QString()) +{ + QString result; + QTextStream str(&result); + switch (r.matchType) { + case TypeRejection::ExcludeClass: + str << " matches class exclusion \"" << r.className.pattern() << '"'; + break; + case TypeRejection::Function: + case TypeRejection::Field: + case TypeRejection::Enum: + str << " matches class \"" << r.className.pattern() << "\" and \"" << r.pattern.pattern() << '"'; + break; + case TypeRejection::ArgumentType: + case TypeRejection::ReturnType: + str << " matches class \"" << r.className.pattern() << "\" and \"" << needle + << "\" matches \"" << r.pattern.pattern() << '"'; + break; + } + return result; +} + +// Match class name only +bool TypeDatabase::isClassRejected(const QString& className, QString *reason) const +{ + for (const TypeRejection& r : m_rejections) { + if (r.matchType == TypeRejection::ExcludeClass && r.className.match(className).hasMatch()) { + if (reason) + *reason = msgRejectReason(r); + return true; + } + } + return false; +} + +// Match class name and function/enum/field +static bool findRejection(const QVector &rejections, + TypeRejection::MatchType matchType, + const QString& className, const QString& name, + QString *reason = nullptr) +{ + Q_ASSERT(matchType != TypeRejection::ExcludeClass); + for (const TypeRejection& r : rejections) { + if (r.matchType == matchType && r.pattern.match(name).hasMatch() + && r.className.match(className).hasMatch()) { + if (reason) + *reason = msgRejectReason(r, name); + return true; + } + } + return false; +} + +bool TypeDatabase::isEnumRejected(const QString& className, const QString& enumName, QString *reason) const +{ + return findRejection(m_rejections, TypeRejection::Enum, className, enumName, reason); +} + +void TypeDatabase::addType(TypeEntry *e) +{ + m_entries[e->qualifiedCppName()].append(e); +} + +bool TypeDatabase::isFunctionRejected(const QString& className, const QString& functionName, + QString *reason) const +{ + return findRejection(m_rejections, TypeRejection::Function, className, functionName, reason); +} + +bool TypeDatabase::isFieldRejected(const QString& className, const QString& fieldName, + QString *reason) const +{ + return findRejection(m_rejections, TypeRejection::Field, className, fieldName, reason); +} + +bool TypeDatabase::isArgumentTypeRejected(const QString& className, const QString& typeName, + QString *reason) const +{ + return findRejection(m_rejections, TypeRejection::ArgumentType, className, typeName, reason); +} + +bool TypeDatabase::isReturnTypeRejected(const QString& className, const QString& typeName, + QString *reason) const +{ + return findRejection(m_rejections, TypeRejection::ReturnType, className, typeName, reason); +} + +FlagsTypeEntry* TypeDatabase::findFlagsType(const QString &name) const +{ + TypeEntry *fte = findType(name); + if (!fte) { + 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) { + if (it.key().endsWith(name)) { + fte = it.value(); + break; + } + } + } + } + return static_cast(fte); +} + +void TypeDatabase::addFlagsType(FlagsTypeEntry *fte) +{ + m_flagsEntries[fte->originalName()] = fte; +} + +void TypeDatabase::addTemplate(TemplateEntry *t) +{ + m_templates[t->name()] = t; +} + +void TypeDatabase::addGlobalUserFunctions(const AddedFunctionList &functions) +{ + m_globalUserFunctions << functions; +} + +AddedFunctionList TypeDatabase::findGlobalUserFunctions(const QString& name) const +{ + AddedFunctionList addedFunctions; + for (const AddedFunction &func : m_globalUserFunctions) { + if (func.name() == name) + addedFunctions.append(func); + } + return addedFunctions; +} + +void TypeDatabase::addGlobalUserFunctionModifications(const FunctionModificationList &functionModifications) +{ + m_functionMods << functionModifications; +} + +QString TypeDatabase::globalNamespaceClassName(const TypeEntry * /*entry*/) +{ + return QLatin1String("Global"); +} + +FunctionModificationList TypeDatabase::functionModifications(const QString& signature) const +{ + FunctionModificationList lst; + for (int i = 0; i < m_functionMods.count(); ++i) { + const FunctionModification& mod = m_functionMods.at(i); + if (mod.signature == signature) + lst << mod; + } + + return lst; +} + +void TypeDatabase::addSuppressedWarning(const QString &s) +{ + m_suppressedWarnings.append(s); +} + +bool TypeDatabase::isSuppressedWarning(const QString& s) const +{ + if (!m_suppressWarnings) + return false; + + for (QString warning : m_suppressedWarnings) { + warning.replace(QLatin1String("\\*"), QLatin1String("&place_holder_for_asterisk;")); + + QStringList segs = warning.split(QLatin1Char('*'), QString::SkipEmptyParts); + if (!segs.size()) + continue; + + int i = 0; + int pos = s.indexOf(QString(segs.at(i++)).replace(QLatin1String("&place_holder_for_asterisk;"), QLatin1String("*"))); + //qDebug() << "s == " << s << ", warning == " << segs; + while (pos != -1) { + if (i == segs.size()) + return true; + pos = s.indexOf(QString(segs.at(i++)).replace(QLatin1String("&place_holder_for_asterisk;"), QLatin1String("*")), pos); + } + } + + return false; +} + +QString TypeDatabase::modifiedTypesystemFilepath(const QString& tsFile) const +{ + const QFileInfo tsFi(tsFile); + if (tsFi.isAbsolute()) // No point in further lookups + return tsFi.absoluteFilePath(); + if (tsFi.isFile()) // Make path absolute + return tsFi.absoluteFilePath(); + const QString fileName = tsFi.fileName(); + for (const QString &path : m_typesystemPaths) { + const QFileInfo fi(path + QLatin1Char('/') + fileName); + if (fi.isFile()) + return fi.absoluteFilePath(); + } + return tsFile; +} + +bool TypeDatabase::parseFile(const QString &filename, bool generate) +{ + QString filepath = modifiedTypesystemFilepath(filename); + if (m_parsedTypesystemFiles.contains(filepath)) + return m_parsedTypesystemFiles[filepath]; + + m_parsedTypesystemFiles[filepath] = true; // Prevent recursion when including self. + + QFile file(filepath); + if (!file.exists()) { + m_parsedTypesystemFiles[filepath] = false; + qCWarning(lcShiboken).noquote().nospace() + << "Can't find " << filename << ", typesystem paths: " << m_typesystemPaths.join(QLatin1String(", ")); + return false; + } + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + m_parsedTypesystemFiles[filepath] = false; + qCWarning(lcShiboken).noquote().nospace() + << "Can't open " << QDir::toNativeSeparators(filename) << ": " << file.errorString(); + return false; + } + + int count = m_entries.size(); + bool ok = parseFile(&file, generate); + m_parsedTypesystemFiles[filepath] = ok; + int newCount = m_entries.size(); + + if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { + qCDebug(lcShiboken) + << QStringLiteral("Parsed: '%1', %2 new entries").arg(filename).arg(newCount - count); + } + return ok; +} + +bool TypeDatabase::parseFile(QIODevice* device, bool generate) +{ + QXmlStreamReader reader(device); + Handler handler(this, generate); + return handler.parse(reader); +} + +PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString& name) const +{ + const TypeEntryList &entries = findTypes(name); + + for (TypeEntry *entry : entries) { + if (entry && entry->isPrimitive() && static_cast(entry)->preferredTargetLangType()) + return static_cast(entry); + } + + return 0; +} + +ComplexTypeEntry* TypeDatabase::findComplexType(const QString& name) const +{ + const TypeEntryList &entries = findTypes(name); + for (TypeEntry *entry : entries) { + if (entry && entry->isComplex()) + return static_cast(entry); + } + return 0; +} + +ObjectTypeEntry* TypeDatabase::findObjectType(const QString& name) const +{ + const TypeEntryList &entries = findTypes(name); + for (TypeEntry *entry : entries) { + if (entry && entry->isObject()) + return static_cast(entry); + } + return 0; +} + +NamespaceTypeEntry* TypeDatabase::findNamespaceType(const QString& name) const +{ + const TypeEntryList &entries = findTypes(name); + for (TypeEntry *entry : entries) { + if (entry && entry->isNamespace()) + return static_cast(entry); + } + return 0; +} + +bool TypeDatabase::shouldDropTypeEntry(const QString& fullTypeName) const +{ + return m_dropTypeEntries.contains(fullTypeName); +} + +void TypeDatabase::setDropTypeEntries(QStringList dropTypeEntries) +{ + m_dropTypeEntries = 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 > TypeRevisionMap; +Q_GLOBAL_STATIC(TypeRevisionMap, typeEntryFields); +static bool computeTypeIndexes = true; +static int maxTypeIndex; + +int getTypeRevision(const TypeEntry* typeEntry) +{ + 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(); +} + +static void _computeTypeIndexes() +{ + TypeDatabase* tdb = TypeDatabase::instance(); + typedef QMap GroupedTypeEntries; + GroupedTypeEntries groupedEntries; + + // 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; + } + } + + 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++; + } + } + computeTypeIndexes = false; +} + +int getTypeIndex(const TypeEntry* typeEntry) +{ + if (computeTypeIndexes) + _computeTypeIndexes(); + return typeEntryFields()->value(typeEntry).second; +} + +int getMaxTypeIndex() +{ + if (computeTypeIndexes) + _computeTypeIndexes(); + return maxTypeIndex; +} + +bool TypeDatabase::setApiVersion(const QString& packageWildcardPattern, const QString &version) +{ + const QString packagePattern = wildcardToRegExp(packageWildcardPattern.trimmed()); + const QVersionNumber versionNumber = QVersionNumber::fromString(version); + if (versionNumber.isNull()) + return false; + ApiVersions &versions = *apiVersions(); + for (int i = 0, size = versions.size(); i < size; ++i) { + if (versions.at(i).first.pattern() == packagePattern) { + versions[i].second = versionNumber; + return true; + } + } + const QRegularExpression packageRegex(packagePattern); + if (!packageRegex.isValid()) + return false; + versions.append(qMakePair(packageRegex, versionNumber)); + return true; +} + +bool TypeDatabase::checkApiVersion(const QString& package, const QString& version) const +{ + const QVersionNumber versionNumber = QVersionNumber::fromString(version); + if (versionNumber.isNull()) { + qCWarning(lcShiboken).noquote().nospace() + << "checkApiVersion: Invalid version \"" << version << "\" specified for package " + << package << '.'; + return false; + } + const ApiVersions &versions = *apiVersions(); + for (int i = 0, size = versions.size(); i < size; ++i) { + if (versions.at(i).first.match(package).hasMatch()) + return versions.at(i).second >= versionNumber; + } + return false; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const TypeEntry *te) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "TypeEntry("; + if (te) { + d << '"' << te->qualifiedCppName() << "\", 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 { + d << '0'; + } + d << ')'; + return d; +} + +QDebug operator<<(QDebug d, const TemplateEntry *te) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "TemplateEntry("; + if (te) { + d << '"' << te->name() << "\", version=" << te->version(); + } else { + d << '0'; + } + d << ')'; + return d; +} + +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"; + } + 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) { + if (it != begin) + d << ", "; + d << it.value(); + } + d << ")\n"; + } + 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) { + if (it != begin) + d << ", "; + d << it.value(); + } + d << ")\n"; + } + d <<"\nglobalUserFunctions=" << m_globalUserFunctions << ')'; +} + +QDebug operator<<(QDebug d, const TypeDatabase &db) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + db.formatDebug(d); + return d; +} +#endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken2/ApiExtractor/typedatabase.h b/sources/shiboken2/ApiExtractor/typedatabase.h new file mode 100644 index 000000000..86f933448 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typedatabase.h @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 TYPEDATABASE_H +#define TYPEDATABASE_H + +#include "apiextractormacros.h" +#include "include.h" +#include "typedatabase_typedefs.h" +#include "typesystem_enums.h" +#include "typesystem_typedefs.h" + +#include + +QT_FORWARD_DECLARE_CLASS(QIODevice) + +class ComplexTypeEntry; +class ContainerTypeEntry; +class FlagsTypeEntry; +class FunctionTypeEntry; +class NamespaceTypeEntry; +class ObjectTypeEntry; +class TemplateEntry; +class TypeEntry; + +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 TypeDatabase +{ + TypeDatabase(); + Q_DISABLE_COPY(TypeDatabase) +public: + ~TypeDatabase(); + + /** + * Return the type system instance. + * \param newInstance This parameter is useful just for unit testing, because singletons causes + * too many side effects on unit testing. + */ + static TypeDatabase* instance(bool newInstance = false); + + static QString normalizedSignature(const QString &signature); + + QStringList requiredTargetImports() const; + + void addRequiredTargetImport(const QString& moduleName); + + void addTypesystemPath(const QString& typesystem_paths); + + IncludeList extraIncludes(const QString& className) const; + + PrimitiveTypeEntry* findPrimitiveType(const QString& name) const; + ComplexTypeEntry* findComplexType(const QString& name) const; + ObjectTypeEntry* findObjectType(const QString& name) const; + NamespaceTypeEntry* findNamespaceType(const QString& name) const; + ContainerTypeEntry* findContainerType(const QString& name) const; + FunctionTypeEntry* findFunctionType(const QString& name) const; + + TypeEntry* findType(const QString& name) const; + + TypeEntryHash allEntries() const { return m_entries; } + + SingleTypeEntryHash entries() const; + + PrimitiveTypeEntryList primitiveTypes() const; + + ContainerTypeEntryList containerTypes() const; + + void addRejection(const TypeRejection &); + bool isClassRejected(const QString& className, QString *reason = nullptr) const; + bool isFunctionRejected(const QString& className, const QString& functionName, + QString *reason = nullptr) const; + bool isFieldRejected(const QString& className, const QString& fieldName, + QString *reason = nullptr) const; + bool isEnumRejected(const QString& className, const QString& enumName, + QString *reason = nullptr) const; + bool isArgumentTypeRejected(const QString& className, const QString& typeName, + QString *reason = nullptr) const; + bool isReturnTypeRejected(const QString& className, const QString& typeName, + QString *reason = nullptr) const; + + void addType(TypeEntry* e); + + FlagsTypeEntry* findFlagsType(const QString& name) const; + void addFlagsType(FlagsTypeEntry* fte); + + TemplateEntry *findTemplate(const QString& name) const { return m_templates[name]; } + + void addTemplate(TemplateEntry* t); + + AddedFunctionList globalUserFunctions() const { return m_globalUserFunctions; } + + void addGlobalUserFunctions(const AddedFunctionList &functions); + + AddedFunctionList findGlobalUserFunctions(const QString& name) const; + + void addGlobalUserFunctionModifications(const FunctionModificationList &functionModifications); + + FunctionModificationList functionModifications(const QString& signature) const; + + void setSuppressWarnings(bool on) { m_suppressWarnings = on; } + + void addSuppressedWarning(const QString &s); + + bool isSuppressedWarning(const QString& s) const; + + static QString globalNamespaceClassName(const TypeEntry *te); + + bool parseFile(const QString &filename, bool generate = true); + bool parseFile(QIODevice* device, bool generate = true); + + bool setApiVersion(const QString& package, const QString& version); + + bool checkApiVersion(const QString& package, const QString &version) const; + + bool hasDroppedTypeEntries() const { return !m_dropTypeEntries.isEmpty(); } + + bool shouldDropTypeEntry(const QString& fullTypeName) const; + + void setDropTypeEntries(QStringList dropTypeEntries); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const; +#endif +private: + TypeEntryList findTypes(const QString &name) const; + QString modifiedTypesystemFilepath(const QString &tsFile) const; + + bool m_suppressWarnings; + TypeEntryHash m_entries; + SingleTypeEntryHash m_flagsEntries; + TemplateEntryHash m_templates; + QStringList m_suppressedWarnings; + + AddedFunctionList m_globalUserFunctions; + FunctionModificationList m_functionMods; + + QStringList m_requiredTargetImports; + + QStringList m_typesystemPaths; + QHash m_parsedTypesystemFiles; + + QVector m_rejections; + + QStringList m_dropTypeEntries; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const TypeEntry *te); +QDebug operator<<(QDebug d, const TypeDatabase &db); +#endif +#endif // TYPEDATABASE_H diff --git a/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h b/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h new file mode 100644 index 000000000..95859a399 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 TYPEDATABASE_TYPEDEFS_H +#define TYPEDATABASE_TYPEDEFS_H + +#include +#include +#include + +class ContainerTypeEntry; +class PrimitiveTypeEntry; +class TemplateEntry; +class TypeEntry; + +typedef QVector TypeEntryList; +typedef QHash TypeEntryHash; +typedef QHash SingleTypeEntryHash; +typedef QHash TemplateEntryHash; + +typedef QVector ContainerTypeEntryList; +typedef QVector PrimitiveTypeEntryList; + +#endif // TYPEDATABASE_TYPEDEFS_H diff --git a/sources/shiboken2/ApiExtractor/typeparser.cpp b/sources/shiboken2/ApiExtractor/typeparser.cpp new file mode 100644 index 000000000..8165bfe44 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typeparser.cpp @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "typeparser.h" + +#include +#include +#include + +class Scanner +{ +public: + enum Token { + StarToken, + AmpersandToken, + LessThanToken, + ColonToken, + CommaToken, + OpenParenToken, + CloseParenToken, + SquareBegin, + SquareEnd, + GreaterThanToken, + + ConstToken, + Identifier, + NoToken, + InvalidToken + }; + + Scanner(const QString &s) + : m_pos(0), m_length(s.length()), m_chars(s.constData()) + { + } + + Token nextToken(QString *errorMessage = Q_NULLPTR); + QString identifier() const; + + QString msgParseError(const QString &why) const; + +private: + int m_pos; + int m_length; + int m_tokenStart; + const QChar *m_chars; +}; + +QString Scanner::identifier() const +{ + return QString(m_chars + m_tokenStart, m_pos - m_tokenStart); +} + +Scanner::Token Scanner::nextToken(QString *errorMessage) +{ + Token tok = NoToken; + + // remove whitespace + while (m_pos < m_length && m_chars[m_pos] == QLatin1Char(' ')) + ++m_pos; + + m_tokenStart = m_pos; + + while (m_pos < m_length) { + + const QChar &c = m_chars[m_pos]; + + if (tok == NoToken) { + switch (c.toLatin1()) { + case '*': tok = StarToken; break; + case '&': tok = AmpersandToken; break; + case '<': tok = LessThanToken; break; + case '>': tok = GreaterThanToken; break; + case ',': tok = CommaToken; break; + case '(': tok = OpenParenToken; break; + case ')': tok = CloseParenToken; break; + case '[': tok = SquareBegin; break; + case ']' : tok = SquareEnd; break; + case ':': + tok = ColonToken; + Q_ASSERT(m_pos + 1 < m_length); + ++m_pos; + break; + default: + if (c.isLetterOrNumber() || c == QLatin1Char('_')) { + tok = Identifier; + } else { + QString message; + QTextStream (&message) << ": Unrecognized character in lexer at " + << m_pos << " : '" << c << '\''; + message = msgParseError(message); + if (errorMessage) + *errorMessage = message; + else + qWarning().noquote().nospace() << message; + return InvalidToken; + } + break; + } + } + + if (tok <= GreaterThanToken) { + ++m_pos; + break; + } + + if (tok == Identifier) { + if (c.isLetterOrNumber() || c == QLatin1Char('_')) + ++m_pos; + else + break; + } + } + + 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; + } + + return tok; + +} + +QString Scanner::msgParseError(const QString &why) const +{ + return QStringLiteral("TypeParser: Unable to parse \"") + + QString(m_chars, m_length) + QStringLiteral("\": ") + why; +} + +static TypeParser::Info invalidInfo() +{ + TypeParser::Info result; + result.is_busted = true; + return result; +} + +TypeParser::Info TypeParser::parse(const QString &str, QString *errorMessage) +{ + Scanner scanner(str); + + Info info; + QStack stack; + stack.push(&info); + + bool colon_prefix = false; + bool in_array = false; + QString array; + + Scanner::Token tok = scanner.nextToken(errorMessage); + while (tok != Scanner::NoToken) { + if (tok == Scanner::InvalidToken) + return invalidInfo(); + +// switch (tok) { +// case Scanner::StarToken: printf(" - *\n"); break; +// case Scanner::AmpersandToken: printf(" - &\n"); break; +// case Scanner::LessThanToken: printf(" - <\n"); break; +// case Scanner::GreaterThanToken: printf(" - >\n"); break; +// case Scanner::ColonToken: printf(" - ::\n"); break; +// case Scanner::CommaToken: printf(" - ,\n"); break; +// case Scanner::ConstToken: printf(" - const\n"); break; +// case Scanner::SquareBegin: printf(" - [\n"); break; +// case Scanner::SquareEnd: printf(" - ]\n"); break; +// case Scanner::Identifier: printf(" - '%s'\n", qPrintable(scanner.identifier())); break; +// default: +// break; +// } + + switch (tok) { + + case Scanner::StarToken: + ++stack.top()->indirections; + break; + + case Scanner::AmpersandToken: + switch (stack.top()->referenceType) { + case NoReference: + stack.top()->referenceType = LValueReference; + break; + case LValueReference: + stack.top()->referenceType = RValueReference; + break; + case RValueReference: + const QString message = scanner.msgParseError(QStringLiteral("Too many '&' qualifiers")); + if (errorMessage) + *errorMessage = message; + else + qWarning().noquote().nospace() << message; + return invalidInfo(); + } + break; + case Scanner::LessThanToken: + stack.top()->template_instantiations << Info(); + stack.push(&stack.top()->template_instantiations.last()); + break; + + case Scanner::CommaToken: + stack.pop(); + stack.top()->template_instantiations << Info(); + stack.push(&stack.top()->template_instantiations.last()); + break; + + case Scanner::GreaterThanToken: + stack.pop(); + break; + + case Scanner::ColonToken: + colon_prefix = true; + break; + + case Scanner::ConstToken: + stack.top()->is_constant = true; + break; + + case Scanner::OpenParenToken: // function pointers not supported + case Scanner::CloseParenToken: { + const QString message = scanner.msgParseError(QStringLiteral("Function pointers are not supported")); + if (errorMessage) + *errorMessage = message; + else + qWarning().noquote().nospace() << message; + return invalidInfo(); + } + + case Scanner::Identifier: + if (in_array) { + array = scanner.identifier(); + } else if (colon_prefix || stack.top()->qualified_name.isEmpty()) { + stack.top()->qualified_name << scanner.identifier(); + colon_prefix = false; + } else { + stack.top()->qualified_name.last().append(QLatin1Char(' ') + scanner.identifier()); + } + break; + + case Scanner::SquareBegin: + in_array = true; + break; + + case Scanner::SquareEnd: + in_array = false; + stack.top()->arrays += array; + break; + + + default: + break; + } + + tok = scanner.nextToken(); + } + + return info; +} + +QString TypeParser::Info::instantiationName() const +{ + QString s(qualified_name.join(QLatin1String("::"))); + if (!template_instantiations.isEmpty()) { + QStringList insts; + for (const Info &info : template_instantiations) + insts << info.toString(); + s += QLatin1String("< ") + insts.join(QLatin1String(", ")) + QLatin1String(" >"); + } + + return s; +} + +QString TypeParser::Info::toString() const +{ + QString s; + + if (is_constant) + s += QLatin1String("const "); + s += instantiationName(); + for (int i = 0; i < arrays.size(); ++i) + s += QLatin1Char('[') + arrays.at(i) + QLatin1Char(']'); + s += QString(indirections, QLatin1Char('*')); + switch (referenceType) { + case NoReference: + break; + case LValueReference: + s += QLatin1Char('&'); + break; + case RValueReference: + s += QLatin1String("&&"); + break; + } + return s; +} diff --git a/sources/shiboken2/ApiExtractor/typeparser.h b/sources/shiboken2/ApiExtractor/typeparser.h new file mode 100644 index 000000000..f42c42a5e --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typeparser.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 TYPEPARSER_H +#define TYPEPARSER_H + +#include "parser/codemodel_enums.h" + +#include +#include +#include +#include + +class TypeParser +{ +public: + struct Info + { + Info() : referenceType(NoReference), is_constant(false), is_busted(false), indirections(0) { } + QStringList qualified_name; + QStringList arrays; + QVector template_instantiations; + ReferenceType referenceType; + uint is_constant : 1; + uint is_busted : 1; + uint indirections : 6; + + QString toString() const; + QString instantiationName() const; + }; + + static Info parse(const QString &str, QString *errorMessage = Q_NULLPTR); +}; + +#endif // TYPEPARSER_H diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp new file mode 100644 index 000000000..3ec82c56d --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -0,0 +1,2737 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "typesystem.h" +#include "typesystem_p.h" +#include "typedatabase.h" +#include "reporthandler.h" +#include +#include +#include +#include +#include + +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 colonColon() { return QStringLiteral("::"); } +static inline QString quoteAfterLineAttribute() { return QStringLiteral("quote-after-line"); } +static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote-before-line"); } +static inline QString nameAttribute() { return QStringLiteral("name"); } +static inline QString sinceAttribute() { return QStringLiteral("since"); } +static inline QString flagsAttribute() { return QStringLiteral("flags"); } +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 QVector customConversionsForReview; + +// Set a regular expression for rejection from text. By legacy, those are fixed +// strings, except for '*' meaning 'match all'. Enclosing in "^..$" +// indicates regular expression. +static bool setRejectionRegularExpression(const QString &patternIn, + QRegularExpression *re, + QString *errorMessage) +{ + QString pattern; + if (patternIn.startsWith(QLatin1Char('^')) && patternIn.endsWith(QLatin1Char('$'))) + pattern = patternIn; + else if (patternIn == QLatin1String("*")) + pattern = QStringLiteral("^.*$"); + else + pattern = QLatin1Char('^') + QRegularExpression::escape(patternIn) + QLatin1Char('$'); + re->setPattern(pattern); + if (!re->isValid()) { + *errorMessage = QLatin1String("Invalid pattern \"") + patternIn + + QLatin1String("\": ") + re->errorString(); + return false; + } + return true; +} + +static bool addRejection(TypeDatabase *database, const QHash &attributes, + QString *errorMessage) +{ + typedef QPair AttributeMatchTypePair; + + TypeRejection rejection; + + const QString className = attributes.value(classAttribute()); + if (!setRejectionRegularExpression(className, &rejection.className, errorMessage)) + return false; + + static const AttributeMatchTypePair attributeMatchTypeMapping[] = + {{functionNameAttribute(), TypeRejection::Function}, + {fieldNameAttribute(), TypeRejection::Field}, + {enumNameAttribute(), TypeRejection::Enum}, + {argumentTypeAttribute(), TypeRejection::ArgumentType}, + {returnTypeAttribute(), TypeRejection::ReturnType} + }; + + // 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; + } + } + + // 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; +} + + +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("inject-documentation"), StackElement::InjectDocumentation); + tagNames.insert(QLatin1String("modify-documentation"), StackElement::ModifyDocumentation); + tagNames.insert(QLatin1String("add-function"), StackElement::AddFunction); +} + +static QString msgReaderError(const QXmlStreamReader &reader, const QString &what) +{ + QString message; + QTextStream str(&message); + str << "Error: "; + if (const QFile *file = qobject_cast(reader.device())) + str << "file=" << QDir::toNativeSeparators(file->fileName()) << ", "; + str << "line=" << reader.lineNumber() << ", column=" << reader.columnNumber() + << ", message=" << what; + return message; +} + +static QString msgReaderError(const QXmlStreamReader &reader) +{ + return msgReaderError(reader, reader.errorString()); +} + +bool Handler::parse(QXmlStreamReader &reader) +{ + m_error.clear(); + while (!reader.atEnd()) { + switch (reader.readNext()) { + case QXmlStreamReader::NoToken: + case QXmlStreamReader::Invalid: + qCWarning(lcShiboken).noquote().nospace() << msgReaderError(reader); + return false; + case QXmlStreamReader::StartElement: + if (!startElement(reader.name(), reader.attributes())) { + m_error = msgReaderError(reader, m_error); + return false; + } + + break; + case QXmlStreamReader::EndElement: + if (!endElement(reader.name())) { + m_error = msgReaderError(reader, m_error); + return false; + } + break; + case QXmlStreamReader::Characters: + if (!characters(reader.text())) { + m_error = msgReaderError(reader, m_error); + return false; + } + break; + case QXmlStreamReader::StartDocument: + case QXmlStreamReader::EndDocument: + case QXmlStreamReader::Comment: + case QXmlStreamReader::DTD: + case QXmlStreamReader::EntityReference: + case QXmlStreamReader::ProcessingInstruction: + break; + } + } + return true; +} + +void Handler::fetchAttributeValues(const QString &name, const QXmlStreamAttributes &atts, + QHash *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) { + --m_ignoreDepth; + return true; + } + + if (m_currentDroppedEntry) { + if (m_currentDroppedEntryDepth == 1) { + m_current = m_currentDroppedEntry->parent; + delete m_currentDroppedEntry; + m_currentDroppedEntry = 0; + m_currentDroppedEntryDepth = 0; + } else { + ++m_currentDroppedEntryDepth; + } + return true; + } + + if (!localName.compare(QLatin1String("import-file"), Qt::CaseInsensitive)) + return true; + + if (!m_current) + return true; + + switch (m_current->type) { + case StackElement::Root: + if (m_generate == TypeEntry::GenerateAll) { + TypeDatabase::instance()->addGlobalUserFunctions(m_contextStack.top()->addedFunctions); + TypeDatabase::instance()->addGlobalUserFunctionModifications(m_contextStack.top()->functionMods); + for (CustomConversion *customConversion : qAsConst(customConversionsForReview)) { + const CustomConversion::TargetToNativeConversions &toNatives = customConversion->targetToNativeConversions(); + for (CustomConversion::TargetToNativeConversion *toNative : toNatives) + toNative->setSourceType(m_database->findType(toNative->sourceTypeName())); + } + } + break; + case StackElement::ObjectTypeEntry: + case StackElement::ValueTypeEntry: + case StackElement::InterfaceTypeEntry: + case StackElement::NamespaceTypeEntry: { + ComplexTypeEntry *centry = static_cast(m_current->entry); + centry->setAddedFunctions(m_contextStack.top()->addedFunctions); + centry->setFunctionModifications(m_contextStack.top()->functionMods); + centry->setFieldModifications(m_contextStack.top()->fieldMods); + centry->setCodeSnips(m_contextStack.top()->codeSnips); + centry->setDocModification(m_contextStack.top()->docModifications); + + if (centry->designatedInterface()) { + centry->designatedInterface()->setCodeSnips(m_contextStack.top()->codeSnips); + centry->designatedInterface()->setFunctionModifications(m_contextStack.top()->functionMods); + } + } + break; + case StackElement::NativeToTarget: + case StackElement::AddConversion: { + CustomConversion* customConversion = static_cast(m_current->entry)->customConversion(); + if (!customConversion) { + m_error = QLatin1String("CustomConversion object is missing."); + return false; + } + + QString code = m_contextStack.top()->codeSnips.takeLast().code(); + if (m_current->type == StackElement::AddConversion) { + if (customConversion->targetToNativeConversions().isEmpty()) { + m_error = QLatin1String("CustomConversion's target to native conversions missing."); + return false; + } + customConversion->targetToNativeConversions().last()->setConversion(code); + } else { + customConversion->setNativeToTargetConversion(code); + } + } + break; + case StackElement::CustomMetaConstructor: { + m_current->entry->setCustomConstructor(*m_current->value.customFunction); + delete m_current->value.customFunction; + } + break; + case StackElement::CustomMetaDestructor: { + m_current->entry->setCustomDestructor(*m_current->value.customFunction); + delete m_current->value.customFunction; + } + break; + case StackElement::EnumTypeEntry: + m_current->entry->setDocModification(m_contextStack.top()->docModifications); + m_contextStack.top()->docModifications = DocModificationList(); + m_currentEnum = 0; + break; + case StackElement::Template: + m_database->addTemplate(m_current->value.templateEntry); + break; + case StackElement::TemplateInstanceEnum: + switch (m_current->parent->type) { + case StackElement::InjectCode: + if (m_current->parent->parent->type == StackElement::Root) { + CodeSnipList snips = m_current->parent->entry->codeSnips(); + CodeSnip snip = snips.takeLast(); + snip.addTemplateInstance(m_current->value.templateInstance); + snips.append(snip); + m_current->parent->entry->setCodeSnips(snips); + break; + } + case StackElement::NativeToTarget: + case StackElement::AddConversion: + m_contextStack.top()->codeSnips.last().addTemplateInstance(m_current->value.templateInstance); + break; + case StackElement::Template: + m_current->parent->value.templateEntry->addTemplateInstance(m_current->value.templateInstance); + break; + case StackElement::CustomMetaConstructor: + case StackElement::CustomMetaDestructor: + m_current->parent->value.customFunction->addTemplateInstance(m_current->value.templateInstance); + break; + case StackElement::ConversionRule: + m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.last().addTemplateInstance(m_current->value.templateInstance); + break; + case StackElement::InjectCodeInFunction: + m_contextStack.top()->functionMods.last().snips.last().addTemplateInstance(m_current->value.templateInstance); + break; + default: + break; // nada + }; + break; + default: + 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; + } + + StackElement *child = m_current; + m_current = m_current->parent; + delete(child); + + return true; +} + +template // QString/QStringRef +bool Handler::characters(const String &ch) +{ + if (m_currentDroppedEntry || m_ignoreDepth) + return true; + + if (m_current->type == StackElement::Template) { + m_current->value.templateEntry->addCode(ch); + return true; + } + + if (m_current->type == StackElement::CustomMetaConstructor || m_current->type == StackElement::CustomMetaDestructor) { + m_current->value.customFunction->addCode(ch); + return true; + } + + if (m_current->type == StackElement::ConversionRule + && m_current->parent->type == StackElement::ModifyArgument) { + m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.last().addCode(ch); + return true; + } + + if (m_current->type == StackElement::NativeToTarget || m_current->type == StackElement::AddConversion) { + m_contextStack.top()->codeSnips.last().addCode(ch); + return true; + } + + if (m_current->parent) { + if ((m_current->type & StackElement::CodeSnipMask)) { + CodeSnipList snips; + switch (m_current->parent->type) { + case StackElement::Root: + snips = m_current->parent->entry->codeSnips(); + snips.last().addCode(ch); + m_current->parent->entry->setCodeSnips(snips); + break; + case StackElement::ModifyFunction: + case StackElement::AddFunction: + m_contextStack.top()->functionMods.last().snips.last().addCode(ch); + m_contextStack.top()->functionMods.last().modifiers |= FunctionModification::CodeInjection; + break; + case StackElement::NamespaceTypeEntry: + case StackElement::ObjectTypeEntry: + case StackElement::ValueTypeEntry: + case StackElement::InterfaceTypeEntry: + m_contextStack.top()->codeSnips.last().addCode(ch); + break; + default: + Q_ASSERT(false); + }; + return true; + } + } + + if (m_current->type & StackElement::DocumentationMask) + m_contextStack.top()->docModifications.last().setCode(ch); + + return true; +} + +bool Handler::importFileElement(const QXmlStreamAttributes &atts) +{ + const QString fileName = atts.value(nameAttribute()).toString(); + if (fileName.isEmpty()) { + m_error = QLatin1String("Required attribute 'name' missing for include-file tag."); + return false; + } + + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + file.setFileName(QLatin1String(":/trolltech/generator/") + fileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + m_error = QString::fromLatin1("Could not open file: '%1'").arg(QDir::toNativeSeparators(fileName)); + return false; + } + } + + const QStringRef quoteFrom = atts.value(quoteAfterLineAttribute()); + bool foundFromOk = quoteFrom.isEmpty(); + bool from = quoteFrom.isEmpty(); + + const QStringRef quoteTo = atts.value(quoteBeforeLineAttribute()); + bool foundToOk = quoteTo.isEmpty(); + bool to = true; + + QTextStream in(&file); + while (!in.atEnd()) { + QString line = in.readLine(); + if (from && to && line.contains(quoteTo)) { + to = false; + foundToOk = true; + break; + } + if (from && to) + characters(line + QLatin1Char('\n')); + if (!from && line.contains(quoteFrom)) { + from = true; + foundFromOk = true; + } + } + if (!foundFromOk || !foundToOk) { + QString fromError = QStringLiteral("Could not find quote-after-line='%1' in file '%2'.") + .arg(quoteFrom.toString(), fileName); + QString toError = QStringLiteral("Could not find quote-before-line='%1' in file '%2'.") + .arg(quoteTo.toString(), fileName); + + if (!foundToOk) + m_error = toError; + if (!foundFromOk) + m_error = fromError; + if (!foundFromOk && !foundToOk) + m_error = fromError + QLatin1Char(' ') + toError; + return false; + } + + return true; +} + +bool Handler::convertBoolean(const QString &_value, const QString &attributeName, bool defaultValue) +{ + QString value = _value.toLower(); + if (value == QLatin1String("true") || value == QLatin1String("yes")) + return true; + else if (value == QLatin1String("false") || value == QLatin1String("no")) + return false; + else { + QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.") + .arg(value, attributeName, + defaultValue ? QLatin1String("yes") : QLatin1String("no")); + + qCWarning(lcShiboken).noquote().nospace() << warn; + return defaultValue; + } +} + +static bool convertRemovalAttribute(const QString& removalAttribute, 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; + } + } + return true; +} + +static void getNamePrefixRecursive(StackElement* element, QStringList& names) +{ + if (!element->parent || !element->parent->entry) + return; + getNamePrefixRecursive(element->parent, names); + names << element->parent->entry->name(); +} + +static QString getNamePrefix(StackElement* element) +{ + QStringList names; + getNamePrefixRecursive(element, names); + return names.join(QLatin1Char('.')); +} + +// Returns empty string if there's no error. +static QString checkSignatureError(const QString& signature, const QString& tag) +{ + QString funcName = signature.left(signature.indexOf(QLatin1Char('('))).trimmed(); + static const QRegularExpression whiteSpace(QStringLiteral("\\s")); + Q_ASSERT(whiteSpace.isValid()); + if (!funcName.startsWith(QLatin1String("operator ")) && funcName.contains(whiteSpace)) { + return QString::fromLatin1("Error in <%1> tag signature attribute '%2'.\n" + "White spaces aren't allowed in function names, " + "and return types should not be part of the signature.") + .arg(tag, signature); + } + return QString(); +} + +void Handler::addFlags(const QString &name, QString flagName, + const QHash &attributes, double since) +{ + FlagsTypeEntry *ftype = new FlagsTypeEntry(QLatin1String("QFlags<") + name + QLatin1Char('>'), since); + ftype->setOriginator(m_currentEnum); + // 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); + QString n = ftype->originalName(); + + QStringList lst = n.split(colonColon()); + if (QStringList(lst.mid(0, lst.size() - 1)).join(colonColon()) != m_currentEnum->targetLangQualifier()) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("enum %1 and flags %2 differ in qualifiers") + // avoid constFirst to stay Qt 5.5 compatible + .arg(m_currentEnum->targetLangQualifier(), lst.first()); + } + + ftype->setFlagsName(lst.last()); + m_currentEnum->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()); +} + +bool Handler::handleSmartPointerEntry(StackElement *element, + QHash &attributes, + const QString &name, + double 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; + } + if (smartPointerType != QLatin1String("shared")) { + m_error = QLatin1String("Currently only the 'shared' type is supported."); + return false; + } + + 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; + } + + 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; + } + + QString errorString = checkSignatureError(signature, + QLatin1String("smart-pointer-type")); + if (!errorString.isEmpty()) { + m_error = errorString; + return false; + } + + SmartPointerTypeEntry *type = new SmartPointerTypeEntry(name, + getter, + smartPointerType, + refCountMethodName, + since); + type->setTargetLangPackage(m_defaultPackage); + type->setCodeGeneration(m_generate); + element->entry = type; + return true; +} + +bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts) +{ + if (m_ignoreDepth) { + ++m_ignoreDepth; + return true; + } + + if (!m_defaultPackage.isEmpty() && atts.hasAttribute(sinceAttribute())) { + TypeDatabase* td = TypeDatabase::instance(); + if (!td->checkApiVersion(m_defaultPackage, atts.value(sinceAttribute()).toString())) { + ++m_ignoreDepth; + return true; + } + } + + const QString tagName = n.toString().toLower(); + if (tagName == QLatin1String("import-file")) + return importFileElement(atts); + + const QHash::const_iterator tit = tagNames.constFind(tagName); + if (tit == tagNames.constEnd()) { + m_error = QStringLiteral("Unknown tag name: '%1'").arg(tagName); + return false; + } + + if (m_currentDroppedEntry) { + ++m_currentDroppedEntryDepth; + return true; + } + + StackElement* element = new StackElement(m_current); + element->type = tit.value(); + + 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) { + m_contextStack.push(new StackElementContext()); + } + + if (element->type & StackElement::TypeEntryMask) { + QHash attributes; + attributes.insert(nameAttribute(), QString()); + attributes.insert(QLatin1String("revision"), QLatin1String("0")); + attributes.insert(sinceAttribute(), QLatin1String("0")); + + 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"), QLatin1String("yes")); + attributes.insert(QLatin1String("preferred-target-lang-type"), QLatin1String("yes")); + 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"), QLatin1String("no")); + attributes.insert(QLatin1String("extensible"), QLatin1String("no")); + attributes.insert(QLatin1String("identified-by-value"), QString()); + break; + case StackElement::ValueTypeEntry: + attributes.insert(QLatin1String("default-constructor"), QString()); + // fall throooough + case StackElement::ObjectTypeEntry: + attributes.insert(QLatin1String("force-abstract"), QLatin1String("no")); + attributes.insert(QLatin1String("deprecated"), QLatin1String("no")); + attributes.insert(QLatin1String("hash-function"), QString()); + attributes.insert(QLatin1String("stream"), QLatin1String("no")); + // fall throooough + case StackElement::InterfaceTypeEntry: + attributes[QLatin1String("default-superclass")] = m_defaultSuperclass; + attributes.insert(QLatin1String("polymorphic-id-expression"), QString()); + attributes.insert(QLatin1String("delete-in-main-thread"), QLatin1String("no")); + attributes.insert(QLatin1String("held-type"), QString()); + attributes.insert(QLatin1String("copyable"), QString()); + // fall through + 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"), QLatin1String("no")); + attributes.insert(QLatin1String("generate"), QLatin1String("yes")); + attributes.insert(QLatin1String("target-type"), QString()); + attributes.insert(QLatin1String("generic-class"), QLatin1String("no")); + 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()]; + double since = attributes[sinceAttribute()].toDouble(); + + if (m_database->hasDroppedTypeEntries()) { + QString identifier = getNamePrefix(element) + QLatin1Char('.'); + identifier += (element->type == StackElement::FunctionTypeEntry ? attributes[QLatin1String("signature")] : name); + if (m_database->shouldDropTypeEntry(identifier)) { + m_currentDroppedEntry = element; + m_currentDroppedEntryDepth = 1; + if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { + qCDebug(lcShiboken) + << QStringLiteral("Type system entry '%1' was intentionally dropped from generation.").arg(identifier); + } + return true; + } + } + + // 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; + 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(since); + mod.signature = signature; + 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, + // or it's not possible to cover all primitive target language + // types (which we need to do in order to support fake meta objects) + if (element->type != StackElement::PrimitiveTypeEntry + && element->type != StackElement::FunctionTypeEntry) { + TypeEntry *tmp = m_database->findType(name); + if (tmp) + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("Duplicate type entry: '%1'").arg(name); + } + + if (element->type == StackElement::EnumTypeEntry) { + if (name.isEmpty()) { + name = attributes[QLatin1String("identified-by-value")]; + } else if (!attributes[QLatin1String("identified-by-value")].isEmpty()) { + m_error = QLatin1String("can't specify both 'name' and 'identified-by-value' attributes"); + return false; + } + } + + // Fix type entry name using nesting information. + if (element->type & StackElement::TypeEntryMask + && element->parent && element->parent->type != StackElement::Root) { + name = element->parent->entry->name() + colonColon() + name; + } + + + if (name.isEmpty()) { + m_error = QLatin1String("no 'name' attribute specified"); + return false; + } + + switch (element->type) { + 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"); + return false; + } else if (containerType == ContainerTypeEntry::NoContainer) { + m_error = QLatin1String("there is no container of type ") + typeName; + return false; + } + + 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.last(), since); + m_currentEnum->setAnonymous(!attributes[QLatin1String("identified-by-value")].isEmpty()); + 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); + } + } + 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; + } + // fall through + 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; + } + + // fall through + case StackElement::NamespaceTypeEntry: + if (!element->entry) + element->entry = new NamespaceTypeEntry(name, since); + + // fall through + case StackElement::ObjectTypeEntry: + if (!element->entry) + element->entry = new ObjectTypeEntry(name, since); + + element->entry->setStream(attributes[QLatin1String("stream")] == QLatin1String("yes")); + + ComplexTypeEntry *ctype = static_cast(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); + + // The expense policy + QString limit = attributes[QLatin1String("expense-limit")]; + if (!limit.isEmpty() && limit != QLatin1String("none")) { + ExpensePolicy ep; + ep.limit = limit.toInt(); + ep.cost = attributes[QLatin1String("expense-cost")]; + ctype->setExpensePolicy(ep); + } + + + 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(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(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; + } + } else { + element->entry = new FunctionTypeEntry(name, signature, since); + element->entry->setCodeGeneration(m_generate); + } + } + break; + default: + Q_ASSERT(false); + }; + + if (element->entry) { + m_database->addType(element->entry); + setTypeRevision(element->entry, attributes[QLatin1String("revision")].toInt()); + } 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 attributes; + attributes.insert(QLatin1String("mode"), QLatin1String("replace")); + attributes.insert(QLatin1String("format"), QLatin1String("native")); + attributes.insert(sinceAttribute(), QLatin1String("0")); + + fetchAttributeValues(tagName, atts, &attributes); + double since = attributes[sinceAttribute()].toDouble(); + + 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 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, since); + mod.format = 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"); + return false; + } + } else if (element->type == StackElement::ModifyDocumentation) { + // check the XML tag attributes + QHash attributes; + attributes.insert(QLatin1String("xpath"), QString()); + attributes.insert(sinceAttribute(), QLatin1String("0")); + fetchAttributeValues(tagName, atts, &attributes); + double since = attributes[sinceAttribute()].toDouble(); + + 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[QLatin1String("xpath")], signature, since); + } else { + m_error = QLatin1String("modify-documentation must be inside modify-function, " + "modify-field or other tags that creates a type"); + return false; + } + } else if (element->type != StackElement::None) { + bool topLevel = element->type == StackElement::Root + || element->type == StackElement::SuppressedWarning + || element->type == StackElement::Rejection + || element->type == StackElement::LoadTypesystem + || element->type == StackElement::InjectCode + || element->type == StackElement::ExtraIncludes + || element->type == StackElement::ConversionRule + || element->type == StackElement::AddFunction + || element->type == StackElement::Template; + + if (!topLevel && m_current->type == StackElement::Root) { + m_error = QStringLiteral("Tag requires parent: '%1'").arg(tagName); + return false; + } + + StackElement topElement = !m_current ? StackElement(0) : *m_current; + element->entry = topElement.entry; + + QHash attributes; + attributes.insert(sinceAttribute(), QLatin1String("0")); + switch (element->type) { + case StackElement::Root: + attributes.insert(QLatin1String("package"), QString()); + attributes.insert(QLatin1String("default-superclass"), QString()); + break; + case StackElement::LoadTypesystem: + attributes.insert(nameAttribute(), QString()); + attributes.insert(QLatin1String("generate"), QLatin1String("yes")); + break; + case StackElement::NoNullPointers: + attributes.insert(QLatin1String("default-value"), QString()); + break; + case StackElement::SuppressedWarning: + attributes.insert(QLatin1String("text"), 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"), QLatin1String("no")); + 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"), QLatin1String("no")); + attributes.insert(QLatin1String("associated-to"), QString()); + attributes.insert(QLatin1String("virtual-slot"), QLatin1String("no")); + attributes.insert(QLatin1String("thread"), QLatin1String("no")); + attributes.insert(QLatin1String("allow-thread"), QLatin1String("no")); + break; + case StackElement::ModifyArgument: + attributes.insert(QLatin1String("index"), QString()); + attributes.insert(QLatin1String("replace-value"), QString()); + attributes.insert(QLatin1String("invalidate-after-use"), QLatin1String("no")); + break; + case StackElement::ModifyField: + attributes.insert(nameAttribute(), QString()); + attributes.insert(QLatin1String("write"), QLatin1String("true")); + attributes.insert(QLatin1String("read"), QLatin1String("true")); + 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")); + break; + case StackElement::CustomMetaDestructor: + attributes[nameAttribute()] = topElement.entry->name().toLower() + QLatin1String("_delete"); + attributes.insert(QLatin1String("param-name"), QLatin1String("copy")); + 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()); + break; + case StackElement::ConversionRule: + attributes.insert(QLatin1String("class"), QString()); + attributes.insert(QLatin1String("file"), QString()); + break; + case StackElement::TargetToNative: + attributes.insert(QLatin1String("replace"), QLatin1String("yes")); + 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()); + default: + { }; + }; + + double since = 0; + if (attributes.count() > 0) { + fetchAttributeValues(tagName, atts, &attributes); + since = attributes[sinceAttribute()].toDouble(); + } + + 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( + 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, generateChild)) { + m_error = QStringLiteral("Failed to parse: '%1'").arg(name); + return false; + } + } + break; + case StackElement::RejectEnumValue: { + if (!m_currentEnum) { + m_error = QLatin1String(" node must be used inside a node"); + return false; + } + QString name = attributes[nameAttribute()]; + } 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"); + 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 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(since); + 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(m_current->entry)); + customConversionsForReview.append(customConversion); + } + } + 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(0); + } + 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")] == QLatin1String("yes"); + static_cast(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(m_current->entry)->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck); + m_contextStack.top()->codeSnips << CodeSnip(0); + } + 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, since); + 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"); + 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"); + return false; + } + + static QHash 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); + return false; + } + + static QHash 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); + return false; + } + + m_contextStack.top()->functionMods.last().argument_mods.last().ownerships[lang] = owner; + } + break; + case StackElement::SuppressedWarning: + if (attributes[QLatin1String("text")].isEmpty()) + qCWarning(lcShiboken) << "Suppressed warning with no text specified"; + else + m_database->addSuppressedWarning(attributes[QLatin1String("text")]); + 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"); + return false; + } + + static QHash 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); + return false; + } + + m_contextStack.top()->functionMods.last().removal = lang; + } + 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 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); + return false; + } + + if (mod) + mod->modifiers |= modifierNames[modifier]; + } + break; + case StackElement::RemoveArgument: + if (topElement.type != StackElement::ModifyArgument) { + m_error = QLatin1String("Removing argument requires argument modification as parent"); + return false; + } + + 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 == QLatin1String("true")) fm.modifiers |= FieldModification::Readable; + if (write == QLatin1String("true")) 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; + } + QString signature = attributes[QLatin1String("signature")]; + + signature = TypeDatabase::normalizedSignature(signature); + 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")], since); + func.setStatic(attributes[QLatin1String("static")] == QLatin1String("yes")); + 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(since); + mod.signature = m_currentSignature; + 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; + } + QString signature = attributes[QLatin1String("signature")]; + + signature = TypeDatabase::normalizedSignature(signature); + 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(since); + m_currentSignature = mod.signature = 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)) + 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; + 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."); + 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 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::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); + return false; + } + + static QHash 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"); + return false; + } + ao.index = idx; + m_contextStack.top()->functionMods.last().argument_mods.last().owner = ao; + } + 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 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 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); + return false; + } + + CodeSnip snip(since); + 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()) { + if (QFile::exists(file_name)) { + QFile codeFile(file_name); + 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"); + return false; + } + + if (topElement.type == StackElement::ModifyFunction || topElement.type == StackElement::AddFunction) { + FunctionModification mod = m_contextStack.top()->functionMods.last(); + 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 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); + return false; + } + + Include::IncludeType loc = locationNames[location]; + Include inc(loc, attributes[QLatin1String("file-name")]); + + ComplexTypeEntry *ctype = static_cast(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"); + return false; + } + + inc = ctype->include(); + IncludeList lst = ctype->extraIncludes(); + ctype = ctype->designatedInterface(); + if (ctype) { + ctype->setExtraIncludes(lst); + ctype->setInclude(inc); + } + } + break; + case StackElement::Rejection: + if (!addRejection(m_database, attributes, &m_error)) + return false; + break; + case StackElement::Template: + element->value.templateEntry = new TemplateEntry(attributes[nameAttribute()], since); + 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."); + return false; + } + element->value.templateInstance = new TemplateInstance(attributes[nameAttribute()], since); + break; + case StackElement::Replace: + if (topElement.type != StackElement::TemplateInstanceEnum) { + m_error = QLatin1String("Can only insert replace rules into insert-template."); + return false; + } + element->parent->value.templateInstance->addReplaceRule(attributes[QLatin1String("from")], attributes[QLatin1String("to")]); + break; + default: + break; // nada + }; + } + + m_current = element; + return true; +} + +PrimitiveTypeEntry *PrimitiveTypeEntry::basicReferencedTypeEntry() const +{ + if (!m_referencedTypeEntry) + return 0; + + PrimitiveTypeEntry *baseReferencedTypeEntry = m_referencedTypeEntry->basicReferencedTypeEntry(); + if (baseReferencedTypeEntry) + return baseReferencedTypeEntry; + else + return m_referencedTypeEntry; +} + +typedef QHash 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); +} + +CodeSnipList TypeEntry::codeSnips() const +{ + return m_codeSnips; +} + +QString Modification::accessModifierString() const +{ + if (isPrivate()) return QLatin1String("private"); + if (isProtected()) return QLatin1String("protected"); + if (isPublic()) return QLatin1String("public"); + if (isFriendly()) return QLatin1String("friendly"); + return QString(); +} + +FunctionModificationList ComplexTypeEntry::functionModifications(const QString &signature) const +{ + FunctionModificationList lst; + for (int i = 0; i < m_functionMods.count(); ++i) { + const FunctionModification &mod = m_functionMods.at(i); + if (mod.signature == signature) + lst << mod; + } + return lst; +} + +FieldModification ComplexTypeEntry::fieldModification(const QString &name) const +{ + for (int i = 0; i < m_fieldMods.size(); ++i) + if (m_fieldMods.at(i).name == name) + return m_fieldMods.at(i); + FieldModification mod; + mod.name = name; + mod.modifiers = FieldModification::Readable | FieldModification::Writable; + return mod; +} + +// The things we do not to break the ABI... +typedef QHash ComplexTypeEntryDefaultConstructorMap; +Q_GLOBAL_STATIC(ComplexTypeEntryDefaultConstructorMap, complexTypeEntryDefaultConstructors); + +void ComplexTypeEntry::setDefaultConstructor(const QString& defaultConstructor) +{ + if (!defaultConstructor.isEmpty()) + complexTypeEntryDefaultConstructors()->insert(this, defaultConstructor); +} +QString ComplexTypeEntry::defaultConstructor() const +{ + if (!complexTypeEntryDefaultConstructors()->contains(this)) + return QString(); + return complexTypeEntryDefaultConstructors()->value(this); +} +bool ComplexTypeEntry::hasDefaultConstructor() const +{ + return complexTypeEntryDefaultConstructors()->contains(this); +} + +QString ContainerTypeEntry::targetLangPackage() const +{ + return QString(); +} + +QString ContainerTypeEntry::targetLangName() const +{ + + switch (m_type) { + case StringListContainer: return QLatin1String("QStringList"); + case ListContainer: return QLatin1String("QList"); + case LinkedListContainer: return QLatin1String("QLinkedList"); + case VectorContainer: return QLatin1String("QVector"); + case StackContainer: return QLatin1String("QStack"); + case QueueContainer: return QLatin1String("QQueue"); + case SetContainer: return QLatin1String("QSet"); + case MapContainer: return QLatin1String("QMap"); + case MultiMapContainer: return QLatin1String("QMultiMap"); + case HashContainer: return QLatin1String("QHash"); + case MultiHashContainer: return QLatin1String("QMultiHash"); + case PairContainer: return QLatin1String("QPair"); + default: + qWarning("bad type... %d", m_type); + break; + } + return QString(); +} + +QString ContainerTypeEntry::qualifiedCppName() const +{ + if (m_type == StringListContainer) + return QLatin1String("QStringList"); + return ComplexTypeEntry::qualifiedCppName(); +} + +QString EnumTypeEntry::targetLangQualifier() const +{ + TypeEntry *te = TypeDatabase::instance()->findType(m_qualifier); + if (te) + return te->targetLangName(); + else + return m_qualifier; +} + +QString EnumTypeEntry::targetLangApiName() const +{ + return QLatin1String("jint"); +} + +QString FlagsTypeEntry::targetLangApiName() const +{ + return QLatin1String("jint"); +} + +void EnumTypeEntry::addEnumValueRedirection(const QString &rejected, const QString &usedValue) +{ + m_enumRedirections << EnumValueRedirection(rejected, usedValue); +} + +QString EnumTypeEntry::enumValueRedirection(const QString &value) const +{ + for (int i = 0; i < m_enumRedirections.size(); ++i) + if (m_enumRedirections.at(i).rejected == value) + return m_enumRedirections.at(i).used; + return QString(); +} + +QString FlagsTypeEntry::qualifiedTargetLangName() const +{ + return targetLangPackage() + QLatin1Char('.') + m_enum->targetLangQualifier() + + QLatin1Char('.') + targetLangName(); +} + +/*! + * The Visual Studio 2002 compiler doesn't support these symbols, + * which our typedefs unforntuatly expand to. + */ +QString fixCppTypeName(const QString &name) +{ + if (name == QLatin1String("long long")) + return QLatin1String("qint64"); + else if (name == QLatin1String("unsigned long long")) + return QLatin1String("quint64"); + return name; +} + +QString TemplateInstance::expandCode() const +{ + TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name); + if (templateEntry) { + typedef QHash::const_iterator ConstIt; + QString code = templateEntry->code(); + for (ConstIt it = replaceRules.begin(), end = replaceRules.end(); it != end; ++it) + code.replace(it.key(), it.value()); + while (!code.isEmpty() && code.at(code.size() - 1).isSpace()) + code.chop(1); + QString result = QLatin1String("// TEMPLATE - ") + m_name + QLatin1String(" - START"); + if (!code.startsWith(QLatin1Char('\n'))) + result += QLatin1Char('\n'); + 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 << '\''; + } + + return QString(); +} + + +QString CodeSnipAbstract::code() const +{ + QString res; + for (const CodeSnipFragment &codeFrag : codeList) + res.append(codeFrag.code()); + + return res; +} + +QString CodeSnipFragment::code() const +{ + if (m_instance) + return m_instance->expandCode(); + else + return m_code; +} + +QString FunctionModification::toString() const +{ + QString str = signature + QLatin1String("->"); + if (modifiers & AccessModifierMask) { + switch (modifiers & AccessModifierMask) { + case Private: str += QLatin1String("private"); break; + case Protected: str += QLatin1String("protected"); break; + case Public: str += QLatin1String("public"); break; + case Friendly: str += QLatin1String("friendly"); break; + } + } + + if (modifiers & Final) str += QLatin1String("final"); + if (modifiers & NonFinal) str += QLatin1String("non-final"); + + if (modifiers & Readable) str += QLatin1String("readable"); + if (modifiers & Writable) str += QLatin1String("writable"); + + if (modifiers & CodeInjection) { + for (const CodeSnip &s : snips) { + str += QLatin1String("\n//code injection:\n"); + str += s.code(); + } + } + + if (modifiers & Rename) str += QLatin1String("renamed:") + renamedToName; + + if (modifiers & Deprecated) str += QLatin1String("deprecate"); + + if (modifiers & ReplaceExpression) str += QLatin1String("replace-expression"); + + return str; +} + +bool FunctionModification::operator!=(const FunctionModification& other) const +{ + return !(*this == other); +} + +bool FunctionModification::operator==(const FunctionModification& other) const +{ + if (signature != other.signature) + return false; + + if (association != other.association) + return false; + + if (modifiers != other.modifiers) + return false; + + if (removal != other.removal) + return false; + + if (m_thread != other.m_thread) + return false; + + if (m_allowThread != other.m_allowThread) + return false; + + if (m_version != other.m_version) + return false; + + return true; +} + +static AddedFunction::TypeInfo parseType(const QString& signature, int startPos = 0, int* endPos = 0) +{ + AddedFunction::TypeInfo result; + static const QRegularExpression regex(QLatin1String("\\w")); + Q_ASSERT(regex.isValid()); + int length = signature.length(); + int start = signature.indexOf(regex, startPos); + if (start == -1) { + if (signature.midRef(startPos + 1, 3) == QLatin1String("...")) { // varargs + if (endPos) + *endPos = startPos + 4; + result.name = QLatin1String("..."); + } else { // error + if (endPos) + *endPos = length; + } + return result; + } + + int cantStop = 0; + QString paramString; + QChar c; + int i = start; + for (; i < length; ++i) { + c = signature[i]; + if (c == QLatin1Char('<')) + cantStop++; + if (c == QLatin1Char('>')) + cantStop--; + if (cantStop < 0) + break; // FIXME: report error? + if ((c == QLatin1Char(')') || c == QLatin1Char(',')) && !cantStop) + break; + paramString += signature[i]; + } + if (endPos) + *endPos = i; + + // Check default value + if (paramString.contains(QLatin1Char('='))) { + QStringList lst = paramString.split(QLatin1Char('=')); + paramString = lst[0].trimmed(); + result.defaultValue = lst[1].trimmed(); + } + + // check constness + if (paramString.startsWith(QLatin1String("const "))) { + result.isConstant = true; + paramString.remove(0, sizeof("const")/sizeof(char)); + paramString = paramString.trimmed(); + } + // check reference + if (paramString.endsWith(QLatin1Char('&'))) { + result.isReference = true; + paramString.chop(1); + paramString = paramString.trimmed(); + } + // check Indirections + while (paramString.endsWith(QLatin1Char('*'))) { + result.indirections++; + paramString.chop(1); + paramString = paramString.trimmed(); + } + result.name = paramString; + + return result; +} + +AddedFunction::AddedFunction(QString signature, QString returnType, double vr) : m_access(Public), m_version(vr) +{ + Q_ASSERT(!returnType.isEmpty()); + m_returnType = parseType(returnType); + signature = signature.trimmed(); + int endPos = signature.indexOf(QLatin1Char('(')); + if (endPos < 0) { + m_isConst = false; + m_name = signature; + } else { + m_name = signature.left(endPos).trimmed(); + int signatureLength = signature.length(); + while (endPos < signatureLength) { + TypeInfo arg = parseType(signature, endPos, &endPos); + if (!arg.name.isEmpty()) + m_arguments.append(arg); + // end of parameters... + if (signature[endPos] == QLatin1Char(')')) + break; + } + // is const? + m_isConst = signature.right(signatureLength - endPos).contains(QLatin1String("const")); + } +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AddedFunction::TypeInfo &ti) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "TypeInfo("; + if (ti.isConstant) + d << "const"; + if (ti.indirections) + d << QByteArray(ti.indirections, '*'); + if (ti.isReference) + d << " &"; + d << ti.name; + if (!ti.defaultValue.isEmpty()) + d << " = " << ti.defaultValue; + d << ')'; + return d; +} + +QDebug operator<<(QDebug d, const AddedFunction &af) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AddedFunction("; + if (af.access() == AddedFunction::Protected) + d << "protected"; + if (af.isStatic()) + d << " static"; + d << af.returnType() << ' ' << af.name() << '(' << af.arguments() << ')'; + if (af.isConstant()) + d << " const"; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +AddedFunction::TypeInfo AddedFunction::TypeInfo::fromSignature(const QString& signature) +{ + return parseType(signature); +} + +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(); +} +QString CharTypeEntry::targetLangApiName() const +{ + return strings_jchar; +} +QString CharTypeEntry::targetLangName() const +{ + return strings_char; +} +QString VariantTypeEntry::targetLangApiName() const +{ + return strings_jobject; +} +QString VariantTypeEntry::targetLangName() const +{ + return strings_Object; +} +QString VariantTypeEntry::targetLangPackage() const +{ + return QString(); +} + +QString ContainerTypeEntry::typeName() const +{ + switch(m_type) { + case LinkedListContainer: + return QLatin1String("linked-list"); + case ListContainer: + return QLatin1String("list"); + case StringListContainer: + return QLatin1String("string-list"); + case VectorContainer: + return QLatin1String("vector"); + case StackContainer: + return QLatin1String("stack"); + case QueueContainer: + return QLatin1String("queue"); + case SetContainer: + return QLatin1String("set"); + case MapContainer: + return QLatin1String("map"); + case MultiMapContainer: + return QLatin1String("multi-map"); + case HashContainer: + return QLatin1String("hash"); + case MultiHashContainer: + return QLatin1String("multi-hash"); + case PairContainer: + return QLatin1String("pair"); + case NoContainer: + default: + return QLatin1String("?"); + } +} + +static bool strLess(const char* a, const char* b) +{ + return ::strcmp(a, b) < 0; +} + +bool TypeEntry::isCppPrimitive() const +{ + if (!isPrimitive()) + return false; + + const PrimitiveTypeEntry *referencedType = + static_cast(this)->basicReferencedTypeEntry(); + QByteArray typeName = (referencedType ? referencedType->name() : m_name).toUtf8(); + + if (typeName.contains(' ') || m_type == VoidType) + return true; + // Keep this sorted!! + static const char* cppTypes[] = { "bool", "char", "double", "float", "int", "long", "long long", "short", "wchar_t" }; + const int N = sizeof(cppTypes)/sizeof(char*); + + const char** res = qBinaryFind(&cppTypes[0], &cppTypes[N], typeName.constData(), strLess); + + return res != &cppTypes[N]; +} + +// Again, stuff to avoid ABI breakage. +typedef QHash TypeEntryCustomConversionMap; +Q_GLOBAL_STATIC(TypeEntryCustomConversionMap, typeEntryCustomConversionMap); + +TypeEntry::~TypeEntry() +{ + if (typeEntryCustomConversionMap()->contains(this)) { + CustomConversion* customConversion = typeEntryCustomConversionMap()->value(this); + typeEntryCustomConversionMap()->remove(this); + delete customConversion; + } +} + +bool TypeEntry::hasCustomConversion() const +{ + return typeEntryCustomConversionMap()->contains(this); +} +void TypeEntry::setCustomConversion(CustomConversion* customConversion) +{ + if (customConversion) + typeEntryCustomConversionMap()->insert(this, customConversion); + else if (typeEntryCustomConversionMap()->contains(this)) + typeEntryCustomConversionMap()->remove(this); +} +CustomConversion* TypeEntry::customConversion() const +{ + if (typeEntryCustomConversionMap()->contains(this)) + return typeEntryCustomConversionMap()->value(this); + return 0; +} + +/* +static void injectCode(ComplexTypeEntry *e, + const char *signature, + const QByteArray &code, + const ArgumentMap &args) +{ + 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 +{ + CustomConversionPrivate(const TypeEntry* ownerType) + : ownerType(ownerType), replaceOriginalTargetToNativeConversions(false) + { + } + const TypeEntry* ownerType; + QString nativeToTargetConversion; + bool replaceOriginalTargetToNativeConversions; + TargetToNativeConversions targetToNativeConversions; +}; + +struct CustomConversion::TargetToNativeConversion::TargetToNativeConversionPrivate +{ + TargetToNativeConversionPrivate() + : sourceType(0) + { + } + const TypeEntry* sourceType; + QString sourceTypeName; + QString sourceTypeCheck; + QString conversion; +}; + +CustomConversion::CustomConversion(TypeEntry* ownerType) +{ + m_d = new CustomConversionPrivate(ownerType); + if (ownerType) + ownerType->setCustomConversion(this); +} + +CustomConversion::~CustomConversion() +{ + qDeleteAll(m_d->targetToNativeConversions); + delete m_d; +} + +const TypeEntry* CustomConversion::ownerType() const +{ + return m_d->ownerType; +} + +QString CustomConversion::nativeToTargetConversion() const +{ + return m_d->nativeToTargetConversion; +} + +void CustomConversion::setNativeToTargetConversion(const QString& nativeToTargetConversion) +{ + m_d->nativeToTargetConversion = nativeToTargetConversion; +} + +bool CustomConversion::replaceOriginalTargetToNativeConversions() const +{ + return m_d->replaceOriginalTargetToNativeConversions; +} + +void CustomConversion::setReplaceOriginalTargetToNativeConversions(bool replaceOriginalTargetToNativeConversions) +{ + m_d->replaceOriginalTargetToNativeConversions = replaceOriginalTargetToNativeConversions; +} + +bool CustomConversion::hasTargetToNativeConversions() const +{ + return !(m_d->targetToNativeConversions.isEmpty()); +} + +CustomConversion::TargetToNativeConversions& CustomConversion::targetToNativeConversions() +{ + return m_d->targetToNativeConversions; +} + +const CustomConversion::TargetToNativeConversions& CustomConversion::targetToNativeConversions() const +{ + return m_d->targetToNativeConversions; +} + +void CustomConversion::addTargetToNativeConversion(const QString& sourceTypeName, + const QString& sourceTypeCheck, + const QString& conversion) +{ + m_d->targetToNativeConversions.append(new TargetToNativeConversion(sourceTypeName, sourceTypeCheck, conversion)); +} + +CustomConversion::TargetToNativeConversion::TargetToNativeConversion(const QString& sourceTypeName, + const QString& sourceTypeCheck, + const QString& conversion) +{ + m_d = new TargetToNativeConversionPrivate; + m_d->sourceTypeName = sourceTypeName; + m_d->sourceTypeCheck = sourceTypeCheck; + m_d->conversion = conversion; +} + +CustomConversion::TargetToNativeConversion::~TargetToNativeConversion() +{ + delete m_d; +} + +const TypeEntry* CustomConversion::TargetToNativeConversion::sourceType() const +{ + return m_d->sourceType; +} + +void CustomConversion::TargetToNativeConversion::setSourceType(const TypeEntry* sourceType) +{ + m_d->sourceType = sourceType; +} + +bool CustomConversion::TargetToNativeConversion::isCustomType() const +{ + return !(m_d->sourceType); +} + +QString CustomConversion::TargetToNativeConversion::sourceTypeName() const +{ + return m_d->sourceTypeName; +} + +QString CustomConversion::TargetToNativeConversion::sourceTypeCheck() const +{ + return m_d->sourceTypeCheck; +} + +QString CustomConversion::TargetToNativeConversion::conversion() const +{ + return m_d->conversion; +} + +void CustomConversion::TargetToNativeConversion::setConversion(const QString& conversion) +{ + m_d->conversion = conversion; +} diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h new file mode 100644 index 000000000..b75da48ba --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -0,0 +1,1975 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 TYPESYSTEM_H +#define TYPESYSTEM_H + +#include "typesystem_enums.h" +#include "typesystem_typedefs.h" +#include "include.h" + +#include +#include +#include +#include +#include +#include +#include + +//Used to identify the conversion rule to avoid break API +#define TARGET_CONVERSION_RULE_FLAG "0" +#define NATIVE_CONVERSION_RULE_FLAG "1" + +class Indentor; + +class AbstractMetaType; +QT_BEGIN_NAMESPACE +class QDebug; +class QTextStream; +QT_END_NAMESPACE + +class EnumTypeEntry; +class FlagsTypeEntry; + +typedef QMap ArgumentMap; + +class TemplateInstance; + +struct ReferenceCount +{ + ReferenceCount() {} + enum Action { // 0x01 - 0xff + Invalid = 0x00, + Add = 0x01, + AddAll = 0x02, + Remove = 0x04, + Set = 0x08, + Ignore = 0x10, + + ActionsMask = 0xff, + + Padding = 0xffffffff + }; + + Action action; + QString varName; +}; + +struct ArgumentOwner +{ + enum Action { + Invalid = 0x00, + Add = 0x01, + Remove = 0x02 + }; + enum { + InvalidIndex = -2, + ThisIndex = -1, + ReturnIndex = 0, + FirstArgumentIndex = 1 + }; + ArgumentOwner() : action(ArgumentOwner::Invalid), index(ArgumentOwner::InvalidIndex) {} + + Action action; + int index; +}; + +class CodeSnipFragment +{ +private: + QString m_code; + TemplateInstance *m_instance; + +public: + CodeSnipFragment() : m_instance(0) {} + CodeSnipFragment(const QString &code) + : m_code(code), + m_instance(0) {} + + CodeSnipFragment(TemplateInstance *instance) + : m_instance(instance) {} + + QString code() const; +}; + +class CodeSnipAbstract +{ +public: + QString code() const; + + void addCode(const QString &code) { codeList.append(CodeSnipFragment(code)); } + void addCode(const QStringRef &code) { addCode(code.toString()); } + + void addTemplateInstance(TemplateInstance *ti) + { + codeList.append(CodeSnipFragment(ti)); + } + + QVector codeList; +}; + +class CustomFunction : public CodeSnipAbstract +{ +public: + CustomFunction(const QString &n = QString()) : name(n) { } + + QString name; + QString paramName; +}; + +class TemplateEntry : public CodeSnipAbstract +{ +public: + TemplateEntry(const QString &name, double vr) + : m_name(name), m_version(vr) + { + }; + + QString name() const + { + return m_name; + }; + + double version() const + { + return m_version; + } + +private: + QString m_name; + double m_version; +}; + +class TemplateInstance +{ +public: + TemplateInstance(const QString &name, double vr) + : m_name(name), m_version(vr) {} + + void addReplaceRule(const QString &name, const QString &value) + { + replaceRules[name] = value; + } + + QString expandCode() const; + + QString name() const + { + return m_name; + } + + double version() const + { + return m_version; + } + +private: + const QString m_name; + double m_version; + QHash replaceRules; +}; + + +class CodeSnip : public CodeSnipAbstract +{ +public: + CodeSnip() : language(TypeSystem::TargetLangCode), version(0) {} + CodeSnip(double vr) : language(TypeSystem::TargetLangCode), version(vr) { } + CodeSnip(double vr, TypeSystem::Language lang) : language(lang), version(vr) { } + + TypeSystem::Language language; + TypeSystem::CodeSnipPosition position; + ArgumentMap argumentMap; + double version; +}; + +struct ArgumentModification +{ + ArgumentModification() : removedDefaultExpression(false), removed(false), + noNullPointers(false), index(-1), version(0) {} + ArgumentModification(int idx, double vr) + : removedDefaultExpression(false), removed(false), + noNullPointers(false), index(idx), version(vr) {} + + // Should the default expression be removed? + uint removedDefaultExpression : 1; + uint removed : 1; + uint noNullPointers : 1; + uint resetAfterUse : 1; + + // The index of this argument + int index; + + // Reference count flags for this argument + QVector referenceCounts; + + // The text given for the new type of the argument + QString modified_type; + + 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; + + // The new definition of ownership for a specific argument + QHash ownerships; + + // Different conversion rules + CodeSnipList conversion_rules; + + //QObject parent(owner) of this argument + ArgumentOwner owner; + + //Api version + double version; + + //New name + QString renamed_to; +}; + +struct Modification +{ + enum Modifiers { + Private = 0x0001, + Protected = 0x0002, + Public = 0x0003, + Friendly = 0x0004, + AccessModifierMask = 0x000f, + + Final = 0x0010, + NonFinal = 0x0020, + FinalMask = Final | NonFinal, + + Readable = 0x0100, + Writable = 0x0200, + + CodeInjection = 0x1000, + Rename = 0x2000, + Deprecated = 0x4000, + ReplaceExpression = 0x8000, + VirtualSlot = 0x10000 | NonFinal + }; + + Modification() : modifiers(0), removal(TypeSystem::NoLanguage) { } + + bool isAccessModifier() const + { + return modifiers & AccessModifierMask; + } + Modifiers accessModifier() const + { + return Modifiers(modifiers & AccessModifierMask); + } + bool isPrivate() const + { + return accessModifier() == Private; + } + bool isProtected() const + { + return accessModifier() == Protected; + } + bool isPublic() const + { + return accessModifier() == Public; + } + bool isFriendly() const + { + return accessModifier() == Friendly; + } + bool isFinal() const + { + return modifiers & Final; + } + bool isNonFinal() const + { + return modifiers & NonFinal; + } + bool isVirtualSlot() const + { + return (modifiers & VirtualSlot) == VirtualSlot; + } + QString accessModifierString() const; + + bool isDeprecated() const + { + return modifiers & Deprecated; + } + + void setRenamedTo(const QString &name) + { + renamedToName = name; + } + QString renamedTo() const + { + return renamedToName; + } + bool isRenameModifier() const + { + return modifiers & Rename; + } + + bool isRemoveModifier() const + { + return removal != TypeSystem::NoLanguage; + } + + uint modifiers; + QString renamedToName; + TypeSystem::Language removal; +}; + +struct FunctionModification: public Modification +{ + FunctionModification() : m_thread(false), m_allowThread(false), m_version(0) {} + FunctionModification(double vr) : m_thread(false), m_allowThread(false), m_version(vr) {} + + bool isCodeInjection() const + { + return modifiers & CodeInjection; + } + void setIsThread(bool flag) + { + m_thread = flag; + } + bool isThread() const + { + return m_thread; + } + bool allowThread() const + { + return m_allowThread; + } + void setAllowThread(bool allow) + { + m_allowThread = allow; + } + double version() const + { + return m_version; + } + + bool operator!=(const FunctionModification& other) const; + bool operator==(const FunctionModification& other) const; + + + QString toString() const; + + QString signature; + QString association; + CodeSnipList snips; + + QVector argument_mods; + +private: + bool m_thread; + bool m_allowThread; + double m_version; + + +}; + +struct FieldModification: public Modification +{ + bool isReadable() const + { + return modifiers & Readable; + } + bool isWritable() const + { + return modifiers & Writable; + } + + QString name; +}; + +/** +* \internal +* Struct used to store information about functions added by the typesystem. +* This info will be used later to create a fake AbstractMetaFunction which +* will be inserted into the right AbstractMetaClass. +*/ +struct AddedFunction +{ + /// Function access types. + enum Access { + Protected = 0x1, + Public = 0x2 + }; + + /** + * \internal + * Internal struct used to store information about arguments and return type of the + * functions added by the type system. This information is later used to create + * AbstractMetaType and AbstractMetaArgument for the AbstractMetaFunctions. + */ + struct TypeInfo { + TypeInfo() : isConstant(false), indirections(0), isReference(false) {} + static TypeInfo fromSignature(const QString& signature); + + QString name; + bool isConstant; + int indirections; + bool isReference; + QString defaultValue; + }; + + /// Creates a new AddedFunction with a signature and a return type. + AddedFunction(QString signature, QString returnType, double vr); + AddedFunction() : m_access(Protected), m_isConst(false), m_isStatic(false), m_version(0) {} + + /// Returns the function name. + QString name() const + { + return m_name; + } + + /// Set the function access type. + void setAccess(Access access) + { + m_access = access; + } + + /// Returns the function access type. + Access access() const + { + return m_access; + } + + /// Returns the function return type. + TypeInfo returnType() const + { + return m_returnType; + } + + /// Returns a list of argument type infos. + QVector arguments() const + { + return m_arguments; + } + + /// Returns true if this is a constant method. + bool isConstant() const + { + return m_isConst; + } + + /// Set this method static. + void setStatic(bool value) + { + m_isStatic = value; + } + + /// Returns true if this is a static method. + bool isStatic() const + { + return m_isStatic; + } + + double version() const + { + return m_version; + } +private: + QString m_name; + Access m_access; + QVector m_arguments; + TypeInfo m_returnType; + bool m_isConst; + bool m_isStatic; + double m_version; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AddedFunction::TypeInfo &ti); +QDebug operator<<(QDebug d, const AddedFunction &af); +#endif + +struct ExpensePolicy +{ + ExpensePolicy() : limit(-1) {} + int limit; + QString cost; + bool isValid() const + { + return limit >= 0; + } +}; + +class InterfaceTypeEntry; +class ObjectTypeEntry; + +class DocModification +{ +public: + DocModification() : format(TypeSystem::NativeCode), m_mode(TypeSystem::DocModificationXPathReplace), m_version(0) {} + DocModification(const QString& xpath, const QString& signature, double vr) + : format(TypeSystem::NativeCode), m_mode(TypeSystem::DocModificationXPathReplace), + m_xpath(xpath), m_signature(signature), m_version(vr) {} + DocModification(TypeSystem::DocModificationMode mode, const QString& signature, double vr) + : m_mode(mode), m_signature(signature), m_version(vr) {} + + void setCode(const QString& code) { m_code = code; } + void setCode(const QStringRef& code) { m_code = code.toString(); } + + QString code() const + { + return m_code; + } + QString xpath() const + { + return m_xpath; + } + QString signature() const + { + return m_signature; + } + TypeSystem::DocModificationMode mode() const + { + return m_mode; + } + double version() const + { + return m_version; + } + + TypeSystem::Language format; + +private: + TypeSystem::DocModificationMode m_mode; + QString m_code; + QString m_xpath; + QString m_signature; + double m_version; +}; + +class CustomConversion; + +class TypeEntry +{ + Q_GADGET +public: + enum Type { + PrimitiveType, + VoidType, + VarargsType, + FlagsType, + EnumType, + EnumValue, + TemplateArgumentType, + ThreadType, + BasicValueType, + StringType, + ContainerType, + InterfaceType, + ObjectType, + NamespaceType, + VariantType, + JObjectWrapperType, + CharType, + ArrayType, + TypeSystemType, + CustomType, + TargetLangType, + FunctionType, + SmartPointerType + }; + Q_ENUM(Type) + + enum CodeGeneration { + GenerateTargetLang = 0x0001, + GenerateCpp = 0x0002, + GenerateForSubclass = 0x0004, + + GenerateNothing = 0, + GenerateAll = 0xffff, + GenerateCode = GenerateTargetLang | GenerateCpp + }; + Q_ENUM(CodeGeneration) + + TypeEntry(const QString &name, Type t, double vr) + : m_name(name), + m_type(t), + m_codeGeneration(GenerateAll), + m_preferredConversion(true), + m_stream(false), + m_version(vr) + { + }; + + virtual ~TypeEntry(); + + Type type() const + { + return m_type; + } + bool isPrimitive() const + { + return m_type == PrimitiveType; + } + bool isEnum() const + { + return m_type == EnumType; + } + bool isFlags() const + { + return m_type == FlagsType; + } + bool isInterface() const + { + return m_type == InterfaceType; + } + bool isObject() const + { + return m_type == ObjectType; + } + bool isString() const + { + return m_type == StringType; + } + bool isChar() const + { + return m_type == CharType; + } + bool isNamespace() const + { + return m_type == NamespaceType; + } + bool isContainer() const + { + return m_type == ContainerType; + } + bool isSmartPointer() const + { + return m_type == SmartPointerType; + } + bool isVariant() const + { + return m_type == VariantType; + } + bool isJObjectWrapper() const + { + return m_type == JObjectWrapperType; + } + bool isArray() const + { + return m_type == ArrayType; + } + bool isTemplateArgument() const + { + return m_type == TemplateArgumentType; + } + bool isVoid() const + { + return m_type == VoidType; + } + bool isVarargs() const + { + return m_type == VarargsType; + } + bool isThread() const + { + return m_type == ThreadType; + } + bool isCustom() const + { + return m_type == CustomType; + } + bool isBasicValue() const + { + return m_type == BasicValueType; + } + bool isTypeSystem() const + { + return m_type == TypeSystemType; + } + bool isFunction() const + { + return m_type == FunctionType; + } + bool isEnumValue() const + { + 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; + } + + void setStream(bool b) + { + m_stream = b; + } + + // The type's name in C++, fully qualified + QString name() const + { + return m_name; + } + + uint codeGeneration() const + { + return m_codeGeneration; + } + void setCodeGeneration(uint cg) + { + m_codeGeneration = cg; + } + + // Returns true if code must be generated for this entry, + // it will return false in case of types coming from typesystems + // included for reference only. + // NOTE: 'GenerateForSubclass' means 'generate="no"' + // on 'load-typesystem' tag + inline bool generateCode() const + { + return m_codeGeneration != TypeEntry::GenerateForSubclass + && m_codeGeneration != TypeEntry::GenerateNothing; + } + + virtual QString qualifiedCppName() const + { + return m_name; + } + + /** + * Its type's name in target language API + * The target language API name represents how this type is + * referred on low level code for the target language. + * Examples: for Java this would be a JNI name, for Python + * it should represent the CPython type name. + * /return string representing the target language API name + * for this type entry + */ + virtual QString targetLangApiName() const + { + return m_name; + } + + // The type's name in TargetLang + virtual QString targetLangName() const + { + return m_name; + } + + // The type to lookup when converting to TargetLang + virtual QString lookupName() const + { + return targetLangName(); + } + + // The package + virtual QString targetLangPackage() const + { + return QString(); + } + + virtual QString qualifiedTargetLangName() const + { + QString pkg = targetLangPackage(); + if (pkg.isEmpty()) + return targetLangName(); + return pkg + QLatin1Char('.') + targetLangName(); + } + + virtual InterfaceTypeEntry *designatedInterface() const + { + return 0; + } + + void setCustomConstructor(const CustomFunction &func) + { + m_customConstructor = func; + } + CustomFunction customConstructor() const + { + return m_customConstructor; + } + + void setCustomDestructor(const CustomFunction &func) + { + m_customDestructor = func; + } + CustomFunction customDestructor() const + { + return m_customDestructor; + } + + virtual bool isValue() const + { + return false; + } + virtual bool isComplex() const + { + return false; + } + + virtual bool isNativeIdBased() const + { + return false; + } + + CodeSnipList codeSnips() const; + void setCodeSnips(const CodeSnipList &codeSnips) + { + m_codeSnips = codeSnips; + } + void addCodeSnip(const CodeSnip &codeSnip) + { + m_codeSnips << codeSnip; + } + + void setDocModification(const DocModificationList& docMods) + { + m_docModifications << docMods; + } + DocModificationList docModifications() const + { + return m_docModifications; + } + + IncludeList extraIncludes() const + { + return m_extraIncludes; + } + void setExtraIncludes(const IncludeList &includes) + { + m_extraIncludes = includes; + } + void addExtraInclude(const Include &include) + { + if (!m_includesUsed.value(include.name(), false)) { + m_extraIncludes << include; + m_includesUsed[include.name()] = true; + } + } + + Include include() const + { + return m_include; + } + void setInclude(const Include &inc) + { + // This is a workaround for preventing double inclusion of the QSharedPointer implementation + // header, which does not use header guards. In the previous parser this was not a problem + // because the Q_QDOC define was set, and the implementation header was never included. + if (inc.name() == QLatin1String("qsharedpointer_impl.h")) + m_include = Include(inc.type(), QLatin1String("qsharedpointer.h")); + else + m_include = inc; + } + + // Replace conversionRule arg to CodeSnip in future version + /// Set the type convertion rule + void setConversionRule(const QString& conversionRule) + { + m_conversionRule = conversionRule; + } + + /// Returns the type convertion rule + QString conversionRule() const + { + //skip conversions flag + return m_conversionRule.mid(1); + } + + /// Returns true if there are any conversiton rule for this type, false otherwise. + bool hasConversionRule() const + { + return !m_conversionRule.isEmpty(); + } + + double version() const + { + return m_version; + } + + /// TODO-CONVERTER: mark as deprecated + bool hasNativeConversionRule() const + { + return m_conversionRule.startsWith(QLatin1String(NATIVE_CONVERSION_RULE_FLAG)); + } + + /// TODO-CONVERTER: mark as deprecated + bool hasTargetConversionRule() const + { + return m_conversionRule.startsWith(QLatin1String(TARGET_CONVERSION_RULE_FLAG)); + } + + bool isCppPrimitive() const; + + bool hasCustomConversion() const; + void setCustomConversion(CustomConversion* customConversion); + CustomConversion* customConversion() const; +private: + QString m_name; + Type m_type; + uint m_codeGeneration; + CustomFunction m_customConstructor; + CustomFunction m_customDestructor; + bool m_preferredConversion; + CodeSnipList m_codeSnips; + DocModificationList m_docModifications; + IncludeList m_extraIncludes; + Include m_include; + QHash m_includesUsed; + QString m_conversionRule; + bool m_stream; + double m_version; +}; + +class TypeSystemTypeEntry : public TypeEntry +{ +public: + TypeSystemTypeEntry(const QString &name, double vr) + : TypeEntry(name, TypeSystemType, vr) + { + }; +}; + +class VoidTypeEntry : public TypeEntry +{ +public: + VoidTypeEntry() : TypeEntry(QLatin1String("void"), VoidType, 0) { } +}; + +class VarargsTypeEntry : public TypeEntry +{ +public: + VarargsTypeEntry() : TypeEntry(QLatin1String("..."), VarargsType, 0) { } +}; + +class TemplateArgumentEntry : public TypeEntry +{ +public: + TemplateArgumentEntry(const QString &name, double vr) + : TypeEntry(name, TemplateArgumentType, vr), m_ordinal(0) + { + } + + int ordinal() const + { + return m_ordinal; + } + void setOrdinal(int o) + { + m_ordinal = o; + } + +private: + int m_ordinal; +}; + +class ArrayTypeEntry : public TypeEntry +{ +public: + ArrayTypeEntry(const TypeEntry *nested_type, double vr) + : TypeEntry(QLatin1String("Array"), ArrayType, vr), m_nestedType(nested_type) + { + Q_ASSERT(m_nestedType); + } + + void setNestedTypeEntry(TypeEntry *nested) + { + m_nestedType = nested; + } + const TypeEntry *nestedTypeEntry() const + { + return m_nestedType; + } + + QString targetLangName() const override + { + return m_nestedType->targetLangName() + QLatin1String("[]"); + } + QString targetLangApiName() const override + { + if (m_nestedType->isPrimitive()) + return m_nestedType->targetLangApiName() + QLatin1String("Array"); + else + return QLatin1String("jobjectArray"); + } + +private: + const TypeEntry *m_nestedType; +}; + + +class PrimitiveTypeEntry : public TypeEntry +{ +public: + PrimitiveTypeEntry(const QString &name, double vr) + : TypeEntry(name, PrimitiveType, vr), + m_preferredConversion(true), + m_preferredTargetLangType(true), + m_referencedTypeEntry(0) + { + } + + QString targetLangName() const override + { + return m_targetLangName; + } + void setTargetLangName(const QString &targetLangName) + { + m_targetLangName = targetLangName; + } + + QString targetLangApiName() const override + { + return m_targetLangApiName; + } + void setTargetLangApiName(const QString &targetLangApiName) + { + m_targetLangApiName = targetLangApiName; + } + + QString defaultConstructor() const + { + return m_defaultConstructor; + } + void setDefaultConstructor(const QString& defaultConstructor) + { + m_defaultConstructor = defaultConstructor; + } + bool hasDefaultConstructor() const + { + return !m_defaultConstructor.isEmpty(); + } + + /** + * The PrimitiveTypeEntry pointed by this type entry if it + * represents a typedef). + * /return the type referenced by the typedef, or a null pointer + * if the current object is not an typedef + */ + PrimitiveTypeEntry* referencedTypeEntry() const { return m_referencedTypeEntry; } + + /** + * Defines type referenced by this entry. + * /param referencedTypeEntry type referenced by this entry + */ + void setReferencedTypeEntry(PrimitiveTypeEntry* referencedTypeEntry) + { + m_referencedTypeEntry = referencedTypeEntry; + } + + /** + * Finds the most basic primitive type that the typedef represents, + * i.e. a type that is not an typedef'ed. + * /return the most basic non-typedef'ed primitive type represented + * by this typedef + */ + PrimitiveTypeEntry* basicReferencedTypeEntry() const; + + bool preferredConversion() const override + { + return m_preferredConversion; + } + void setPreferredConversion(bool b) override + { + m_preferredConversion = b; + } + + bool preferredTargetLangType() const + { + return m_preferredTargetLangType; + } + void setPreferredTargetLangType(bool b) + { + m_preferredTargetLangType = b; + } + + void setTargetLangPackage(const QString& package); + QString targetLangPackage() const override; +private: + QString m_targetLangName; + QString m_targetLangApiName; + QString m_defaultConstructor; + uint m_preferredConversion : 1; + uint m_preferredTargetLangType : 1; + PrimitiveTypeEntry* m_referencedTypeEntry; +}; + +struct EnumValueRedirection +{ + EnumValueRedirection() {} + EnumValueRedirection(const QString &rej, const QString &us) + : rejected(rej), + used(us) + { + } + QString rejected; + QString used; +}; + +class EnumTypeEntry : public TypeEntry +{ +public: + EnumTypeEntry(const QString &nspace, const QString &enumName, double vr) + : TypeEntry(nspace.isEmpty() ? enumName : nspace + QLatin1String("::") + enumName, + EnumType, vr), + m_qualifier(nspace), + m_targetLangName(enumName), + m_flags(0), + m_extensible(false), + m_forceInteger(false), + m_anonymous(false) + { + } + + QString targetLangPackage() const + { + return m_packageName; + } + void setTargetLangPackage(const QString &package) + { + m_packageName = package; + } + + QString targetLangName() const + { + return m_targetLangName; + } + QString targetLangQualifier() const; + QString qualifiedTargetLangName() const override + { + QString qualifiedName; + QString pkg = targetLangPackage(); + QString qualifier = targetLangQualifier(); + + if (!pkg.isEmpty()) + qualifiedName += pkg + QLatin1Char('.'); + if (!qualifier.isEmpty()) + qualifiedName += qualifier + QLatin1Char('.'); + qualifiedName += targetLangName(); + + return qualifiedName; + } + + QString targetLangApiName() const override; + + QString qualifier() const + { + return m_qualifier; + } + void setQualifier(const QString &q) + { + m_qualifier = q; + } + + bool preferredConversion() const override + { + return false; + } + + 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; + } + + void setFlags(FlagsTypeEntry *flags) + { + m_flags = flags; + } + FlagsTypeEntry *flags() const + { + return m_flags; + } + + bool isExtensible() const + { + return m_extensible; + } + void setExtensible(bool is) + { + m_extensible = is; + } + + bool isEnumValueRejected(const QString &name) + { + return m_rejectedEnums.contains(name); + } + void addEnumValueRejection(const QString &name) + { + m_rejectedEnums << name; + } + QStringList enumValueRejections() const + { + return m_rejectedEnums; + } + + void addEnumValueRedirection(const QString &rejected, const QString &usedValue); + QString enumValueRedirection(const QString &value) const; + + bool forceInteger() const + { + return m_forceInteger; + } + void setForceInteger(bool force) + { + m_forceInteger = force; + } + + bool isAnonymous() const + { + return m_anonymous; + } + void setAnonymous(bool anonymous) + { + m_anonymous = anonymous; + } + +private: + QString m_packageName; + QString m_qualifier; + QString m_targetLangName; + + QString m_lowerBound; + QString m_upperBound; + + QStringList m_rejectedEnums; + QVector m_enumRedirections; + + FlagsTypeEntry *m_flags; + + bool m_extensible; + bool m_forceInteger; + bool m_anonymous; +}; + +class EnumValueTypeEntry : public TypeEntry +{ +public: + EnumValueTypeEntry(const QString& name, const QString& value, const EnumTypeEntry* enclosingEnum, double vr) + : TypeEntry(name, TypeEntry::EnumValue, vr), m_value(value), m_enclosingEnum(enclosingEnum) + { + } + + QString value() const { return m_value; } + const EnumTypeEntry* enclosingEnum() const { return m_enclosingEnum; } +private: + QString m_value; + const EnumTypeEntry* m_enclosingEnum; +}; + +class FlagsTypeEntry : public TypeEntry +{ +public: + FlagsTypeEntry(const QString &name, double vr) : TypeEntry(name, FlagsType, vr), m_enum(0) + { + } + + QString qualifiedTargetLangName() const override; + QString targetLangName() const override + { + return m_targetLangName; + } + QString targetLangApiName() const override; + bool preferredConversion() const override + { + return false; + } + + QString originalName() const + { + return m_originalName; + } + void setOriginalName(const QString &s) + { + m_originalName = s; + } + + QString flagsName() const + { + return m_targetLangName; + } + void setFlagsName(const QString &name) + { + m_targetLangName = name; + } + + bool forceInteger() const + { + return m_enum->forceInteger(); + } + + EnumTypeEntry *originator() const + { + return m_enum; + } + void setOriginator(EnumTypeEntry *e) + { + m_enum = e; + } + + QString targetLangPackage() const override + { + return m_enum->targetLangPackage(); + } + +private: + QString m_originalName; + QString m_targetLangName; + EnumTypeEntry *m_enum; +}; + + +class ComplexTypeEntry : public TypeEntry +{ +public: + enum TypeFlag { + ForceAbstract = 0x1, + DeleteInMainThread = 0x2, + Deprecated = 0x4 + }; + typedef QFlags TypeFlags; + + enum CopyableFlag { + CopyableSet, + NonCopyableSet, + Unknown + }; + + ComplexTypeEntry(const QString &name, Type t, double vr) + : TypeEntry(QString(name).replace(QLatin1String(".*::"), QString()), t, vr), + m_qualifiedCppName(name), + m_qobject(false), + m_polymorphicBase(false), + m_genericClass(false), + m_typeFlags(0), + m_copyableFlag(Unknown), + m_baseContainerType(0) + { + } + + bool isComplex() const + { + return true; + } + + ComplexTypeEntry *copy() const + { + ComplexTypeEntry *centry = new ComplexTypeEntry(name(), type(), version()); + centry->setInclude(include()); + centry->setExtraIncludes(extraIncludes()); + centry->setAddedFunctions(addedFunctions()); + centry->setFunctionModifications(functionModifications()); + centry->setFieldModifications(fieldModifications()); + centry->setQObject(isQObject()); + centry->setDefaultSuperclass(defaultSuperclass()); + centry->setCodeSnips(codeSnips()); + centry->setTargetLangPackage(targetLangPackage()); + centry->setBaseContainerType(baseContainerType()); + centry->setDefaultConstructor(defaultConstructor()); + + return centry; + } + + void setLookupName(const QString &name) + { + m_lookupName = name; + } + + QString lookupName() const override + { + return m_lookupName.isEmpty() ? targetLangName() : m_lookupName; + } + + QString targetLangApiName() const override; + + void setTypeFlags(TypeFlags flags) + { + m_typeFlags = flags; + } + + TypeFlags typeFlags() const + { + return m_typeFlags; + } + + FunctionModificationList functionModifications() const + { + return m_functionMods; + } + void setFunctionModifications(const FunctionModificationList &functionModifications) + { + m_functionMods = functionModifications; + } + void addFunctionModification(const FunctionModification &functionModification) + { + m_functionMods << functionModification; + } + FunctionModificationList functionModifications(const QString &signature) const; + + AddedFunctionList addedFunctions() const + { + return m_addedFunctions; + } + void setAddedFunctions(const AddedFunctionList &addedFunctions) + { + m_addedFunctions = addedFunctions; + } + void addNewFunction(const AddedFunction &addedFunction) + { + m_addedFunctions << addedFunction; + } + + FieldModification fieldModification(const QString &name) const; + void setFieldModifications(const FieldModificationList &mods) + { + m_fieldMods = mods; + } + FieldModificationList fieldModifications() const + { + return m_fieldMods; + } + + QString targetLangPackage() const + { + return m_package; + } + void setTargetLangPackage(const QString &package) + { + m_package = package; + } + + bool isQObject() const + { + return m_qobject; + } + void setQObject(bool qobject) + { + m_qobject = qobject; + } + + QString defaultSuperclass() const + { + return m_defaultSuperclass; + } + void setDefaultSuperclass(const QString &sc) + { + m_defaultSuperclass = sc; + } + + QString qualifiedCppName() const override + { + return m_qualifiedCppName; + } + + + void setIsPolymorphicBase(bool on) + { + m_polymorphicBase = on; + } + bool isPolymorphicBase() const + { + return m_polymorphicBase; + } + + void setPolymorphicIdValue(const QString &value) + { + m_polymorphicIdValue = value; + } + QString polymorphicIdValue() const + { + return m_polymorphicIdValue; + } + + void setHeldType(const QString &value) + { + m_heldTypeValue = value; + } + QString heldTypeValue() const + { + return m_heldTypeValue; + } + + + void setExpensePolicy(const ExpensePolicy &policy) + { + m_expensePolicy = policy; + } + const ExpensePolicy &expensePolicy() const + { + return m_expensePolicy; + } + + QString targetType() const + { + return m_targetType; + } + void setTargetType(const QString &code) + { + m_targetType = code; + } + + QString targetLangName() const override + { + return m_targetLangName.isEmpty() + ? TypeEntry::targetLangName() + : m_targetLangName; + } + void setTargetLangName(const QString &name) + { + m_targetLangName = name; + } + + bool isGenericClass() const + { + return m_genericClass; + } + void setGenericClass(bool isGeneric) + { + m_genericClass = isGeneric; + } + + CopyableFlag copyable() const + { + return m_copyableFlag; + } + void setCopyable(CopyableFlag flag) + { + m_copyableFlag = flag; + } + + QString hashFunction() const + { + return m_hashFunction; + } + void setHashFunction(QString hashFunction) + { + m_hashFunction = hashFunction; + } + + void setBaseContainerType(const ComplexTypeEntry *baseContainer) + { + m_baseContainerType = baseContainer; + } + + const ComplexTypeEntry* baseContainerType() const + { + return m_baseContainerType; + } + + QString defaultConstructor() const; + void setDefaultConstructor(const QString& defaultConstructor); + bool hasDefaultConstructor() const; + +private: + AddedFunctionList m_addedFunctions; + FunctionModificationList m_functionMods; + FieldModificationList m_fieldMods; + QString m_package; + QString m_defaultSuperclass; + QString m_qualifiedCppName; + QString m_targetLangName; + + uint m_qobject : 1; + uint m_polymorphicBase : 1; + uint m_genericClass : 1; + + QString m_polymorphicIdValue; + QString m_heldTypeValue; + QString m_lookupName; + QString m_targetType; + ExpensePolicy m_expensePolicy; + TypeFlags m_typeFlags; + CopyableFlag m_copyableFlag; + QString m_hashFunction; + + const ComplexTypeEntry* m_baseContainerType; +}; + +class ContainerTypeEntry : public ComplexTypeEntry +{ + Q_GADGET +public: + enum Type { + NoContainer, + ListContainer, + StringListContainer, + LinkedListContainer, + VectorContainer, + StackContainer, + QueueContainer, + SetContainer, + MapContainer, + MultiMapContainer, + HashContainer, + MultiHashContainer, + PairContainer, + }; + Q_ENUM(Type) + + ContainerTypeEntry(const QString &name, Type type, double vr) + : ComplexTypeEntry(name, ContainerType, vr), m_type(type) + { + setCodeGeneration(GenerateForSubclass); + } + + Type type() const + { + return m_type; + } + + QString typeName() const; + QString targetLangName() const; + QString targetLangPackage() const; + QString qualifiedCppName() const; + + static Type containerTypeFromString(QString typeName) + { + static QHash 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); + } + +private: + Type m_type; +}; + +class SmartPointerTypeEntry : public ComplexTypeEntry +{ +public: + SmartPointerTypeEntry(const QString &name, + const QString &getterName, + const QString &smartPointerType, + const QString &refCountMethodName, + double vr) + : ComplexTypeEntry(name, SmartPointerType, vr), + m_getterName(getterName), + m_smartPointerType(smartPointerType), + m_refCountMethodName(refCountMethodName) + { + } + + QString getter() const + { + return m_getterName; + } + + QString refCountMethodName() const + { + return m_refCountMethodName; + } + +private: + QString m_getterName; + QString m_smartPointerType; + QString m_refCountMethodName; +}; + +class NamespaceTypeEntry : public ComplexTypeEntry +{ +public: + NamespaceTypeEntry(const QString &name, double vr) : ComplexTypeEntry(name, NamespaceType, vr) { } +}; + + +class ValueTypeEntry : public ComplexTypeEntry +{ +public: + ValueTypeEntry(const QString &name, double vr) : ComplexTypeEntry(name, BasicValueType, vr) { } + + bool isValue() const override + { + return true; + } + + bool isNativeIdBased() const override + { + return true; + } + +protected: + ValueTypeEntry(const QString &name, Type t, double vr) : ComplexTypeEntry(name, t, vr) { } +}; + + +class StringTypeEntry : public ValueTypeEntry +{ +public: + StringTypeEntry(const QString &name, double vr) + : ValueTypeEntry(name, StringType, vr) + { + setCodeGeneration(GenerateNothing); + } + + QString targetLangApiName() const override; + QString targetLangName() const override; + QString targetLangPackage() const override; + + bool isNativeIdBased() const override + { + return false; + } +}; + +class CharTypeEntry : public ValueTypeEntry +{ +public: + CharTypeEntry(const QString &name, double vr) : ValueTypeEntry(name, CharType, vr) + { + setCodeGeneration(GenerateNothing); + } + + QString targetLangApiName() const override; + QString targetLangName() const override; + QString targetLangPackage() const override + { + return QString(); + } + + bool isNativeIdBased() const override + { + return false; + } +}; + +class VariantTypeEntry: public ValueTypeEntry +{ +public: + VariantTypeEntry(const QString &name, double vr) : ValueTypeEntry(name, VariantType, vr) { } + + QString targetLangApiName() const override; + QString targetLangName() const override; + QString targetLangPackage() const override; + + bool isNativeIdBased() const override + { + return false; + } +}; + + +class InterfaceTypeEntry : public ComplexTypeEntry +{ +public: + InterfaceTypeEntry(const QString &name, double vr) + : ComplexTypeEntry(name, InterfaceType, vr) {} + + static QString interfaceName(const QString &name) + { + return name + QLatin1String("Interface"); + } + + ObjectTypeEntry *origin() const + { + return m_origin; + } + void setOrigin(ObjectTypeEntry *origin) + { + m_origin = origin; + } + + bool isNativeIdBased() const override + { + return true; + } + QString qualifiedCppName() const override + { + const int len = ComplexTypeEntry::qualifiedCppName().length() - interfaceName(QString()).length(); + return ComplexTypeEntry::qualifiedCppName().left(len); + } + +private: + ObjectTypeEntry *m_origin; +}; + + +class FunctionTypeEntry : public TypeEntry +{ +public: + FunctionTypeEntry(const QString& name, const QString& signature, double vr) + : TypeEntry(name, FunctionType, vr) + { + addSignature(signature); + } + void addSignature(const QString& signature) + { + m_signatures << signature; + } + + QStringList signatures() const + { + return m_signatures; + } + + bool hasSignature(const QString& signature) const + { + return m_signatures.contains(signature); + } +private: + QStringList m_signatures; +}; + +class ObjectTypeEntry : public ComplexTypeEntry +{ +public: + ObjectTypeEntry(const QString &name, double vr) + : ComplexTypeEntry(name, ObjectType, vr), m_interface(0) {} + + InterfaceTypeEntry *designatedInterface() const + { + return m_interface; + } + void setDesignatedInterface(InterfaceTypeEntry *entry) + { + m_interface = entry; + } + + bool isNativeIdBased() const override + { + return true; + } + +private: + InterfaceTypeEntry *m_interface; +}; + +struct TypeRejection +{ + enum MatchType + { + ExcludeClass, // Match className only + Function, // Match className and function name + Field, // Match className and field name + Enum, // Match className and enum name + ArgumentType, // Match className and argument type + ReturnType // Match className and return type + }; + + QRegularExpression className; + QRegularExpression pattern; + MatchType matchType; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const TypeRejection &r); +#endif + +QString fixCppTypeName(const QString &name); + +class CustomConversion +{ +public: + CustomConversion(TypeEntry* ownerType); + ~CustomConversion(); + + const TypeEntry* ownerType() const; + QString nativeToTargetConversion() const; + void setNativeToTargetConversion(const QString& nativeToTargetConversion); + + class TargetToNativeConversion + { + public: + TargetToNativeConversion(const QString& sourceTypeName, + const QString& sourceTypeCheck, + const QString& conversion = QString()); + ~TargetToNativeConversion(); + + const TypeEntry* sourceType() const; + void setSourceType(const TypeEntry* sourceType); + bool isCustomType() const; + QString sourceTypeName() const; + QString sourceTypeCheck() const; + QString conversion() const; + void setConversion(const QString& conversion); + private: + struct TargetToNativeConversionPrivate; + TargetToNativeConversionPrivate* m_d; + }; + + /** + * Returns true if the target to C++ custom conversions should + * replace the original existing ones, and false if the custom + * conversions should be added to the original. + */ + bool replaceOriginalTargetToNativeConversions() const; + void setReplaceOriginalTargetToNativeConversions(bool replaceOriginalTargetToNativeConversions); + + typedef QVector TargetToNativeConversions; + bool hasTargetToNativeConversions() const; + TargetToNativeConversions& targetToNativeConversions(); + const TargetToNativeConversions& targetToNativeConversions() const; + void addTargetToNativeConversion(const QString& sourceTypeName, + const QString& sourceTypeCheck, + const QString& conversion = QString()); +private: + struct CustomConversionPrivate; + CustomConversionPrivate* m_d; +}; + +#endif // TYPESYSTEM_H diff --git a/sources/shiboken2/ApiExtractor/typesystem_enums.h b/sources/shiboken2/ApiExtractor/typesystem_enums.h new file mode 100644 index 000000000..2d67d7cc5 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typesystem_enums.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 TYPESYSTEM_ENUMS_H +#define TYPESYSTEM_ENUMS_H + +namespace TypeSystem +{ +enum Language { + NoLanguage = 0x0000, + TargetLangCode = 0x0001, + NativeCode = 0x0002, + ShellCode = 0x0004, + ShellDeclaration = 0x0008, + PackageInitializer = 0x0010, + DestructorFunction = 0x0020, + Constructors = 0x0040, + Interface = 0x0080, + + // masks + All = TargetLangCode + | NativeCode + | ShellCode + | ShellDeclaration + | PackageInitializer + | Constructors + | Interface + | DestructorFunction, + + TargetLangAndNativeCode = TargetLangCode | NativeCode +}; + +enum Ownership { + InvalidOwnership, + DefaultOwnership, + TargetLangOwnership, + CppOwnership +}; + +enum CodeSnipPosition { + CodeSnipPositionBeginning, + CodeSnipPositionEnd, + CodeSnipPositionAfterThis, + // QtScript + CodeSnipPositionDeclaration, + CodeSnipPositionPrototypeInitialization, + CodeSnipPositionConstructorInitialization, + CodeSnipPositionConstructor, + CodeSnipPositionAny +}; + +enum DocModificationMode { + DocModificationAppend, + DocModificationPrepend, + DocModificationReplace, + DocModificationXPathReplace +}; + +} // namespace TypeSystem + +#endif // TYPESYSTEM_ENUMS_H diff --git a/sources/shiboken2/ApiExtractor/typesystem_p.h b/sources/shiboken2/ApiExtractor/typesystem_p.h new file mode 100644 index 000000000..f2105a631 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typesystem_p.h @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 TYPESYSTEM_P_H +#define TYPESYSTEM_P_H + +#include +#include "typesystem.h" + +QT_FORWARD_DECLARE_CLASS(QXmlStreamAttributes) +QT_FORWARD_DECLARE_CLASS(QXmlStreamReader) + +class TypeDatabase; +class StackElement +{ + public: + enum ElementType { + None = 0x0, + + // Type tags (0x1, ... , 0xff) + ObjectTypeEntry = 0x1, + ValueTypeEntry = 0x2, + InterfaceTypeEntry = 0x3, + NamespaceTypeEntry = 0x4, + ComplexTypeEntryMask = 0x7, + + // Non-complex type tags (0x8, 0x9, ... , 0xf) + PrimitiveTypeEntry = 0x8, + EnumTypeEntry = 0x9, + ContainerTypeEntry = 0xa, + FunctionTypeEntry = 0xb, + CustomTypeEntry = 0xc, + SmartPointerTypeEntry = 0xd, + TypeEntryMask = 0xf, + + // Documentation tags + InjectDocumentation = 0x10, + ModifyDocumentation = 0x20, + DocumentationMask = 0xf0, + + // Simple tags (0x100, 0x200, ... , 0xf00) + ExtraIncludes = 0x0100, + Include = 0x0200, + ModifyFunction = 0x0300, + ModifyField = 0x0400, + Root = 0x0500, + CustomMetaConstructor = 0x0600, + CustomMetaDestructor = 0x0700, + ArgumentMap = 0x0800, + SuppressedWarning = 0x0900, + Rejection = 0x0a00, + LoadTypesystem = 0x0b00, + RejectEnumValue = 0x0c00, + Template = 0x0d00, + TemplateInstanceEnum = 0x0e00, + Replace = 0x0f00, + AddFunction = 0x1000, + NativeToTarget = 0x1100, + TargetToNative = 0x1200, + AddConversion = 0x1300, + SimpleMask = 0x3f00, + + // Code snip tags (0x1000, 0x2000, ... , 0xf000) + InjectCode = 0x4000, + InjectCodeInFunction = 0x8000, + CodeSnipMask = 0xc000, + + // Function modifier tags (0x010000, 0x020000, ... , 0xf00000) + Access = 0x010000, + Removal = 0x020000, + Rename = 0x040000, + ModifyArgument = 0x080000, + Thread = 0x100000, + FunctionModifiers = 0xff0000, + + // Argument modifier tags (0x01000000 ... 0xf0000000) + ConversionRule = 0x01000000, + ReplaceType = 0x02000000, + ReplaceDefaultExpression = 0x04000000, + RemoveArgument = 0x08000000, + DefineOwnership = 0x10000000, + RemoveDefaultExpression = 0x20000000, + NoNullPointers = 0x40000000, + ReferenceCount = 0x80000000, + ParentOwner = 0x90000000, + ArgumentModifiers = 0xff000000 + }; + + StackElement(StackElement *p) : entry(0), type(None), parent(p) { } + + TypeEntry* entry; + ElementType type; + StackElement *parent; + + union { + TemplateInstance* templateInstance; + TemplateEntry* templateEntry; + CustomFunction* customFunction; + } value; +}; + +struct StackElementContext +{ + CodeSnipList codeSnips; + AddedFunctionList addedFunctions; + FunctionModificationList functionMods; + FieldModificationList fieldMods; + DocModificationList docModifications; +}; + +class Handler +{ +public: + Handler(TypeDatabase* database, bool generate); + + bool parse(QXmlStreamReader &reader); + +private: + bool startElement(const QStringRef& localName, const QXmlStreamAttributes& atts); + bool handleSmartPointerEntry(StackElement *element, + QHash &attributes, + const QString &name, + double since); + bool endElement(const QStringRef& localName); + template // QString/QStringRef + bool characters(const String &ch); + void fetchAttributeValues(const QString &name, const QXmlStreamAttributes &atts, + QHash *acceptedAttributes); + + bool importFileElement(const QXmlStreamAttributes &atts); + bool convertBoolean(const QString &, const QString &, bool); + void addFlags(const QString &name, QString flagName, + const QHash &attributes, double since); + + TypeDatabase* m_database; + StackElement* m_current; + StackElement* m_currentDroppedEntry; + int m_currentDroppedEntryDepth; + int m_ignoreDepth; + QString m_defaultPackage; + QString m_defaultSuperclass; + QString m_error; + TypeEntry::CodeGeneration m_generate; + + EnumTypeEntry* m_currentEnum; + QStack m_contextStack; + + QHash tagNames; + QString m_currentSignature; +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/typesystem_typedefs.h b/sources/shiboken2/ApiExtractor/typesystem_typedefs.h new file mode 100644 index 000000000..4f29deced --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typesystem_typedefs.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 TYPESYSTEM_TYPEDEFS_H +#define TYPESYSTEM_TYPEDEFS_H + +#include +#include +#include + +class CodeSnip; +class DocModification; + +struct AddedFunction; +struct FieldModification; +struct FunctionModification; + +typedef QVector AddedFunctionList; +typedef QVector CodeSnipList; +typedef QVector DocModificationList; +typedef QVector FieldModificationList; +typedef QVector FunctionModificationList; + +#endif // TYPESYSTEM_TYPEDEFS_H diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt new file mode 100644 index 000000000..ddba62df8 --- /dev/null +++ b/sources/shiboken2/CMakeLists.txt @@ -0,0 +1,285 @@ +Include(icecc.cmake) +project(shiboken2) + +cmake_minimum_required(VERSION 3.0) +cmake_policy(VERSION 3.0) + +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules/ + ${CMAKE_MODULE_PATH}) + +find_package(Qt5 REQUIRED COMPONENTS Core Xml XmlPatterns) + +add_definitions(${Qt5Core_DEFINITIONS}) + +set(shiboken_MAJOR_VERSION "2") +set(shiboken_MINOR_VERSION "0") +set(shiboken_MICRO_VERSION "0") +set(shiboken2_VERSION "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}.${shiboken_MICRO_VERSION}") + +option(BUILD_TESTS "Build tests." TRUE) +option(USE_PYTHON_VERSION "Use specific python version to build shiboken2." "") + +if (USE_PYTHON_VERSION) + find_package(PythonInterp ${USE_PYTHON_VERSION} REQUIRED) + find_package(PythonLibs ${USE_PYTHON_VERSION} REQUIRED) +else() + find_package(PythonInterp 2.6) + find_package(PythonLibs 2.6) +endif() + +set(CLANG_DIR "") +set(CLANG_DIR_SOURCE "") + +if (DEFINED ENV{LLVM_INSTALL_DIR}) + set(CLANG_DIR $ENV{LLVM_INSTALL_DIR}) + set(CLANG_DIR_SOURCE "LLVM_INSTALL_DIR") +elseif (DEFINED ENV{CLANG_INSTALL_DIR}) + set(CLANG_DIR $ENV{CLANG_INSTALL_DIR}) + set(CLANG_DIR_SOURCE "CLANG_INSTALL_DIR") +else () + EXEC_PROGRAM("llvm-config" ARGS "--prefix" OUTPUT_VARIABLE CLANG_DIR) + set(CLANG_DIR_SOURCE "llvm-config") + if (NOT "${CLANG_DIR}" STREQUAL "") + EXEC_PROGRAM("llvm-config" ARGS "--version" OUTPUT_VARIABLE CLANG_VERSION) + if (CLANG_VERSION VERSION_LESS 3.9) + message(FATAL_ERROR "LLVM version 3.9 is required (llvm-config detected ${CLANG_VERSION} at ${CLANG_DIR}).") + endif() + endif() +endif() + +if ("${CLANG_DIR}" STREQUAL "") + message(FATAL_ERROR "Unable to detect CLANG location by checking LLVM_INSTALL_DIR, CLANG_INSTALL_DIR or running llvm-config.") +elseif (NOT IS_DIRECTORY ${CLANG_DIR}) + message(FATAL_ERROR "${CLANG_DIR} detected by ${CLANG_DIR_SOURCE} does not exist.") +endif() + +set(CLANG_LIB_NAME "clang") +if(MSVC) + set(CLANG_LIB_NAME "libclang") +endif() + +find_library(CLANG_LIBRARY ${CLANG_LIB_NAME} HINTS ${CLANG_DIR}/lib) +if (NOT EXISTS ${CLANG_LIBRARY}) + message(FATAL_ERROR "Unable to find Clang library ${CLANG_LIB_NAME} in ${CLANG_DIR}.") +endif() + +message(STATUS "CLANG: ${CLANG_DIR}, ${CLANG_LIBRARY} detected by ${CLANG_DIR_SOURCE}") + +set(CLANG_EXTRA_INCLUDES ${CLANG_DIR}/include) +set(CLANG_EXTRA_LIBRARIES ${CLANG_LIBRARY}) + +## For debugging the PYTHON* variables +message("PYTHONLIBS_FOUND: " ${PYTHONLIBS_FOUND}) +message("PYTHON_LIBRARIES: " ${PYTHON_LIBRARIES}) +message("PYTHON_INCLUDE_DIRS: " ${PYTHON_INCLUDE_DIRS}) +message("PYTHON_DEBUG_LIBRARIES: " ${PYTHON_DEBUG_LIBRARIES}) +message("PYTHONINTERP_FOUND: " ${PYTHONINTERP_FOUND}) +message("PYTHON_EXECUTABLE: " ${PYTHON_EXECUTABLE}) +message("PYTHON_VERSION: " ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.${PYTHON_VERSION_PATCH}) + +# Queries the python sysconfig for the abi flags which need to be inserted into extension suffixes. +# Only present starting with Python 3.2. +# Corresponding configure switches to single letter flags: +# --with-pymalloc -> m +# --with-pydebug -> d +# --with-unicode -> u (rare) +macro(get_python3_abi_flags) + if (NOT PYTHON_ABI_FLAGS) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "if True: + import sysconfig + print(sysconfig.get_config_var('abiflags')) + " + OUTPUT_VARIABLE PYTHON_ABI_FLAGS + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() + message("PYTHON_ABI_FLAGS: " ${PYTHON_ABI_FLAGS}) +endmacro() + +macro(get_python_multi_arch_suffix) + # TODO: This part needs testing to check if it is available on Windows. + # It is present on macOS, but is not used yet. + # Result is something like 'x86_64-linux-gnu'. + if (NOT PYTHON_MULTIARCH_SUFFIX) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "if True: + import sysconfig + print(sysconfig.get_config_var('MULTIARCH')) + " + OUTPUT_VARIABLE PYTHON_MULTIARCH_SUFFIX + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() + message("PYTHON_MULTIARCH_SUFFIX: " ${PYTHON_MULTIARCH_SUFFIX}) +endmacro() + +macro(get_python2_release_suffix) + # Result of imp.get_suffixes() is something like: + # [('_d.so', 'rb', 3), ('module_d.so', 'rb', 3), ('.x86_64-linux-gnu_d.so', 'rb', 3)] + # or alternatively the same but withut the '_d' part. + # The list comprehension is used to choose which suffix to include in library names. + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "if True: + import imp + print('_d' if any([tup[0].endswith('_d.so') for tup in imp.get_suffixes()]) else '') + " + OUTPUT_VARIABLE PYTHON_MODULE_RELEASE_SUFFIX + OUTPUT_STRIP_TRAILING_WHITESPACE) + message("PYTHON_MODULE_RELEASE_SUFFIX: " ${PYTHON_MODULE_RELEASE_SUFFIX}) +endmacro() + +# Note the quirk that UNIX includes Apple! +if (UNIX AND NOT APPLE) + if (NOT PYTHON_EXTENSION_SUFFIX) + get_python_multi_arch_suffix() + # The suffix added to .so libraries should be differenet between Python 2 and 3. + # The position of the multiarch suffix is different, and the way the debug flag is set + # computed differently. + # In Python 2 there is no standard way to query if the python interpeter was built in debug or + # release build (sysconfig.get_config_var('Py_Debug') can have a different value than you would + # expect if you do a custom Python build). The solution is to query for the import + # suffixes and check if _d is present there. It is present on Linux distribution + # packages of Python, but not in custom built Python builds, because the distros apply their + # custom patches too append the '_d's. + # In Python 3 (starting with 3.2) there is a standard way to check if '_d' needs to be added, + # as well as any other letters, by querying the abiflags sysconfig variable. + if (PYTHON_VERSION_MAJOR EQUAL 2) + get_python2_release_suffix() + if(PYTHON_MULTIARCH_SUFFIX) + set(PYTHON_EXTENSION_SUFFIX ".${PYTHON_MULTIARCH_SUFFIX}") + endif() + set(PYTHON_EXTENSION_SUFFIX "${PYTHON_EXTENSION_SUFFIX}${PYTHON_MODULE_RELEASE_SUFFIX}") + elseif (PYTHON_VERSION_MAJOR EQUAL 3) + get_python3_abi_flags() + set(PYTHON_EXTENSION_SUFFIX ".cpython-${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}${PYTHON_ABI_FLAGS}") + if(PYTHON_MULTIARCH_SUFFIX) + set(PYTHON_EXTENSION_SUFFIX "${PYTHON_EXTENSION_SUFFIX}-${PYTHON_MULTIARCH_SUFFIX}") + endif() + else() + message(FATAL_ERROR "Unsupported PYTHON_VERSION=${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.${PYTHON_VERSION_PATCH}!") + endif() + endif() + message(STATUS "PYTHON_EXTENSION_SUFFIX: ${PYTHON_EXTENSION_SUFFIX}") +endif () + +if (NOT PYTHON_SITE_PACKAGES) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "if True: + from distutils import sysconfig + from os.path import sep + print(sysconfig.get_python_lib(1, 0, prefix='${CMAKE_INSTALL_PREFIX}').replace(sep, '/')) + " + OUTPUT_VARIABLE PYTHON_SITE_PACKAGES + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT PYTHON_SITE_PACKAGES) + message(FATAL_ERROR "Could not detect Python module installation directory.") + elseif (APPLE) + message(STATUS "!!! The generated bindings will be installed on ${PYTHON_SITE_PACKAGES}, is it right!?") + endif() +endif() + +if(MSVC) + # Qt5: this flag has changed from /Zc:wchar_t- in Qt4.X + set(CMAKE_CXX_FLAGS "/Zc:wchar_t /GR /EHsc /DWIN32 /D_WINDOWS /D_SCL_SECURE_NO_WARNINGS") +else() + if(CMAKE_HOST_UNIX AND NOT CYGWIN) + add_definitions(-fPIC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fvisibility=hidden -Wno-strict-aliasing") + endif() + set(CMAKE_CXX_FLAGS_DEBUG "-g") + option(ENABLE_GCC_OPTIMIZATION "Enable specific GCC flags to optimization library size and performance. Only available on Release Mode" 0) + if(ENABLE_GCC_OPTIMIZATION) + set(CMAKE_BUILD_TYPE Release) + set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -Os -Wl,-O1") + if(NOT CMAKE_HOST_APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--hash-style=gnu") + endif() + endif() +endif() + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D QT_NO_CAST_FROM_ASCII -D QT_NO_CAST_TO_ASCII") + +set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) +set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE) + +if (WIN32) + set(PATH_SEP "\;") +else() + set(PATH_SEP ":") +endif() + +if(CMAKE_HOST_APPLE) + set(OSX_USE_LIBCPP "OFF" CACHE BOOL "Explicitly link the libc++ standard library (useful for osx deployment targets lower than 10.9.") + if(OSX_USE_LIBCPP) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + endif() +endif() + +add_subdirectory(ApiExtractor) + +set(generator_plugin_DIR ${LIB_INSTALL_DIR}/generatorrunner${generator_SUFFIX}) + +# uninstall target +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) +add_custom_target(uninstall "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") + +set(SHIBOKEN_BUILD_TYPE "Release") +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + if(NOT PYTHON_DEBUG_LIBRARIES) + message(WARNING "Python debug shared library not found; assuming python was built with shared library support disabled.") + endif() + if(NOT PYTHON_WITH_DEBUG) + message(WARNING "Compiling shiboken2 with debug enabled, but the python executable was not compiled with debug support.") + else() + add_definitions("-DPy_DEBUG") + set(SBK_ADD_PY_DEBUG_DEFINITION "add_definitions(\"-DPy_DEBUG\")") + set(SBK_PKG_CONFIG_PY_DEBUG_DEFINITION " -DPy_DEBUG") + endif() + set(SBK_PYTHON_LIBRARIES ${PYTHON_DEBUG_LIBRARIES}) + set(SHIBOKEN_BUILD_TYPE "Debug") +else() + set(SBK_PYTHON_LIBRARIES ${PYTHON_LIBRARIES}) + add_definitions("-DNDEBUG") +endif() +if(APPLE) + set(SBK_PYTHON_LIBRARIES "-undefined dynamic_lookup") +endif() + +if(CMAKE_VERSION VERSION_LESS 2.8) + set(SBK_PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_PATH}) +else() + set(SBK_PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIRS}) +endif() + +add_subdirectory(libshiboken) +add_subdirectory(doc) + +# deps found, compile the generator. +if (Qt5Core_FOUND AND PYTHONINTERP_FOUND) + add_subdirectory(generator) + add_subdirectory(shibokenmodule) + + if (BUILD_TESTS) + enable_testing() + add_subdirectory(tests) + endif() +else() + message(WARNING "Some dependencies were not found, shiboken2 generator compilation disabled!") +endif() + +add_subdirectory(data) + +# dist target +set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${shiboken2_VERSION}) +add_custom_target(dist + COMMAND mkdir -p "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}" && + git log > "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}/ChangeLog" && + git archive --prefix=${ARCHIVE_NAME}/ HEAD --format=tar --output="${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar" && + tar -C "${CMAKE_BINARY_DIR}" --owner=root --group=root -r "${ARCHIVE_NAME}/ChangeLog" -f "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar" && + bzip2 -f9 "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar" && + echo "Source package created at ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.bz2." + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + + diff --git a/sources/shiboken2/COPYING b/sources/shiboken2/COPYING new file mode 100644 index 000000000..4ccd71466 --- /dev/null +++ b/sources/shiboken2/COPYING @@ -0,0 +1,342 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +------------------------------------------------------------------------- diff --git a/sources/shiboken2/COPYING.libsample b/sources/shiboken2/COPYING.libsample new file mode 100644 index 000000000..9315102f7 --- /dev/null +++ b/sources/shiboken2/COPYING.libsample @@ -0,0 +1,501 @@ +GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + diff --git a/sources/shiboken2/COPYING.libshiboken b/sources/shiboken2/COPYING.libshiboken new file mode 100644 index 000000000..9315102f7 --- /dev/null +++ b/sources/shiboken2/COPYING.libshiboken @@ -0,0 +1,501 @@ +GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + diff --git a/sources/shiboken2/Doxyfile b/sources/shiboken2/Doxyfile new file mode 100644 index 000000000..9be56a0e4 --- /dev/null +++ b/sources/shiboken2/Doxyfile @@ -0,0 +1,311 @@ +# Doxyfile 1.5.7.1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "Generator Runner" +PROJECT_NUMBER = 0.1 +OUTPUT_DIRECTORY = doc +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = /tmp/src/generatorrunner/ +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +SYMBOL_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = /tmp/src/generatorrunner +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.PY \ + *.F90 \ + *.F \ + *.VHD \ + *.VHDL +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 3 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +HTML_DYNAMIC_SECTIONS = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHG_LOCATION = +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NONE +TREEVIEW_WIDTH = 250 +FORMULA_FONTSIZE = 10 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = ../libgenrunner/libgenrunner.tag=../libgenrunner +GENERATE_TAGFILE = generatorrunner.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +DOT_FONTNAME = FreeSans +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = NO +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = NO +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/sources/shiboken2/LICENSE.GPLv3 b/sources/shiboken2/LICENSE.GPLv3 new file mode 100644 index 000000000..71c4ad49c --- /dev/null +++ b/sources/shiboken2/LICENSE.GPLv3 @@ -0,0 +1,686 @@ + GNU GENERAL PUBLIC LICENSE + + The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd. + Contact: http://www.qt.io/licensing/ + + You may use, distribute and copy the Qt Toolkit under the terms of + GNU Lesser General Public License version 3. That license references + the General Public License version 3, that is displayed below. Other + portions of the Qt Toolkit may be licensed directly under this license. + +------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/sources/shiboken2/LICENSE.LGPLv21 b/sources/shiboken2/LICENSE.LGPLv21 new file mode 100644 index 000000000..15a208b48 --- /dev/null +++ b/sources/shiboken2/LICENSE.LGPLv21 @@ -0,0 +1,514 @@ + GNU LESSER GENERAL PUBLIC LICENSE + + The Qt Toolkit is Copyright (C) 2016 The Qt Company Ltd. + Contact: http://www.qt.io/licensing/ + + You may use, distribute and copy the Qt Toolkit under the terms of + GNU Lesser General Public License version 2.1, which is displayed below. + +------------------------------------------------------------------------- + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/sources/shiboken2/LICENSE.LGPLv3 b/sources/shiboken2/LICENSE.LGPLv3 new file mode 100644 index 000000000..849103ad9 --- /dev/null +++ b/sources/shiboken2/LICENSE.LGPLv3 @@ -0,0 +1,175 @@ + GNU LESSER GENERAL PUBLIC LICENSE + + The Qt Toolkit is Copyright (C) 2016 The Qt Company Ltd. + Contact: http://www.qt.io/licensing/ + + You may use, distribute and copy the Qt Toolkit under the terms of + GNU Lesser General Public License version 3, which is displayed below. + This license makes reference to the version 3 of the GNU General + Public License, which you can find in the LICENSE.GPLv3 file. + +------------------------------------------------------------------------- + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright © 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies of this +licensedocument, but changing it is not allowed. + +This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + +0. Additional Definitions. + + As used herein, “this License” refers to version 3 of the GNU Lesser +General Public License, and the “GNU GPL” refers to version 3 of the +GNU General Public License. + + “The Library” refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An “Application” is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A “Combined Work” is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the “Linked +Version”. + + The “Minimal Corresponding Source” for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The “Corresponding Application Code” for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + +1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + +2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort + to ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + +3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this + license document. + +4. Combined Works. + + You may convey a Combined Work under terms of your choice that, taken +together, effectively do not restrict modification of the portions of +the Library contained in the Combined Work and reverse engineering for +debugging such modifications, if you also do each of the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this + license document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of + this License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with + the Library. A suitable mechanism is one that (a) uses at run + time a copy of the Library already present on the user's + computer system, and (b) will operate properly with a modified + version of the Library that is interface-compatible with the + Linked Version. + + e) Provide Installation Information, but only if you would + otherwise be required to provide such information under section 6 + of the GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the Application + with a modified version of the Linked Version. (If you use option + 4d0, the Installation Information must accompany the Minimal + Corresponding Source and Corresponding Application Code. If you + use option 4d1, you must provide the Installation Information in + the manner specified by section 6 of the GNU GPL for conveying + Corresponding Source.) + +5. Combined Libraries. + + You may place library facilities that are a work based on the Library +side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities, conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of + it is a work based on the Library, and explaining where to find + the accompanying uncombined form of the same work. + +6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +as you received it specifies that a certain numbered version of the +GNU Lesser General Public License “or any later version” applies to +it, you have the option of following the terms and conditions either +of that published version or of any later version published by the +Free Software Foundation. If the Library as you received it does not +specify a version number of the GNU Lesser General Public License, +you may choose any version of the GNU Lesser General Public License +ever published by the Free Software Foundation. + +If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the Library. + diff --git a/sources/shiboken2/LICENSE.PREVIEW.COMMERCIAL b/sources/shiboken2/LICENSE.PREVIEW.COMMERCIAL new file mode 100644 index 000000000..0f96e738c --- /dev/null +++ b/sources/shiboken2/LICENSE.PREVIEW.COMMERCIAL @@ -0,0 +1,630 @@ +TECHNOLOGY PREVIEW LICENSE AGREEMENT + +For individuals and/or legal entities resident in the Americas (North +America, Central America and South America), the applicable licensing +terms are specified under the heading "Technology Preview License +Agreement: The Americas". + +For individuals and/or legal entities not resident in The Americas, the +applicable licensing terms are specified under the heading "Technology +Preview License Agreement: Rest of the World". + + +TECHNOLOGY PREVIEW LICENSE AGREEMENT: The Americas +Agreement version 2.4 + +This Technology Preview License Agreement ("Agreement")is a legal agreement +between The Qt Company USA, Inc. ("The Qt Company"), with its registered +office at 2350 Mission College Blvd., Suite 1020, Santa Clara, California +95054, U.S.A. and you (either an individual or a legal entity) ("Licensee") +for the Licensed Software (as defined below). + +1. DEFINITIONS + +"Affiliate" of a Party shall mean an entity (i) which is directly or +indirectly controlling such Party; (ii) which is under the same direct +or indirect ownership or control as such Party; or (iii) which is +directly or indirectly owned or controlled by such Party. For these +purposes, an entity shall be treated as being controlled by another if +that other entity has fifty percent (50 %) or more of the votes in such +entity, is able to direct its affairs and/or to control the composition +of its board of directors or equivalent body. + +"Applications" shall mean Licensee's software products created using the +Licensed Software which may include portions of the Licensed Software. + +"Term" shall mean the period of time six (6) months from the later of +(a) the Effective Date; or (b) the date the Licensed Software was +initially delivered to Licensee by The Qt Company. If no specific Effective +Date is set forth in the Agreement, the Effective Date shall be deemed to be +the date the Licensed Software was initially delivered to Licensee. + +"Licensed Software" shall mean the computer software, "online" or +electronic documentation, associated media and printed materials, +including the source code, example programs and the documentation +delivered by The Qt Company to Licensee in conjunction with this Agreement. + +"Party" or "Parties" shall mean Licensee and/or The Qt Company. + + +2. OWNERSHIP + +The Licensed Software is protected by copyright laws and international +copyright treaties, as well as other intellectual property laws and +treaties. The Licensed Software is licensed, not sold. + +If Licensee provides any findings, proposals, suggestions or other +feedback ("Feedback") to The Qt Company regarding the Licensed Software, +The Qt Company shall own all right, title and interest including the +intellectual property rights in and to such Feedback, excluding however any +existing patent rights of Licensee. To the extent Licensee owns or controls +any patents for such Feedback Licensee hereby grants to The Qt Company and its +Affiliates, a worldwide, perpetual, non-transferable, sublicensable, +royalty-free license to (i) use, copy and modify Feedback and to create +derivative works thereof, (ii) to make (and have made), use, import, +sell, offer for sale, lease, dispose, offer for disposal or otherwise +exploit any products or services of The Qt Company containing Feedback, and +(iii) sublicense all the foregoing rights to third party licensees and +customers of The Qt Company and/or its Affiliates. + + +3. VALIDITY OF THE AGREEMENT + +By installing, copying, or otherwise using the Licensed Software, +Licensee agrees to be bound by the terms of this Agreement. If Licensee +does not agree to the terms of this Agreement, Licensee may not install, +copy, or otherwise use the Licensed Software. Upon Licensee's acceptance +of the terms and conditions of this Agreement, The Qt Company grants Licensee +the right to use the Licensed Software in the manner provided below. + + +4. LICENSES + +4.1. Using and Copying + +The Qt Company grants to Licensee a non-exclusive, non-transferable, +time-limited license to use and copy the Licensed Software for sole purpose +of designing, developing and testing Applications, and evaluating and the +Licensed Software during the Term. + +Licensee may install copies of the Licensed Software on an unlimited +number of computers provided that (a) if an individual, only such +individual; or (b) if a legal entity only its employees; use the +Licensed Software for the authorized purposes. + +4.2 No Distribution or Modifications + +Licensee may not disclose, modify, sell, market, commercialise, +distribute, loan, rent, lease, or license the Licensed Software or any +copy of it or use the Licensed Software for any purpose that is not +expressly granted in this Section 4. Licensee may not alter or remove +any details of ownership, copyright, trademark or other property right +connected with the Licensed Software. Licensee may not distribute any +software statically or dynamically linked with the Licensed Software. + +4.3 No Technical Support + +The Qt Company has no obligation to furnish Licensee with any technical +support whatsoever. Any such support is subject to separate agreement between +the Parties. + + +5. PRE-RELEASE CODE +The Licensed Software contains pre-release code that is not at the level +of performance and compatibility of a final, generally available, +product offering. The Licensed Software may not operate correctly and +may be substantially modified prior to the first commercial product +release, if any. The Qt Company is not obligated to make this or any later +version of the Licensed Software commercially available. The License +Software is "Not for Commercial Use" and may only be used for the +purposes described in Section 4. The Licensed Software may not be used +in a live operating environment where it may be relied upon to perform +in the same manner as a commercially released product or with data that +has not been sufficiently backed up. + +6. THIRD PARTY SOFTWARE + +The Licensed Software may provide links to third party libraries or code +(collectively "Third Party Software") to implement various functions. +Third Party Software does not comprise part of the Licensed Software. In +some cases, access to Third Party Software may be included along with +the Licensed Software delivery as a convenience for development and +testing only. Such source code and libraries may be listed in the +".../src/3rdparty" source tree delivered with the Licensed Software or +documented in the Licensed Software where the Third Party Software is +used, as may be amended from time to time, do not comprise the Licensed +Software. Licensee acknowledges (1) that some part of Third Party +Software may require additional licensing of copyright and patents from +the owners of such, and (2) that distribution of any of the Licensed +Software referencing any portion of a Third Party Software may require +appropriate licensing from such third parties. + + +7. LIMITED WARRANTY AND WARRANTY DISCLAIMER + +The Licensed Software is licensed to Licensee "as is". To the maximum +extent permitted by applicable law, The Qt Company on behalf of itself and +its suppliers, disclaims all warranties and conditions, either express or +implied, including, but not limited to, implied warranties of +merchantability, fitness for a particular purpose, title and +non-infringement with regard to the Licensed Software. + + +8. LIMITATION OF LIABILITY + +If, The Qt Company's warranty disclaimer notwithstanding, The Qt Company is +held liable to Licensee, whether in contract, tort or any other legal theory, +based on the Licensed Software, The Qt Company's entire liability to Licensee +and Licensee's exclusive remedy shall be, at The Qt Company's option, either +(A) return of the price Licensee paid for the Licensed Software, or (B) +repair or replacement of the Licensed Software, provided Licensee +returns to The Qt Company all copies of the Licensed Software as originally +delivered to Licensee. The Qt Company shall not under any circumstances be +liable to Licensee based on failure of the Licensed Software if the failure +resulted from accident, abuse or misapplication, nor shall The Qt Company +under any circumstances be liable for special damages, punitive or exemplary +damages, damages for loss of profits or interruption of business or for +loss or corruption of data. Any award of damages from The Qt Company to +Licensee shall not exceed the total amount Licensee has paid to The Qt +Company in connection with this Agreement. + + +9. CONFIDENTIALITY + +Each party acknowledges that during the Term of this Agreement it shall +have access to information about the other party's business, business +methods, business plans, customers, business relations, technology, and +other information, including the terms of this Agreement, that is +confidential and of great value to the other party, and the value of +which would be significantly reduced if disclosed to third parties (the +"Confidential Information"). Accordingly, when a party (the "Receiving +Party") receives Confidential Information from another party (the +"Disclosing Party"), the Receiving Party shall, and shall obligate its +employees and agents and employees and agents of its Affiliates to: (i) +maintain the Confidential Information in strict confidence; (ii) not +disclose the Confidential Information to a third party without the +Disclosing Party's prior written approval; and (iii) not, directly or +indirectly, use the Confidential Information for any purpose other than +for exercising its rights and fulfilling its responsibilities pursuant +to this Agreement. Each party shall take reasonable measures to protect +the Confidential Information of the other party, which measures shall +not be less than the measures taken by such party to protect its own +confidential and proprietary information. + +"Confidential Information" shall not include information that (a) is or +becomes generally known to the public through no act or omission of the +Receiving Party; (b) was in the Receiving Party's lawful possession +prior to the disclosure hereunder and was not subject to limitations on +disclosure or use; (c) is developed by the Receiving Party without +access to the Confidential Information of the Disclosing Party or by +persons who have not had access to the Confidential Information of the +Disclosing Party as proven by the written records of the Receiving +Party; (d) is lawfully disclosed to the Receiving Party without +restrictions, by a third party not under an obligation of +confidentiality; or (e) the Receiving Party is legally compelled to +disclose the information, in which case the Receiving Party shall assert +the privileged and confidential nature of the information and cooperate +fully with the Disclosing Party to protect against and prevent +disclosure of any Confidential Information and to limit the scope of +disclosure and the dissemination of disclosed Confidential Information +by all legally available means. + +The obligations of the Receiving Party under this Section shall continue +during the Initial Term and for a period of five (5) years after +expiration or termination of this Agreement. To the extent that the +terms of the Non-Disclosure Agreement between The Qt Company and Licensee +conflict with the terms of this Section 9, this Section 9 shall be +controlling over the terms of the Non-Disclosure Agreement. + + +10. GENERAL PROVISIONS + +10.1 No Assignment + +Licensee shall not be entitled to assign or transfer all or any of its +rights, benefits and obligations under this Agreement without the prior +written consent of The Qt Company, which shall not be unreasonably withheld. + +10.2 Termination + +The Qt Company may terminate the Agreement at any time immediately upon +written notice by The Qt Company to Licensee if Licensee breaches this +Agreement. + +Upon termination of this Agreement, Licensee shall return to The Qt Company +all copies of Licensed Software that were supplied by The Qt Company. All +other copies of Licensed Software in the possession or control of Licensee +must be erased or destroyed. An officer of Licensee must promptly +deliver to The Qt Company a written confirmation that this has occurred. + +10.3 Surviving Sections + +Any terms and conditions that by their nature or otherwise reasonably +should survive a cancellation or termination of this Agreement shall +also be deemed to survive. Such terms and conditions include, but are +not limited to the following Sections: 2, 5, 6, 7, 8, 9, 10.2, 10.3, 10.4, +10.5, 10.6, 10.7, and 10.8 of this Agreement. + +10.4 Entire Agreement + +This Agreement constitutes the complete agreement between the parties +and supersedes all prior or contemporaneous discussions, +representations, and proposals, written or oral, with respect to the +subject matters discussed herein, with the exception of the +non-disclosure agreement executed by the parties in connection with this +Agreement ("Non-Disclosure Agreement"), if any, shall be subject to +Section 9. No modification of this Agreement shall be effective unless +contained in a writing executed by an authorized representative of each +party. No term or condition contained in Licensee's purchase order shall +apply unless expressly accepted by The Qt Company in writing. If any +provision of the Agreement is found void or unenforceable, the remainder +shall remain valid and enforceable according to its terms. If any remedy +provided is determined to have failed for its essential purpose, all +limitations of liability and exclusions of damages set forth in this +Agreement shall remain in effect. + +10.5 Export Control + +Licensee acknowledges that the Licensed Software may be subject to +export control restrictions of various countries. Licensee shall fully +comply with all applicable export license restrictions and requirements +as well as with all laws and regulations relating to the importation of +the Licensed Software and shall procure all necessary governmental +authorizations, including without limitation, all necessary licenses, +approvals, permissions or consents, where necessary for the +re-exportation of the Licensed Software., + +10.6 Governing Law and Legal Venue + +This Agreement shall be governed by and construed in accordance with the +federal laws of the United States of America and the internal laws of +the State of New York without given effect to any choice of law rule +that would result in the application of the laws of any other +jurisdiction. The United Nations Convention on Contracts for the +International Sale of Goods (CISG) shall not apply. Each Party (a) +hereby irrevocably submits itself to and consents to the jurisdiction of +the United States District Court for the Southern District of New York +(or if such court lacks jurisdiction, the state courts of the State of +New York) for the purposes of any action, claim, suit or proceeding +between the Parties in connection with any controversy, claim, or +dispute arising out of or relating to this Agreement; and (b) hereby +waives, and agrees not to assert by way of motion, as a defense or +otherwise, in any such action, claim, suit or proceeding, any claim that +is not personally subject to the jurisdiction of such court(s), that the +action, claim, suit or proceeding is brought in an inconvenient forum or +that the venue of the action, claim, suit or proceeding is improper. +Notwithstanding the foregoing, nothing in this Section 9.6 is intended +to, or shall be deemed to, constitute a submission or consent to, or +selection of, jurisdiction, forum or venue for any action for patent +infringement, whether or not such action relates to this Agreement. + +10.7 No Implied License + +There are no implied licenses or other implied rights granted under this +Agreement, and all rights, save for those expressly granted hereunder, +shall remain with The Qt Company and its licensors. In addition, no licenses +or immunities are granted to the combination of the Licensed Software with +any other software or hardware not delivered by The Qt Company under this +Agreement. + +10.8 Government End Users + +A "U.S. Government End User" shall mean any agency or entity of the +government of the United States. The following shall apply if Licensee +is a U.S. Government End User. The Licensed Software is a "commercial +item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), +consisting of "commercial computer software" and "commercial computer +software documentation," as such terms are used in 48 C.F.R. 12.212 +(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 +through 227.7202-4 (June 1995), all U.S. Government End Users acquire +the Licensed Software with only those rights set forth herein. The +Licensed Software (including related documentation) is provided to U.S. +Government End Users: (a) only as a commercial end item; and (b) only +pursuant to this Agreement. + + + + + +TECHNOLOGY PREVIEW LICENSE AGREEMENT: Rest of the World +Agreement version 2.4 + +This Technology Preview License Agreement ("Agreement") is a legal +agreement between The Qt Company Ltd ("The Qt Company"), with its registered +office at Valimotie 21,FI-00380 Helsinki, Finland and you (either an +individual or a legal entity) ("Licensee") for the Licensed Software. + +1. DEFINITIONS + +"Affiliate" of a Party shall mean an entity (i) which is directly or +indirectly controlling such Party; (ii) which is under the same direct +or indirect ownership or control as such Party; or (iii) which is +directly or indirectly owned or controlled by such Party. For these +purposes, an entity shall be treated as being controlled by another if +that other entity has fifty percent (50 %) or more of the votes in such +entity, is able to direct its affairs and/or to control the composition +of its board of directors or equivalent body. + +"Applications" shall mean Licensee's software products created using the +Licensed Software which may include portions of the Licensed Software. + +"Term" shall mean the period of time six (6) months from the later of +(a) the Effective Date; or (b) the date the Licensed Software was +initially delivered to Licensee by The Qt Company. If no specific Effective +Date is set forth in the Agreement, the Effective Date shall be deemed to be +the date the Licensed Software was initially delivered to Licensee. + +"Licensed Software" shall mean the computer software, "online" or +electronic documentation, associated media and printed materials, +including the source code, example programs and the documentation +delivered by The Qt Company to Licensee in conjunction with this Agreement. + +"Party" or "Parties" shall mean Licensee and/or The Qt Company. + + +2. OWNERSHIP + +The Licensed Software is protected by copyright laws and international +copyright treaties, as well as other intellectual property laws and +treaties. The Licensed Software is licensed, not sold. + +If Licensee provides any findings, proposals, suggestions or other +feedback ("Feedback") to The Qt Company regarding the Licensed Software, +The Qt Companyshall own all right, title and interest including the +intellectual property rights in and to such Feedback, excluding however any +existing patent rights of Licensee. To the extent Licensee owns or controls +any patents for such Feedback Licensee hereby grants to The Qt Company and +its Affiliates, a worldwide, perpetual, non-transferable, sublicensable, +royalty-free license to (i) use, copy and modify Feedback and to create +derivative works thereof, (ii) to make (and have made), use, import, +sell, offer for sale, lease, dispose, offer for disposal or otherwise +exploit any products or services of The Qt Company containing Feedback, and +(iii) sublicense all the foregoing rights to third party licensees and +customers of The Qt Company and/or its Affiliates. + +3. VALIDITY OF THE AGREEMENT + +By installing, copying, or otherwise using the Licensed Software, +Licensee agrees to be bound by the terms of this Agreement. If Licensee +does not agree to the terms of this Agreement, Licensee may not install, +copy, or otherwise use the Licensed Software. Upon Licensee's acceptance +of the terms and conditions of this Agreement, The Qt Company grants Licensee +the right to use the Licensed Software in the manner provided below. + + +4. LICENSES + +4.1. Using and Copying + +The Qt Company grants to Licensee a non-exclusive, non-transferable, +time-limited license to use and copy the Licensed Software for sole purpose +of designing, developing and testing Applications, and evaluating and the +Licensed Software during the Term. + +Licensee may install copies of the Licensed Software on an unlimited +number of computers provided that (a) if an individual, only such +individual; or (b) if a legal entity only its employees; use the +Licensed Software for the authorized purposes. + +4.2 No Distribution or Modifications + +Licensee may not disclose, modify, sell, market, commercialise, +distribute, loan, rent, lease, or license the Licensed Software or any +copy of it or use the Licensed Software for any purpose that is not +expressly granted in this Section 4. Licensee may not alter or remove +any details of ownership, copyright, trademark or other property right +connected with the Licensed Software. Licensee may not distribute any +software statically or dynamically linked with the Licensed Software. + +4.3 No Technical Support + +The Qt Company has no obligation to furnish Licensee with any technical +support whatsoever. Any such support is subject to separate agreement +between the Parties. + + +5. PRE-RELEASE CODE + +The Licensed Software contains pre-release code that is not at the level +of performance and compatibility of a final, generally available, +product offering. The Licensed Software may not operate correctly and +may be substantially modified prior to the first commercial product +release, if any. The Qt Company is not obligated to make this or any later +version of the Licensed Software commercially available. The License +Software is "Not for Commercial Use" and may only be used for the +purposes described in Section 4. The Licensed Software may not be used +in a live operating environment where it may be relied upon to perform +in the same manner as a commercially released product or with data that +has not been sufficiently backed up. + +6. THIRD PARTY SOFTWARE + +The Licensed Software may provide links to third party libraries or code +(collectively "Third Party Software") to implement various functions. +Third Party Software does not comprise part of the Licensed Software. In +some cases, access to Third Party Software may be included along with +the Licensed Software delivery as a convenience for development and +testing only. Such source code and libraries may be listed in the +".../src/3rdparty" source tree delivered with the Licensed Software or +documented in the Licensed Software where the Third Party Software is +used, as may be amended from time to time, do not comprise the Licensed +Software. Licensee acknowledges (1) that some part of Third Party +Software may require additional licensing of copyright and patents from +the owners of such, and (2) that distribution of any of the Licensed +Software referencing any portion of a Third Party Software may require +appropriate licensing from such third parties. + + +7. LIMITED WARRANTY AND WARRANTY DISCLAIMER + +The Licensed Software is licensed to Licensee "as is". To the maximum +extent permitted by applicable law, The Qt Company on behalf of itself and +its suppliers, disclaims all warranties and conditions, either express or +implied, including, but not limited to, implied warranties of +merchantability, fitness for a particular purpose, title and +non-infringement with regard to the Licensed Software. + + +8. LIMITATION OF LIABILITY + +If, The Qt Company's warranty disclaimer notwithstanding, The Qt Company is +held liable to Licensee, whether in contract, tort or any other legal theory, +based on the Licensed Software, The Qt Company's entire liability to Licensee +and Licensee's exclusive remedy shall be, at The Qt Company's option, either +(A) return of the price Licensee paid for the Licensed Software, or (B) +repair or replacement of the Licensed Software, provided Licensee +returns to The Qt Company all copies of the Licensed Software as originally +delivered to Licensee. The Qt Company shall not under any circumstances be +liable to Licensee based on failure of the Licensed Software if the failure +resulted from accident, abuse or misapplication, nor shall The Qt Company +under any circumstances be liable for special damages, punitive or exemplary +damages, damages for loss of profits or interruption of business or for +loss or corruption of data. Any award of damages from The Qt Company to +Licensee shall not exceed the total amount Licensee has paid to +The Qt Company in connection with this Agreement. + + +9. CONFIDENTIALITY + +Each party acknowledges that during the Term of this Agreement it shall +have access to information about the other party's business, business +methods, business plans, customers, business relations, technology, and +other information, including the terms of this Agreement, that is +confidential and of great value to the other party, and the value of +which would be significantly reduced if disclosed to third parties (the +"Confidential Information"). Accordingly, when a party (the "Receiving +Party") receives Confidential Information from another party (the +"Disclosing Party"), the Receiving Party shall, and shall obligate its +employees and agents and employees and agents of its Affiliates to: (i) +maintain the Confidential Information in strict confidence; (ii) not +disclose the Confidential Information to a third party without the +Disclosing Party's prior written approval; and (iii) not, directly or +indirectly, use the Confidential Information for any purpose other than +for exercising its rights and fulfilling its responsibilities pursuant +to this Agreement. Each party shall take reasonable measures to protect +the Confidential Information of the other party, which measures shall +not be less than the measures taken by such party to protect its own +confidential and proprietary information. + +"Confidential Information" shall not include information that (a) is or +becomes generally known to the public through no act or omission of the +Receiving Party; (b) was in the Receiving Party's lawful possession +prior to the disclosure hereunder and was not subject to limitations on +disclosure or use; (c) is developed by the Receiving Party without +access to the Confidential Information of the Disclosing Party or by +persons who have not had access to the Confidential Information of the +Disclosing Party as proven by the written records of the Receiving +Party; (d) is lawfully disclosed to the Receiving Party without +restrictions, by a third party not under an obligation of +confidentiality; or (e) the Receiving Party is legally compelled to +disclose the information, in which case the Receiving Party shall assert +the privileged and confidential nature of the information and cooperate +fully with the Disclosing Party to protect against and prevent +disclosure of any Confidential Information and to limit the scope of +disclosure and the dissemination of disclosed Confidential Information +by all legally available means. + +The obligations of the Receiving Party under this Section shall continue +during the Initial Term and for a period of five (5) years after +expiration or termination of this Agreement. To the extent that the +terms of the Non-Disclosure Agreement between The Qt Company and Licensee +conflict with the terms of this Section 9, this Section 9 shall be +controlling over the terms of the Non-Disclosure Agreement. + + +10. GENERAL PROVISIONS + +10.1 No Assignment + +Licensee shall not be entitled to assign or transfer all or any of its +rights, benefits and obligations under this Agreement without the prior +written consent of The Qt Company, which shall not be unreasonably withheld. + +10.2 Termination + +The Qt Company may terminate the Agreement at any time immediately upon +written notice by The Qt Company to Licensee if Licensee breaches this +Agreement. + +Upon termination of this Agreement, Licensee shall return to The Qt Company +all copies of Licensed Software that were supplied by The Qt Company. All +other copies of Licensed Software in the possession or control of Licensee +must be erased or destroyed. An officer of Licensee must promptly +deliver to The Qt Company a written confirmation that this has occurred. + +10.3 Surviving Sections + +Any terms and conditions that by their nature or otherwise reasonably +should survive a cancellation or termination of this Agreement shall +also be deemed to survive. Such terms and conditions include, but are +not limited to the following Sections: 2, 5, 6, 7, 8, 9, 10.2, 10.3, 10.4, +10.5, 10.6, 10.7, and 10.8 of this Agreement. + +10.4 Entire Agreement + +This Agreement constitutes the complete agreement between the parties +and supersedes all prior or contemporaneous discussions, +representations, and proposals, written or oral, with respect to the +subject matters discussed herein, with the exception of the +non-disclosure agreement executed by the parties in connection with this +Agreement ("Non-Disclosure Agreement"), if any, shall be subject to +Section 9. No modification of this Agreement shall be effective unless +contained in a writing executed by an authorized representative of each +party. No term or condition contained in Licensee's purchase order shall +apply unless expressly accepted by The Qt Company in writing. If any provision +of the Agreement is found void or unenforceable, the remainder shall remain +valid and enforceable according to its terms. If any remedy provided is +determined to have failed for its essential purpose, all limitations of +liability and exclusions of damages set forth in this Agreement shall +remain in effect. + +10.5 Export Control + +Licensee acknowledges that the Licensed Software may be subject to +export control restrictions of various countries. Licensee shall fully +comply with all applicable export license restrictions and requirements +as well as with all laws and regulations relating to the importation of +the Licensed Software and shall procure all necessary governmental +authorizations, including without limitation, all necessary licenses, +approvals, permissions or consents, where necessary for the +re-exportation of the Licensed Software., + +10.6 Governing Law and Legal Venue + +This Agreement shall be construed and interpreted in accordance with the +laws of Finland, excluding its choice of law provisions. Any disputes +arising out of or relating to this Agreement shall be resolved in +arbitration under the Rules of Arbitration of the Chamber of Commerce of +Helsinki, Finland. The arbitration tribunal shall consist of one (1), or +if either Party so requires, of three (3), arbitrators. The award shall +be final and binding and enforceable in any court of competent +jurisdiction. The arbitration shall be held in Helsinki, Finland and the +process shall be conducted in the English language. + +10.7 No Implied License + +There are no implied licenses or other implied rights granted under this +Agreement, and all rights, save for those expressly granted hereunder, +shall remain with The Qt Company and its licensors. In addition, no licenses +or immunities are granted to the combination of the Licensed Software with +any other software or hardware not delivered by The Qt Company under this +Agreement. + +10.8 Government End Users + +A "U.S. Government End User" shall mean any agency or entity of the +government of the United States. The following shall apply if Licensee +is a U.S. Government End User. The Licensed Software is a "commercial +item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), +consisting of "commercial computer software" and "commercial computer +software documentation," as such terms are used in 48 C.F.R. 12.212 +(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 +through 227.7202-4 (June 1995), all U.S. Government End Users acquire +the Licensed Software with only those rights set forth herein. The +Licensed Software (including related documentation) is provided to U.S. +Government End Users: (a) only as a commercial end item; and (b) only +pursuant to this Agreement. + + + + diff --git a/sources/shiboken2/README.md b/sources/shiboken2/README.md new file mode 100644 index 000000000..b64f97d36 --- /dev/null +++ b/sources/shiboken2/README.md @@ -0,0 +1,19 @@ +# shiboken2 + +This is shiboken2, the code generator for PySide2. It is part of pyside2-setup, which you +should download for building and getting further information. + +Resources: + +* [PySide2-setup](https://github.com/PySide/pyside2-setup) + The container-project with the setup.py script. It contains the following sub-projects: + * [PySide2 Wiki](https://github.com/PySide/pyside2/wiki) + Developer information + * [PySide2](https://github.com/PySide/pyside2) + The PySide2 project + * [Shiboken2](https://github.com/PySide/shiboken2) + The Shiboken2 project + * [PySide2-tools](https://github.com/PySide/pyside2-examples) + The PySide2-tools project + * [PySide2-examples](https://github.com/PySide/pyside2-examples) + The PySide2 example scripts diff --git a/sources/shiboken2/cmake_uninstall.cmake b/sources/shiboken2/cmake_uninstall.cmake new file mode 100644 index 000000000..df95fb9d8 --- /dev/null +++ b/sources/shiboken2/cmake_uninstall.cmake @@ -0,0 +1,21 @@ +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + IF(EXISTS "$ENV{DESTDIR}${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ELSE(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + ENDIF(EXISTS "$ENV{DESTDIR}${file}") +ENDFOREACH(file) diff --git a/sources/shiboken2/data/CMakeLists.txt b/sources/shiboken2/data/CMakeLists.txt new file mode 100644 index 000000000..c36cb148d --- /dev/null +++ b/sources/shiboken2/data/CMakeLists.txt @@ -0,0 +1,28 @@ +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(LIBRARY_OUTPUT_SUFFIX ${CMAKE_DEBUG_POSTFIX}) +else() + set(LIBRARY_OUTPUT_SUFFIX ${CMAKE_RELEASE_POSTFIX}) +endif() + +add_custom_target(data) +add_dependencies(data shiboken2) +get_target_property(SHIBOKEN_GENERATOR shiboken2 OUTPUT_NAME) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Shiboken2Config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/Shiboken2Config.cmake" @ONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Shiboken2Config-spec.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/Shiboken2Config${PYTHON_EXTENSION_SUFFIX}.cmake" @ONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Shiboken2ConfigVersion.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/Shiboken2ConfigVersion.cmake" @ONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/shiboken2.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/shiboken2${shiboken2_SUFFIX}.pc" @ONLY) + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Shiboken2Config.cmake" + DESTINATION "${LIB_INSTALL_DIR}/cmake/Shiboken2-${shiboken2_VERSION}") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Shiboken2Config${PYTHON_EXTENSION_SUFFIX}.cmake" + DESTINATION "${LIB_INSTALL_DIR}/cmake/Shiboken2-${shiboken2_VERSION}") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Shiboken2ConfigVersion.cmake" + DESTINATION "${LIB_INSTALL_DIR}/cmake/Shiboken2-${shiboken2_VERSION}") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/shiboken2${shiboken2_SUFFIX}.pc" + DESTINATION "${LIB_INSTALL_DIR}/pkgconfig") + diff --git a/sources/shiboken2/data/GeneratorRunnerConfig.cmake.in b/sources/shiboken2/data/GeneratorRunnerConfig.cmake.in new file mode 100644 index 000000000..cf973e2a6 --- /dev/null +++ b/sources/shiboken2/data/GeneratorRunnerConfig.cmake.in @@ -0,0 +1,17 @@ +# GENERATORRUNNER_INCLUDE_DIR - Directories to include to use GENERATORRUNNER +# GENERATORRUNNER_LIBRARIES - Files to link against to use GENERATORRUNNER +# GENERATORRUNNER_PLUGIN_DIR - Where to find/put plugins for generator runner +# GENERATORRUNNER_BINARY - Executable name + +SET(GENERATORRUNNER_INCLUDE_DIR "@CMAKE_INSTALL_PREFIX@/include/generatorrunner@generator_SUFFIX@") +if(MSVC) + SET(GENERATORRUNNER_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_SHARED_LIBRARY_PREFIX@genrunner@generator_SUFFIX@.lib") +elseif(CYGWIN) + SET(GENERATORRUNNER_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_IMPORT_LIBRARY_PREFIX@genrunner@generator_SUFFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@") +elseif(WIN32) + SET(GENERATORRUNNER_LIBRARY "@CMAKE_INSTALL_PREFIX@/bin/@CMAKE_SHARED_LIBRARY_PREFIX@genrunner@generator_SUFFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@") +else() + SET(GENERATORRUNNER_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_SHARED_LIBRARY_PREFIX@genrunner@generator_SUFFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@") +endif() +SET(GENERATORRUNNER_PLUGIN_DIR "@generator_plugin_DIR@") +SET(GENERATORRUNNER_BINARY "@CMAKE_INSTALL_PREFIX@/bin/generatorrunner@generator_SUFFIX@") diff --git a/sources/shiboken2/data/GeneratorRunnerConfigVersion.cmake.in b/sources/shiboken2/data/GeneratorRunnerConfigVersion.cmake.in new file mode 100644 index 000000000..8eb5ba479 --- /dev/null +++ b/sources/shiboken2/data/GeneratorRunnerConfigVersion.cmake.in @@ -0,0 +1,10 @@ +set(PACKAGE_VERSION @generator_VERSION@) + +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") +endif("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) diff --git a/sources/shiboken2/data/Shiboken2Config-spec.cmake.in b/sources/shiboken2/data/Shiboken2Config-spec.cmake.in new file mode 100644 index 000000000..1aac9caa0 --- /dev/null +++ b/sources/shiboken2/data/Shiboken2Config-spec.cmake.in @@ -0,0 +1,29 @@ +# SHIBOKEN_INCLUDE_DIR - Directories to include to use SHIBOKEN +# SHIBOKEN_LIBRARY - Files to link against to use SHIBOKEN +# SHIBOKEN_BINARY - Executable name +# SHIBOKEN_BUILD_TYPE - Tells if Shiboken was compiled in Release or Debug mode. +# SHIBOKEN_PYTHON_INTERPRETER - Python interpreter (regular or debug) to be used with the bindings. +# SHIBOKEN_PYTHON_LIBRARIES - Python libraries (regular or debug) Shiboken is linked against. + +SET(SHIBOKEN_INCLUDE_DIR "@CMAKE_INSTALL_PREFIX@/include/shiboken2@shiboken2_SUFFIX@") +if(MSVC) + SET(SHIBOKEN_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_SHARED_LIBRARY_PREFIX@shiboken2@shiboken2_SUFFIX@@PYTHON_EXTENSION_SUFFIX@@LIBRARY_OUTPUT_SUFFIX@.lib") +elseif(CYGWIN) + SET(SHIBOKEN_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_IMPORT_LIBRARY_PREFIX@shiboken2@shiboken2_SUFFIX@@PYTHON_EXTENSION_SUFFIX@@LIBRARY_OUTPUT_SUFFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@") +elseif(WIN32) + SET(SHIBOKEN_LIBRARY "@CMAKE_INSTALL_PREFIX@/bin/@CMAKE_SHARED_LIBRARY_PREFIX@shiboken2@shiboken2_SUFFIX@@PYTHON_EXTENSION_SUFFIX@@LIBRARY_OUTPUT_SUFFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@") +else() + SET(SHIBOKEN_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_SHARED_LIBRARY_PREFIX@shiboken2@shiboken2_SUFFIX@@PYTHON_EXTENSION_SUFFIX@@LIBRARY_OUTPUT_SUFFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@") +endif() +SET(SHIBOKEN_PYTHON_INCLUDE_DIR "@SBK_PYTHON_INCLUDE_DIR@") +SET(SHIBOKEN_PYTHON_INCLUDE_DIR "@SBK_PYTHON_INCLUDE_DIR@") +SET(SHIBOKEN_PYTHON_INTERPRETER "@PYTHON_EXECUTABLE@") +SET(SHIBOKEN_PYTHON_VERSION_MAJOR "@PYTHON_VERSION_MAJOR@") +SET(SHIBOKEN_PYTHON_VERSION_MINOR "@PYTHON_VERSION_MINOR@") +SET(SHIBOKEN_PYTHON_VERSION_PATCH "@PYTHON_VERSION_PATCH@") +SET(SHIBOKEN_PYTHON_LIBRARIES "@SBK_PYTHON_LIBRARIES@") +SET(SHIBOKEN_PYTHON_EXTENSION_SUFFIX "@PYTHON_EXTENSION_SUFFIX@") +message(STATUS "libshiboken built for @SHIBOKEN_BUILD_TYPE@") +@SBK_ADD_PY_DEBUG_DEFINITION@ + +set(SHIBOKEN_BINARY "@CMAKE_INSTALL_PREFIX@/bin/@SHIBOKEN_GENERATOR@") diff --git a/sources/shiboken2/data/Shiboken2Config.cmake.in b/sources/shiboken2/data/Shiboken2Config.cmake.in new file mode 100644 index 000000000..5f7ecaec1 --- /dev/null +++ b/sources/shiboken2/data/Shiboken2Config.cmake.in @@ -0,0 +1,5 @@ +if (NOT PYTHON_EXTENSION_SUFFIX) + message(STATUS "Shiboken2Config: Using default python: @PYTHON_EXTENSION_SUFFIX@") + SET(PYTHON_EXTENSION_SUFFIX @PYTHON_EXTENSION_SUFFIX@) +endif() +include(@LIB_INSTALL_DIR@/cmake/Shiboken2-@shiboken2_VERSION@/Shiboken2Config${PYTHON_EXTENSION_SUFFIX}.cmake) diff --git a/sources/shiboken2/data/Shiboken2ConfigVersion.cmake.in b/sources/shiboken2/data/Shiboken2ConfigVersion.cmake.in new file mode 100644 index 000000000..9460099b2 --- /dev/null +++ b/sources/shiboken2/data/Shiboken2ConfigVersion.cmake.in @@ -0,0 +1,10 @@ +set(PACKAGE_VERSION @shiboken2_VERSION@) + +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") +endif("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) diff --git a/sources/shiboken2/data/docgenerator.1 b/sources/shiboken2/data/docgenerator.1 new file mode 120000 index 000000000..c65282f98 --- /dev/null +++ b/sources/shiboken2/data/docgenerator.1 @@ -0,0 +1 @@ +generatorrunner.1 \ No newline at end of file diff --git a/sources/shiboken2/data/generatorrunner.1 b/sources/shiboken2/data/generatorrunner.1 new file mode 100644 index 000000000..045b55ad4 --- /dev/null +++ b/sources/shiboken2/data/generatorrunner.1 @@ -0,0 +1,76 @@ +.TH GENERATORRUNNER 1 "SEPTEMBER 2009" Linux "User Manuals" +.SH NAME +generatorrunner - plugin-based binding source code generator +.SH SYNOPSIS +.B generatorrunner \-\-generator-set= [options] header-file typesystem-file +.SH DESCRIPTION +.B generatorrunner +is a utility that uses the information taken from APIExtractor +related to the provided C++ headers and typesystem files and execute +generators using this information. Generators are plugins and you need +to specify one using the \-\-generator-set parameter. At the moment there +are two generators available: + +.B qtdoc +\- Generates Sphinx-based documentation for C++ libraries documented using +.B qdoc3 +documentation syntax, using the XML files created by the documentation tool +.B (qdoc3). +Can be called supplying +.B \-\-generator-set=qtdoc +to +.B generatorrunner +or by calling the convenience executable +.B docgenerator. + +Other plugins can be used with +.B generatorrunner, +provided that they follow the generator front-end specifications, +and can be written to generate code or documentation for any target +languague you desire. For more information about the generator front-end +architecture and current limitations, refer to http://www.pyside.org/home-binding. + +.SH OPTIONS +.SS "General options" +.IP \-\-api-version= +Specify the supported api version used to generate the bindings. +.IP \-\-debug-level=[sparse|medium|full] +The amount of messages displayed. +.IP \-\-documentation-only +Only generates the documentation. +.IP \-\-drop-type-entries="[;TypeEntry1;...]" +Semicolon separated list of type system entries (classes, namespaces, global functions and enums) to be dropped from generation. +.IP \-\-help \fR,\fP \-h \fR,\fP -? +Prints the usage message. +.IP \-\-project-file= +Text file containing a description of the binding project. Replaces and overrides command line arguments. +.IP \-\-include\-paths=\fI[:path:..]\fR +The directories where the generator will search for the +headers. Works like gcc's \-I flag. +.IP \-\-license\-file=\fI[licensefile]\fR +Template for copyright headers of generated files. +.IP \-\-no\-supress\-warnings +Show all warnings. +.IP \-\-output\-directory=\fI[dir]\fR +The directory where the generated files will be written. +.IP \-\-silent +Avoid printing any messages. +.IP \-\-typesytem\-paths=\fI[:path:..]\fR +The directories where the generator will search for the +external typesystems referred by the main one. +.IP \-\-version +Displays the current version. +Drops support for named args. +.SS "Specific to qtdoc plugin" +.IP \-\-documentation\-code\-snippets\-dir +Directory used to search code snippets used by the documentation +.IP \-\-documentation\-data\-dir +Directory with XML files generated by documentation tool (qdoc3 or Doxygen) +.IP \-\-documentation\-out\-dir +The directory where the generated documentation files will be written +.IP \-\-library\-source\-dir +Directory where library source code is located + +.SH AUTHORS +Lauro Moura , Bruno Araujo , Hugo Lima + diff --git a/sources/shiboken2/data/generatorrunner.pc.in b/sources/shiboken2/data/generatorrunner.pc.in new file mode 100644 index 000000000..a566f4356 --- /dev/null +++ b/sources/shiboken2/data/generatorrunner.pc.in @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@LIB_INSTALL_DIR@ +includedir=@CMAKE_INSTALL_PREFIX@/include + + +Name: generatorrunner@generator_SUFFIX@ +Description: Generator Runner loads and calls binding generator front-ends. +Requires: apiextractor +Version: @generatorrunner_VERSION@ +Libs: -L${libdir} -lgenrunner@generator_SUFFIX@ +Cflags: -I${includedir}@generator_SUFFIX@ + diff --git a/sources/shiboken2/data/shiboken2.pc.in b/sources/shiboken2/data/shiboken2.pc.in new file mode 100644 index 000000000..aec210c5c --- /dev/null +++ b/sources/shiboken2/data/shiboken2.pc.in @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@LIB_INSTALL_DIR@ +includedir=@CMAKE_INSTALL_PREFIX@/include/shiboken2 +generator_location=@CMAKE_INSTALL_PREFIX@/bin/@SHIBOKEN_GENERATOR@ +python_interpreter=@PYTHON_EXECUTABLE@ +python_include_dir=@SBK_PYTHON_INCLUDE_DIR@ + +Name: shiboken2 +Description: Support library for Python bindings created with the Shiboken2 generator. +Version: @shiboken2_VERSION@ +Libs: @SBK_PYTHON_LIBRARIES@ -L${libdir} -lshiboken2@shiboken2_SUFFIX@@PYTHON_EXTENSION_SUFFIX@@LIBRARY_OUTPUT_SUFFIX@ +Cflags: -I@SBK_PYTHON_INCLUDE_DIR@ -I${includedir}/@shiboken2_SUFFIX@@SBK_PKG_CONFIG_PY_DEBUG_DEFINITION@ diff --git a/sources/shiboken2/doc/CMakeLists.txt b/sources/shiboken2/doc/CMakeLists.txt new file mode 100644 index 000000000..7bd0161ad --- /dev/null +++ b/sources/shiboken2/doc/CMakeLists.txt @@ -0,0 +1,24 @@ + +find_program(SPHINX sphinx-build DOC "Path to sphinx-build binary.") + +if (SPHINX) + message("-- sphinx-build - found") + configure_file(conf.py.in conf.py @ONLY) + add_custom_target(doc ${SPHINX} -b html -c . ${CMAKE_CURRENT_SOURCE_DIR} html ) +else() + message("-- sphinx-build - not found! doc target disabled") + if (WIN32) + # if jom is used and we have no sphinx, then jom will crash. + # so for windows, we always create a doc target (until jom gets fixed...) + add_custom_target(doc echo. + COMMAND echo +++ This is a fake build, to make 'jom' happy. + COMMAND echo +++ The documentation was _not_ built! + COMMAND echo. + ) + endif() +endif() + +if (NOT WIN32) + file(GLOB manpages "${CMAKE_CURRENT_SOURCE_DIR}/*.1") + install(FILES ${manpages} DESTINATION share/man/man1) +endif() diff --git a/sources/shiboken2/doc/_templates/index.html b/sources/shiboken2/doc/_templates/index.html new file mode 100644 index 000000000..00ac64271 --- /dev/null +++ b/sources/shiboken2/doc/_templates/index.html @@ -0,0 +1,35 @@ +{% extends "layout.html" %} +{% set title = 'Overview' %} +{% block body %} +
+

{{ project }} {{ version }}

+ +

{{ project }} is a plugin (front-end) for Generator Runner. It generates bindings for C++ libraries using CPython source code.

+ +

Documentation

+ + + +
+ + + + + + + + + + +
+
+{% endblock %} diff --git a/sources/shiboken2/doc/_templates/layout.html b/sources/shiboken2/doc/_templates/layout.html new file mode 100644 index 000000000..94ff3534e --- /dev/null +++ b/sources/shiboken2/doc/_templates/layout.html @@ -0,0 +1,29 @@ +{% extends "!layout.html" %} + +# Invert sidebars +{%- block sidebar1 %}{{ sidebar() }}{%- endblock %} +{%- block sidebar2 %}{%- endblock %} + +{%- block header %} +
+
+
+ + {{ relbar() }} +
+
+{%- endblock -%} + +{%- block footer %} + +
+{%- endblock %} + +# No top relbar. +{%- block relbar1 %}{%- endblock %} + +# No bottom relbar. +{%- block relbar2 %}{%- endblock %} diff --git a/sources/shiboken2/doc/_themes/pysidedocs/searchbox.html b/sources/shiboken2/doc/_themes/pysidedocs/searchbox.html new file mode 100644 index 000000000..55a972156 --- /dev/null +++ b/sources/shiboken2/doc/_themes/pysidedocs/searchbox.html @@ -0,0 +1,12 @@ +{%- if pagename != "search" %} + + +{%- endif %} diff --git a/sources/shiboken2/doc/_themes/pysidedocs/static/bg_header.png b/sources/shiboken2/doc/_themes/pysidedocs/static/bg_header.png new file mode 100644 index 000000000..843e7e2c5 Binary files /dev/null and b/sources/shiboken2/doc/_themes/pysidedocs/static/bg_header.png differ diff --git a/sources/shiboken2/doc/_themes/pysidedocs/static/bg_topo.jpg b/sources/shiboken2/doc/_themes/pysidedocs/static/bg_topo.jpg new file mode 100644 index 000000000..4229ae8db Binary files /dev/null and b/sources/shiboken2/doc/_themes/pysidedocs/static/bg_topo.jpg differ diff --git a/sources/shiboken2/doc/_themes/pysidedocs/static/fakebar.png b/sources/shiboken2/doc/_themes/pysidedocs/static/fakebar.png new file mode 100644 index 000000000..b45830e00 Binary files /dev/null and b/sources/shiboken2/doc/_themes/pysidedocs/static/fakebar.png differ diff --git a/sources/shiboken2/doc/_themes/pysidedocs/static/logo_python.jpg b/sources/shiboken2/doc/_themes/pysidedocs/static/logo_python.jpg new file mode 100644 index 000000000..cd474efba Binary files /dev/null and b/sources/shiboken2/doc/_themes/pysidedocs/static/logo_python.jpg differ diff --git a/sources/shiboken2/doc/_themes/pysidedocs/static/logo_qt.png b/sources/shiboken2/doc/_themes/pysidedocs/static/logo_qt.png new file mode 100644 index 000000000..39a4a26f3 Binary files /dev/null and b/sources/shiboken2/doc/_themes/pysidedocs/static/logo_qt.png differ diff --git a/sources/shiboken2/doc/_themes/pysidedocs/static/pysidedocs.css b/sources/shiboken2/doc/_themes/pysidedocs/static/pysidedocs.css new file mode 100644 index 000000000..708ddf77c --- /dev/null +++ b/sources/shiboken2/doc/_themes/pysidedocs/static/pysidedocs.css @@ -0,0 +1,475 @@ +* { + font: 100% Verdana, Arial, Helvetica, sans-serif; + font-size:12px; +} + +html { + height: 100%; +} + +body { + margin: 0; + padding: 0; + background-color: #EBEBEB; + height: 100%; + color: #333; +} + +strong { + font-weight:bold; +} + +.document { + padding-bottom: 90px; +} + +#container { + position: relative; + min-height: 100%; + background-image: url(fakebar.png); + background-repeat: repeat-y; + background-color: white; +} + +.footer { + position: absolute; + bottom: 0px; + margin-top: 50px; + text-align:center; + background-color: white; + border-top: 2px solid #e0e0e0; + white-space: nowrap; + height: 90px; + width: 100%; +} + +.footer img { + margin-left: 8px; + margin-right: 8px; +} + +.sphinxsidebar { + float: left; + width: 250px; + padding: 0px 10px 0px 10px; + text-align: left; +} + +.sphinxsidebar ul { + padding: 0px; + margin: 0px; + list-style-position: inside; +} + +.sphinxsidebar > ul { + padding: 0px; + margin: 0px; +} + +.sphinxsidebar ul li { + margin-left: 10px; + padding: 0px; +} + +.sphinxsidebar h3, .sphinxsidebar h3 a { + font-weight: bold; + color: #333; +} + +.documentwrapper { + margin-left: 270px; + text-align: left; + background-color: #ffffff; + border-left: 1px solid #989898; + font-size:18px; + padding: 10px 50px 15px 50px; + height: 100%; +} + +h1 { + font-size:18px; + padding-left: 50px; + padding-bottom: 15px; + padding-top: 15px; + border-bottom: 1px solid #c2c2c2; + margin-right: -100px; + position: relative; + left: -50px; + top: -10px; +} + +h2 { + font-size:12px; + font-weight:bold; + border-left-width: 1px; + border-right-width: 1px; + border-top-width: 1px; + border-bottom-width: 2px; + border-style: solid; + border-left-color: #b1b1b1; + border-right-color: #b1b1b1; + border-top-color: #b1b1b1; + border-bottom-color: #009491; + background-color: #e0e0e0; + padding:5px; + margin-top: 20px; + -moz-border-radius:5px; + -webkit-border-radius:5px; + -khtml-border-radius:5px; +} + +h3, h4 { + font-weight: bolder; +} + +pre { + border-top: 1px solid #e0e0e0; + border-bottom: 1px solid #e0e0e0; + background-color: #fafafa; + padding: 5px; + font: 100% monospace; + overflow: auto; +} + +pre * { + font: 100% monospace; +} + +.pre { + font: 100% monospace; +} + +.headerlink { + font-size: 100%; + color: inherit; + float: right; + visibility: Hidden +} + +h1 .headerlink { + padding-right: 50px; +} + +h1:hover .headerlink, h2:hover .headerlink, h3:hover .headerlink { + visibility: Visible; +} + +a, a:visited { + color: #009491; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +div.seealso { + background-color: #ffffcc; + border: 1px solid #ffff66; +} + +div.note { + border: 1px solid #e3e3e3; +} + +table.docutils { + margin-left: auto; + margin-right: auto; + margin-bottom: 10px; + border: none; +} + +table.docutils td { + border: none; +} + +table.docutils th { + border: none; + font-weight: bold; + vertical-align: top; +} + +h2 em { + float: right; + font-size: 10px; + position: relative; + top: -20px; +} + +/* Table of pymaemo components */ + +#development table.docutils td { + border-bottom: 1px solid #EBEBEB; +} + +#development th { + background-color: #EBEBEB; + color: #FC7E00; + padding: 5px; +} + +#development th:first-child { + -moz-border-radius: 20px 0px 0px 0px; + -webkit-border-radius: 20px 0px 0px 0px; + -khtml-border-radius: 20px 0px 0px 0px; + padding-left: 10px; +} +#development th:last-child { + -moz-border-radius: 0px 20px 0px 0px; + -webkit-border-radius: 0px 20px 0px 0px; + -khtml-border-radius: 0px 20px 0px 0px; + padding-right: 10px; + width: 100px; +} + +hr { + border: none; + border-bottom: 1px dashed #EBEBEB; + width: 70% +} + +.oldnews { + text-align: right; +} + +/******************* TOPO *****************************/ +.header { + background-image: url(bg_topo.jpg); + background-repeat: repeat-x; + height: 147px; +} + +.header_container { + background-image: url(bg_header.png); + background-repeat: no-repeat; + background-position: 100px 0px; +} + +.logo { + text-align: left; + margin-bottom: 10px; +} + +#searchbox { + border-top: 1px solid #989898; + padding-top: 10px; + margin-left: -10px; + margin-right: -10px; + padding-left: 10px; + padding-right: 10px; +} + +#search_button { + border: 1px solid #3A393A; + background-color: #3A393A; + color: white; + cursor: pointer; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -khtml-border-radius: 5px; + +} + +form { + margin: 0px; + padding: 0px; +} + +/* search field */ +form #q { + width: 136px; +/* height: 22px; */ + border: none; + margin: 0px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -khtml-border-radius: 5px; + margin-top: 2px; + padding: 4px; + line-height: 22px +} + +#search-results h2 { + display: none; +} + +#search-results h2 { + display: none; +} + +#search-results ul.search { + margin: 0px; + padding: 0px; +} + +ul.search div.context { + padding-left: 40px; +} + +#installation td { + text-align: center; + font-weight: bold; +} + +em { + color: inherit; + font-style:italic; +} + +/******** REL bar *********/ + +.related { + display: inline; +} + +.related ul { + padding: 0px 0px 0px 10px; + margin: 0px; + text-align: left; + background-image: url(relbar_bg.png); +} + +.related li { + display: inline; + color: white; + font-weight: bold; +} + +.related li a { + color: inherit; + line-height: 35px; + font-weight: bold; + vertical-align: middle; +} + +.related li.right { + float: right; + margin-right: 5px; +} + +.related h3 { + display: none; +} + +.align-center { + text-align: center; +} + +.contentstable { + width: 100%; +} + +.contentstable td { + padding-left: 30px; + vertical-align: top; +} + +p.biglink a { + font-size: 20px; +} + +dt:target, .highlight { + background-color: #fbe54e; +} + +img { + border: 0px; +} + +.figure .caption { + font-style:italic; +} + +table.footnote { + margin: 0px; +} + +#synopsis table, table.field-list { + margin: 0px; +} + +tt.descname { + font-size: 120%; + font-weight: bold; +} + +#functions ul, #virtual-functions ul, #slots ul, #signals ul, #static-functions ul { + list-style: none; + margin: 0px; + padding: 10px; + border: 1px solid #ddd; + background-color: #f4f4f4; + -moz-border-radius:10px; + -webkit-border-radius:10px; + -khtml-border-radius:10px; +} + +#synopsis span.pre { + color: #009491; + font-weight: bolder; +} + +#detailed-description .class dt, #detailed-description .method dt, #detailed-description .attribute dt, #detailed-description .function dt { + margin: 0px; + padding: 10px; + border: 1px solid #ddd; + background-color: #f4f4f4; + -moz-border-radius:10px; + -webkit-border-radius:10px; + -khtml-border-radius:10px; +} + +.pysidetoc ul { + list-style: none; + padding: 0px; + margin: 0px; +} + +.pysidetoc em { + font-style: normal; +} + +.pysidetoc strong { + display: block; + padding: 5px; + border: 1px solid #ddd; + background-color: #f4f4f4; + -moz-border-radius:6px; + -webkit-border-radius:6px; + -khtml-border-radius:6px; +} + +.hide { + display: none; +} diff --git a/sources/shiboken2/doc/_themes/pysidedocs/static/pysidelogo.png b/sources/shiboken2/doc/_themes/pysidedocs/static/pysidelogo.png new file mode 100644 index 000000000..076c1057c Binary files /dev/null and b/sources/shiboken2/doc/_themes/pysidedocs/static/pysidelogo.png differ diff --git a/sources/shiboken2/doc/_themes/pysidedocs/static/relbar_bg.png b/sources/shiboken2/doc/_themes/pysidedocs/static/relbar_bg.png new file mode 100644 index 000000000..4036733a7 Binary files /dev/null and b/sources/shiboken2/doc/_themes/pysidedocs/static/relbar_bg.png differ diff --git a/sources/shiboken2/doc/_themes/pysidedocs/theme.conf b/sources/shiboken2/doc/_themes/pysidedocs/theme.conf new file mode 100644 index 000000000..e0a652a5d --- /dev/null +++ b/sources/shiboken2/doc/_themes/pysidedocs/theme.conf @@ -0,0 +1,7 @@ +[theme] +inherit = default +stylesheet = pysidedocs.css +pygments_style = none + +[options] +nosidebar = false diff --git a/sources/shiboken2/doc/codeinjectionsemantics.rst b/sources/shiboken2/doc/codeinjectionsemantics.rst new file mode 100644 index 000000000..d748a3aae --- /dev/null +++ b/sources/shiboken2/doc/codeinjectionsemantics.rst @@ -0,0 +1,397 @@ +************************ +Code Injection Semantics +************************ + +API Extractor provides the `inject-code +`_ tag +allowing the user to put custom written code to on specific locations of the generated code. +Yet this is only part of what is needed to generate proper binding code, where the custom code +should be written to depends upon the technology used on the generated binding code. + +This is the ``inject-code`` tag options that matters to |project|. + + .. code-block:: xml + + + // custom code + + +Conventions +=========== + +**C++ Wrapper** + This term refers to a generated C++ class that extends a class from the + wrapped library. It is used only when a wrapped C++ class is polymorphic, + i.e. it has or inherits any virtual methods. + +**Python Wrapper** + The code that exports the C++ wrapped class to Python. **Python wrapper** + refers to all the code needed to export a C++ class to Python, and + **Python method/function wrapper** means the specific function that calls + the C++ method/function on behalf of Python. + +**Native** + This is a possible value for the ``class`` attribute of the ``inject-code`` + tag, it means things more akin to the C++ side. + +**Target** + Another ``class`` attribute value, it indicates things more close to the + Python side. + +inject-code tag +=============== + +The following table describes the semantics of ``inject-code`` tag as used on +|project|. + + +---------------+------+---------+--------------------------------------------------------------+ + |Parent Tag |Class |Position |Meaning | + +===============+======+=========+==============================================================+ + |value-type, |native|beginning|Write to the beginning of a class wrapper ``.cpp`` file, right| + |object-type | | |after the ``#include`` clauses. A common use would be to write| + | | | |prototypes for custom functions whose definitions are put on a| + | | | |``native/end`` code injection. | + | | +---------+--------------------------------------------------------------+ + | | |end |Write to the end of a class wrapper ``.cpp`` file. Could be | + | | | |used to write custom/helper functions definitions for | + | | | |prototypes declared on ``native/beginning``. | + | +------+---------+--------------------------------------------------------------+ + | |target|beginning|Put custom code on the beginning of the wrapper initializer | + | | | |function (``init_CLASS(PyObject *module)``). This could be | + | | | |used to manipulate the ``PyCLASS_Type`` structure before | + | | | |registering it on Python. | + | | +---------+--------------------------------------------------------------+ + | | |end |Write the given custom code at the end of the class wrapper | + | | | |initializer function (``init_CLASS(PyObject *module)``). The | + | | | |code here will be executed after all the wrapped class | + | | | |components have been initialized. | + +---------------+------+---------+--------------------------------------------------------------+ + |modify-function|native|beginning|Code here is put on the virtual method override of a C++ | + | | | |wrapper class (the one responsible for passing C++ calls to a | + | | | |Python override, if there is any), right after the C++ | + | | | |arguments have been converted but before the Python call. | + | | +---------+--------------------------------------------------------------+ + | | |end |This code injection is put in a virtual method override on the| + | | | |C++ wrapper class, after the call to Python and before | + | | | |dereferencing the Python method and tuple of arguments. | + | +------+---------+--------------------------------------------------------------+ + | |target|beginning|This code is injected on the Python method wrapper | + | | | |(``PyCLASS_METHOD(...)``), right after the decisor have found | + | | | |which signature to call and also after the conversion of the | + | | | |arguments to be used, but before the actual call. | + | | +---------+--------------------------------------------------------------+ + | | |end |This code is injected on the Python method wrapper | + | | | |(``PyCLASS_METHOD(...)``), right after the C++ method call, | + | | | |but still inside the scope created by the overload for each | + | | | |signature. | + | +------+---------+--------------------------------------------------------------+ + | |shell |beginning|Used only for virtual functions. The code is injected when the| + | | | |function does not has a pyhton implementation, then the code | + | | | |is inserted before c++ call | + | | +---------+--------------------------------------------------------------+ + | | |end |Same as above, but the code is inserted after c++ call | + +---------------+------+---------+--------------------------------------------------------------+ + |typesystem |native|beginning|Write code to the beginning of the module ``.cpp`` file, right| + | | | |after the ``#include`` clauses. This position has a similar | + | | | |purpose as the ``native/beginning`` position on a wrapper | + | | | |class ``.cpp`` file, namely write function prototypes, but not| + | | | |restricted to this use. | + | | +---------+--------------------------------------------------------------+ + | | |end |Write code to the end of the module ``.cpp`` file. Usually | + | | | |implementations for function prototypes inserted at the | + | | | |beginning of the file with a ``native/beginning`` code | + | | | |injection. | + | +------+---------+--------------------------------------------------------------+ + | |target|beginning|Insert code at the start of the module initialization function| + | | | |(``initMODULENAME()``), before the calling ``Py_InitModule``. | + | | +---------+--------------------------------------------------------------+ + | | |end |Insert code at the end of the module initialization function | + | | | |(``initMODULENAME()``), but before the checking that emits a | + | | | |fatal error in case of problems importing the module. | + +---------------+------+---------+--------------------------------------------------------------+ + + +Anatomy of Code Injection +========================= + +To make things clear let's use a simplified example of generated wrapper code +and the places where each kind of code injection goes. + +Below is the example C++ class for whom wrapper code will be generated. + + .. code-block:: c++ + + class InjectCode { + public: + InjectCode(); + double overloadedMethod(int arg); + double overloadedMethod(double arg); + virtual int virtualMethod(int arg); + }; + +From the C++ class, |project| will generate a ``injectcode_wrapper.cpp`` file +with the binding code. The next section will use a simplified version of the +generated wrapper code with the injection spots marked with comments. + +Noteworthy Cases +---------------- + +The type system description system gives the binding developer a lot of +flexibility, which is power, which comes with responsibility. Some modifications +to the wrapped API will not be complete without some code injection. + + +Removing arguments and setting a default values for them +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A simple case is when a function have one argument removed, as when the C++ +method ``METHOD(ARG)`` is modified to be used from Python as ``METHOD()``; +of course the binding developer must provide some guidelines to the generator +on what to do to call it. The most common solution is to remove the argument and +set a default value for it at the same time, so the original C++ method could be +called without problems. + +Removing arguments and calling the method with your own hands +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If the argument is removed and no default value is provided, the generator will +not write any call to the method and expect the ``modify-function - target/beginning`` +code injection to call the original C++ method on its own terms. If even this +custom code is not provided the generator will put an ``#error`` clause to +prevent compilation of erroneus binding code. + +Calling the method with your own hands always! +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If your custom code to be injected contains a call to the wrapped C++ method, +it surely means that you don't want the generator to write another call to the +same method. As expected |project| will detect the user written call on the code +injection and will not write its own call, but for this to work properly the +binding developer must use the template variable ``%FUNCTION_NAME`` instead +of writing the actual name of the wrapped method/function. + +In other words, use + + .. code-block:: xml + + + %CPPSELF.originalMethodName(); + + + +instead of + + + .. code-block:: xml + + + %CPPSELF.%FUNCTION_NAME(); + + + +Code Injection for Functions/Methods +==================================== + + +.. _codeinjecting_method_native: + +On The Native Side +------------------ + +Notice that this is only used when there is a C++ wrapper, i.e. the wrapped +class is polymorphic. + + .. code-block:: c++ + + int InjectCodeWrapper::virtualMethod(int arg) + { + PyObject* method = BindingManager::instance().getOverride(this, "virtualMethod"); + if (!py_override) + return this->InjectCode::virtualMethod(arg); + + (... here C++ arguments are converted to Python ...) + + // INJECT-CODE: + // Uses: pre method call custom code, modify the argument before the + // Python call. + + (... Python method call goes in here ...) + + // INJECT-CODE: + // Uses: post method call custom code, modify the result before delivering + // it to C++ caller. + + (... Python method and argument tuple are dereferenced here ...) + + return Shiboken::Converter::toCpp(method_result); + } + + +On The Target Side +------------------ + +All the overloads of a method from C++ are gathered together on a single Python +method that uses an overload decisor to call the correct C++ method based on the +arguments passed by the Python call. Each overloaded method signature has its +own ``beginning`` and ``end`` code injections. + + .. code-block:: c++ + + static PyObject* + PyInjectCode_overloadedMethod(PyObject* self, PyObject* arg) + { + PyObject* py_result = 0; + if (PyFloat_Check(arg)) { + double cpp_arg0 = Shiboken::Converter::toCpp(arg); + + // INJECT-CODE: + // Uses: pre method call custom code. + + py_result = Shiboken::Converter::toPython( + PyInjectCode_cptr(self)->InjectCode::overloadedMethod(cpp_arg0) + ); + + // INJECT-CODE: + // Uses: post method call custom code. + + } else if (PyNumber_Check(arg)) { + (... other overload calling code ...) + } else goto PyInjectCode_overloadedMethod_TypeError; + + if (PyErr_Occurred() || !py_result) + return 0; + + return py_result; + + PyInjectCode_overloadedMethod_TypeError: + PyErr_SetString(PyExc_TypeError, "'overloadedMethod()' called with wrong parameters."); + return 0; + } + + +.. _codeinjecting_classes: + +Code Injection for Wrapped Classes +================================== + +.. _codeinjecting_classes_native: + +On The Native Side +------------------ + +Those injections go in the body of the ``CLASSNAME_wrapper.cpp`` file for the +wrapped class. + + .. code-block:: c++ + + // Start of ``CLASSNAME_wrapper.cpp`` + #define protected public + // default includes + #include + (...) + #include "injectcode_wrapper.h" + using namespace Shiboken; + + // INJECT-CODE: + // Uses: prototype declarations + + (... C++ wrapper virtual methods, if any ...) + + (... Python wrapper code ...) + + PyAPI_FUNC(void) + init_injectcode(PyObject *module) + { + (...) + } + + (...) + + // INJECT-CODE: + // Uses: definition of functions prototyped at ``native/beginning``. + + // End of ``CLASSNAME_wrapper.cpp`` + + +.. _codeinjecting_classes_target: + +On The Target Side +------------------ + +Code injections to the class Python initialization function. + + .. code-block:: c++ + + // Start of ``CLASSNAME_wrapper.cpp`` + + (...) + + PyAPI_FUNC(void) + init_injectcode(PyObject *module) + { + // INJECT-CODE: + // Uses: Alter something in the PyInjectCode_Type (tp_flags value for example) + // before registering it. + + if (PyType_Ready(&PyInjectCode_Type) < 0) + return; + + Py_INCREF(&PyInjectCode_Type); + PyModule_AddObject(module, "InjectCode", + ((PyObject*)&PyInjectCode_Type)); + + // INJECT-CODE: + // Uses: do something right after the class is registered, like set some static + // variable injected on this same file elsewhere. + } + + (...) + + // End of ``CLASSNAME_wrapper.cpp`` + +Code Injection for Modules +========================== + +The C++ libraries are wapped as Python modules, a collection of classes, +functions, enums and namespaces. |project| creates wrapper files for all of +them and also one extra ``MODULENAME_module_wrapper.cpp`` to register the whole +module. Code injection xml tags who have the ``typesystem`` tag as parent will +be put on this file. + +On The Native Side +------------------ + +This works exactly as the class wrapper code injections :ref:`codeinjecting_classes_native`. + +On The Target Side +------------------ + +This is very similar to class wrapper code injections :ref:`codeinjecting_classes_target`. +Notice that the inject code at ``target/end`` is inserted before the check for errors +to prevent bad custom code to pass unnoticed. + + .. code-block:: c++ + + // Start of ``MODULENAME_module_wrapper.cpp`` + + (...) + initMODULENAME() + { + // INJECT-CODE: + // Uses: do something before the module is created. + + PyObject* module = Py_InitModule("MODULENAME", MODULENAME_methods); + + (... initialization of wrapped classes, namespaces, functions and enums ...) + + // INJECT-CODE: + // Uses: do something after the module is registered and initialized. + + if (PyErr_Occurred()) + Py_FatalError("can't initialize module sample"); + } + + (...) + + // Start of ``MODULENAME_module_wrapper.cpp`` + diff --git a/sources/shiboken2/doc/commandlineoptions.rst b/sources/shiboken2/doc/commandlineoptions.rst new file mode 100644 index 000000000..d373561cd --- /dev/null +++ b/sources/shiboken2/doc/commandlineoptions.rst @@ -0,0 +1,105 @@ +.. _command-line: + +Command line options +******************** + +Usage +----- + +:: + + shiboken [options] header-file typesystem-file + + +Options +------- + +``--disable-verbose-error-messages`` + Disable verbose error messages. Turn the CPython code hard to debug but saves a few kilobytes + in the generated binding. + +.. _parent-heuristic: + +``--enable-parent-ctor-heuristic`` + This flag enable an useful heuristic which can save a lot of work related to object ownership when + writing the typesystem. + For more info, check :ref:`ownership-parent-heuristics`. + +.. _pyside-extensions: + +``--enable-pyside-extensions`` + Enable pyside extensions like support for signal/slots. Use this if you are creating a binding based + on PySide. + +.. _return-heuristic: + +``--enable-return-value-heuristic`` + Enable heuristics to detect parent relationship on return values. + For more info, check :ref:`return-value-heuristics`. + +.. _api-version: + +``--api-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`` + Do not generate any code, just the documentation. + +.. _drop-type-entries: + +``--drop-type-entries="[;TypeEntry1;...]"`` + Semicolon separated list of type system entries (classes, namespaces, + global functions and enums) to be dropped from generation. + +.. _generation-set: + +``--generation-set`` + Generator set to be used (e.g. qtdoc). + +.. _help: + +``--help`` + Display this help and exit. + +.. _include-paths: + +``--include-paths=[::...]`` + Include paths used by the C++ parser. + +.. _license-file=[license-file]: + +``--license-file=[license-file]`` + File used for copyright headers of generated files. + +.. _no-suppress-warnings: + +``--no-suppress-warnings`` + Show all warnings. + +.. _output-directory: + +``--output-directory=[dir]`` + The directory where the generated files will be written. + +.. _silent: + +``--silent`` + Avoid printing any message. + +.. _typesystem-paths: + +``--typesystem-paths=[::...]`` + Paths used when searching for type system files. + +.. _version: + +``--version`` + Output version information and exit. + diff --git a/sources/shiboken2/doc/conf.py.in b/sources/shiboken2/doc/conf.py.in new file mode 100644 index 000000000..ed61d2695 --- /dev/null +++ b/sources/shiboken2/doc/conf.py.in @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- +# +# PyQtB documentation build configuration file, created by +# sphinx-quickstart on Wed Apr 22 15:04:20 2009. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.append(os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.coverage'] + +rst_epilog = """ +.. |project| replace:: Shiboken +""" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +source_encoding = 'utf-8' + +# The master toctree document. +#master_doc = 'contents' + +# General information about the project. +project = u'Shiboken' +copyright = u'Copyright (C) 2016 The Qt Company Ltd.' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '@shiboken_VERSION@' +# The full version, including alpha/beta/rc tags. +release = '@shiboken_VERSION@' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'pysidedocs' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = { +#} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_themes'] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# 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 = { '' : ''} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +html_additional_pages = { 'index' : 'index.html'} + +# If false, no module index is generated. +html_use_modindex = False + +# If false, no index is generated. +html_use_index = False + +# If true, the index is split into individual pages for each letter. +html_split_index = False + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = False + +html_add_permalinks = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + diff --git a/sources/shiboken2/doc/contents.rst b/sources/shiboken2/doc/contents.rst new file mode 100644 index 000000000..24adb1c68 --- /dev/null +++ b/sources/shiboken2/doc/contents.rst @@ -0,0 +1,17 @@ +Table of contents +***************** +.. toctree:: + :numbered: + :maxdepth: 3 + + faq.rst + overview.rst + commandlineoptions.rst + projectfile.rst + typesystemvariables.rst + typeconverters.rst + codeinjectionsemantics.rst + sequenceprotocol.rst + ownership.rst + wordsofadvice.rst + shibokenmodule.rst diff --git a/sources/shiboken2/doc/dependency-pyqtb.svg b/sources/shiboken2/doc/dependency-pyqtb.svg new file mode 100644 index 000000000..a458bf6fb --- /dev/null +++ b/sources/shiboken2/doc/dependency-pyqtb.svg @@ -0,0 +1,600 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + API Extractor + 0.2 + Headers and libraries - compile-time + LGPL version 2.1 + + + + + + Shiboken (generator) + 0.1 + Binary executable - compile-time + GPL version 2 + + + + + + boost::graph + 1.38.0 + headers and libraries - compile-time + Boost Software License 1.0 + + + + + + + + + Boost + + + + Qt Software + + + + INdT/Nokia + + + + Python Foundation + + + + + + + + libshiboken + 0.1 + Headers and libraries - compile-time + LGPL version 2.1 + + + + + + Qt 4.5 + 4.5 + headers and libraries - compile-time and run-time + GNU General Public License v3 /GNU Lesser General Public Licence v2.1 + + + + + + Python + 2.6 + Headers and libraries - compile-time and run-time + Python license + + + + + + diff --git a/sources/shiboken2/doc/dependency-pyside.svg b/sources/shiboken2/doc/dependency-pyside.svg new file mode 100644 index 000000000..786bdb8a6 --- /dev/null +++ b/sources/shiboken2/doc/dependency-pyside.svg @@ -0,0 +1,527 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + boost::python + 1.38.0 + headers and libraries - compile-time and run-time + Boost Software License 1.0 + + + + Qt 4.5 + 4.5 + headers and libraries - compile-time and run-time + GNU General Public License v3 /GNU Lesser General Public Licence v2.1 + + + + libapiextractor + 0.1 + headers and libraries - compile-time and run-time + LGPL version 2.1 + + + + BoostPythonGenerator + 0.1 + Binary executable - compile-time + LGPL version 2.1 + + + + Qt Python bindings + 0.1 + Target + LGPL version 2.1 + + + + boost::graph + 1.38.0 + headers and libraries - compile-time and run-time + Boost Software License 1.0 + + + + + + + + + Boost + Qt Software + INdT/Nokia + + + + + diff --git a/sources/shiboken2/doc/faq.rst b/sources/shiboken2/doc/faq.rst new file mode 100644 index 000000000..77e0fbdfc --- /dev/null +++ b/sources/shiboken2/doc/faq.rst @@ -0,0 +1,67 @@ +************************** +Frequently Asked Questions +************************** + +This is a list of Frequently Asked Questions about |project|. Feel free to +suggest new entries! + +General +======= + +What is Shiboken? +----------------- + +Shiboken is a `GeneratorRunner `_ +plugin that outputs C++ code for CPython extensions. The first version of PySide +had source code based on Boost templates. It was easier to produce code but a +paradigm change was needed, as the next question explains. + +Why did you switch from Boost.Python to Shiboken? +------------------------------------------------- + +The main reason was the size reduction. Boost.Python makes excessive use of templates +resulting in a significant increase of the binaries size. On the other hand, as Shiboken +generates CPython code, the resulting binaries are smaller. + +Creating bindings +================= + +Can I wrap non-Qt libraries? +---------------------------- + +Yes. Check Shiboken source code for an example (libsample). + + +Is there any runtime dependency on the generated binding? +--------------------------------------------------------- + +Yes. Only libshiboken, and the obvious Python interpreter +and the C++ library that is being wrapped. + +What do I have to do to create my bindings? +------------------------------------------- + +.. todo: put link to typesystem documentation + +Most of the work is already done by the API Extractor. The developer creates +a `typesystem `_ file +with any customization wanted in the generated code, like removing classes or +changing method signatures. The generator will output the .h and .cpp files +with the CPython code that will wrap the target library for python. + +Is there any recommended build system? +-------------------------------------- + +Both API Extractor and generator uses and recommends the CMake build system. + +Can I write closed-source bindings with the generator? +------------------------------------------------------ + +Yes, as long as you use a LGPL version of Qt, due to runtime requirements. + +What is 'inject code'? +---------------------- + +That's how we call customized code that will be *injected* into the +generated at specific locations. They are specified inside the typesytem. + diff --git a/sources/shiboken2/doc/images/.directory b/sources/shiboken2/doc/images/.directory new file mode 100644 index 000000000..e65475f65 --- /dev/null +++ b/sources/shiboken2/doc/images/.directory @@ -0,0 +1,3 @@ +[Dolphin] +ShowPreview=true +Timestamp=2009,5,5,17,43,26 diff --git a/sources/shiboken2/doc/images/bindinggen-development.png b/sources/shiboken2/doc/images/bindinggen-development.png new file mode 100644 index 000000000..2dd64ba1d Binary files /dev/null and b/sources/shiboken2/doc/images/bindinggen-development.png differ diff --git a/sources/shiboken2/doc/images/bindinggen-development.svg b/sources/shiboken2/doc/images/bindinggen-development.svg new file mode 100644 index 000000000..3b6b3a26e --- /dev/null +++ b/sources/shiboken2/doc/images/bindinggen-development.svg @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + Qt bindings(generated code) + + + + generatorfront-end + + + + + + + + + + + + + API Extractor + + + + 1 + + + + 2 + + + + + + + + + + + typesystem(handwritten) + + + + + + + + + + + injected code(handwritten) + + + + 3 + + + + 4 + + + + diff --git a/sources/shiboken2/doc/images/boostgen.png b/sources/shiboken2/doc/images/boostgen.png new file mode 100644 index 000000000..ae9d9fc3d Binary files /dev/null and b/sources/shiboken2/doc/images/boostgen.png differ diff --git a/sources/shiboken2/doc/images/boostqtarch.png b/sources/shiboken2/doc/images/boostqtarch.png new file mode 100644 index 000000000..f1b145e9c Binary files /dev/null and b/sources/shiboken2/doc/images/boostqtarch.png differ diff --git a/sources/shiboken2/doc/images/boostqtarch.svg b/sources/shiboken2/doc/images/boostqtarch.svg new file mode 100644 index 000000000..9fbb38271 --- /dev/null +++ b/sources/shiboken2/doc/images/boostqtarch.svg @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + Boost::Pythonhelper library to interface with CPython APIand expose C++ entities to Python + + + + Qt-Python BindingsQt classes and functionsexported to Python + + + + + CPythonAPI + + + + Qt4Libraries + + + + + diff --git a/sources/shiboken2/doc/images/converter.dot b/sources/shiboken2/doc/images/converter.dot new file mode 100644 index 000000000..412341df9 --- /dev/null +++ b/sources/shiboken2/doc/images/converter.dot @@ -0,0 +1,14 @@ +digraph Conversions { + rankdir=LR + CppType1 [ label="C++\nType" ] + Converter1 [ label="Converter\nPython -> C++", shape=hexagon ] + PythonType1 -> Converter1 + PythonType2 -> Converter1 + PythonType3 -> Converter1 + Converter1 -> CppType1 + + CppType2 [ label="C++\nType" ] + PythonType4 [ label="PythonType" ] + Converter2 [ label="Converter\nPython -> C++", shape=hexagon ] + CppType2 -> Converter2 -> PythonType4 +} \ No newline at end of file diff --git a/sources/shiboken2/doc/images/converter.png b/sources/shiboken2/doc/images/converter.png new file mode 100644 index 000000000..51cd2af71 Binary files /dev/null and b/sources/shiboken2/doc/images/converter.png differ diff --git a/sources/shiboken2/doc/images/genrunnerarch.png b/sources/shiboken2/doc/images/genrunnerarch.png new file mode 100644 index 000000000..db1077cd0 Binary files /dev/null and b/sources/shiboken2/doc/images/genrunnerarch.png differ diff --git a/sources/shiboken2/doc/images/genrunnerarch.svg b/sources/shiboken2/doc/images/genrunnerarch.svg new file mode 100644 index 000000000..ea7eb73e7 --- /dev/null +++ b/sources/shiboken2/doc/images/genrunnerarch.svg @@ -0,0 +1,654 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + API Extractor + + + ApiExtractorcommands the parsing andbuilding of the data modeland calls the user generators + + + front-end + + Generator Runner + + + Generatorbase class for front-endoutput classes + + + + SpecificGeneratorgenerators written for anydesired output, e.g.: HppGenerator,CppGenerator,ConverterGenerator + + + + + + Generator App* loads generators* setup API Extractor* executes each generator + + + + + + + AbstractMetaBuilderbuilds the data model with informationfrom headers and binding directives + + + + TypeDatabaseparses typesystemand stores information + + + + Parserparses thelib headers + + + + + diff --git a/sources/shiboken2/doc/overview.rst b/sources/shiboken2/doc/overview.rst new file mode 100644 index 000000000..5f50610ff --- /dev/null +++ b/sources/shiboken2/doc/overview.rst @@ -0,0 +1,46 @@ +.. _gen-overview: + +****************** +Generator Overview +****************** + +In a few words, the Generator is a utility that parses a collection of header and +typesystem files, generating other files (code, documentation, etc.) as result. + +Creating new bindings +===================== + +.. figure:: images/bindinggen-development.png + :scale: 80 + :align: center + + Creating new bindings + +Each module of the generator system has an specific role. + +1. Provide enough data about the classes and functions. +2. Generate valid code, with modifications from typesystems and injected codes. +3. Modify the API to expose the objects in a way that fits you target language best. +4. Insert customizations where handwritten code is needed. + +.. figure:: images/boostqtarch.png + :scale: 80 + :align: center + + Runtime architecture + +The newly created binding will run on top of Boost.Python library which takes +care of interfacing Python and the underlying C++ library. + +Handwritten inputs +================== + +Creating new bindings involves creating two pieces of "code": the typesystem and +the inject code. + +:typesystem: XML files that provides the developer with a tool to customize the + way that the generators will see the classes and functions. For + example, functions can be renamed, have its signature changed and + many other actions. +:inject code: allows the developer to insert handwritten code where the generated + code is not suitable or needs some customization. diff --git a/sources/shiboken2/doc/ownership.rst b/sources/shiboken2/doc/ownership.rst new file mode 100644 index 000000000..69791f855 --- /dev/null +++ b/sources/shiboken2/doc/ownership.rst @@ -0,0 +1,153 @@ +**************** +Object ownership +**************** + +One of the main things a binding developer should have in mind is +how the C++ instances lives will cope with Python's reference count. +The last thing you want is to crash a program due to a segfault +when your C++ instance was deleted and the +wrapper object tries to access the invalid memory there. + +In this section we'll show how |project| deals with object ownership +and parentship, taking advantage of the information provided by the +APIExtractor. + +Ownership basics +================ + +As any python binding, |project|-based bindings uses reference counting +to handle the life of the wrapper object (the Python object that contains the +C++ object, do not confuse with the *wrapped* C++ object). +When a reference count reaches zero, the wrapper is deleted by Python garbage +collector and tries to delete the wrapped instance, but sometimes the wrapped +C++ object is already deleted, or maybe the C++ object should not be freed after +the Python wrapper go out of scope and die, because C++ is already taking care of +the wrapped instance. + +In order to handle this, you should tell the +generator whether the instance's ownership belongs to the binding or +to the C++ Library. When belonging to the binding, we are sure that the C++ object +won't be deleted by C++ code and we can call the C++ destructor when the refcount +reaches 0. Otherwise, instances owned by C++ code can be destroyed arbitrarily, +without notifying the Python wrapper of its destruction. + +Invalidating objects +==================== + +To prevent segfaults and double frees, the wrapper objects are invalidated. +An invalidated can't be passed as argument or have an attributte or method accessed. +Trying to do this will raise RuntimeError. + +The following situations can invalidate an object: + +C++ taking ownership +-------------------- + + When an object is passed to a function or method that takes ownership of it, the wrapper + is invalidated as we can't be sure of when the object is destroyed, unless it has a + :ref:`virtual destructor ` or the transfer is due to the special case + of :ref:`parent ownership `. + + Besides being passed as argument, the callee object can have its ownership changed, like + the `setParent` method in Qt's `QObject`. + +Invalidate after use +-------------------- + + Objects marked with *invalidate-after-use* in the type system description always are + virtual method arguments provided by a C++ originated call. They should be + invalidated right after the Python function returns. + +.. _ownership-virt-method: + +Objects with virtual methods +---------------------------- + + A little bit of implementation details: + virtual methods are supported by creating a C++ class, the **shell**, that inherits + from the class with virtual methods, the native one, and override those methods to check if + any derived class in Python also override it. + + If the class has a virtual destructor (and C++ classes with virtual methods should have), this + C++ instance invalidates the wrapper only when the overriden destructor is called. + + One exception to this rule is when the object is created in C++, like in a + factory method. This way the wrapped object is a C++ instance of the native + class, not the shell one, and we cannot know when it is destroyed. + +.. _ownership-parent: + +Parent-child relationship +========================= + +One special type of ownership is the parent-child relationship. +Being a child of an object means that when the object's parent dies, +the C++ instance also dies, so the Python references will be invalidated. +Qt's QObject system, for example, implements this behavior, but this is valid +for any C++ library with similar behavior. + +.. _ownership-parent-heuristics: + +Parentship heuristics +--------------------- + + As the parent-child relationship is very common, |project| tries to automatically + infer what methods falls into the parent-child scheme, adding the extra + directives related to ownership. + + This heuristic will be triggered when generating code for a method and: + + * The function is a constructor. + * The argument name is `parent`. + * The argument type is a pointer to an object. + + When triggered, the heuristic will set the argument named "parent" + as the parent of the object being created by the constructor. + + The main focus of this process was to remove a lot of hand written code from + type system when binding Qt libraries. For Qt, this heuristic works in all cases, + but be aware that it might not when binding your own libraries. + + To activate this heuristic, use the :ref:`--enable-parent-ctor-heuristic ` + command line switch. + +.. _return-value-heuristics: + +Return value heuristics +----------------------- + + When enabled, object returned as pointer in C++ will become child of the object on which the method + was called. + + To activate this heuristic, use the :ref:`--enable-return-value-heuristic ` + +Common pitfalls +=============== + +Not saving unowned objects references +------------------------------------- + + Sometimes when you pass an instance as argument to a method and the receiving + instance will need that object to live indifinitely, but will not take ownership + of the argument instance. In this case, you should hold a reference to the argument + instance. + + For example, let's say that you have a renderer class that will use a source class + in a setSource method but will not take ownership of it. The following code is wrong, + because when `render` is called the `Source` object created during the call to `setSource` + is already destroyed. + + .. code-block:: python + + renderer.setModel(Source()) + renderer.render() + + To solve this, you should hold a reference to the source object, like in + + .. code-block:: python + + source = Source() + renderer.setSource(source) + renderer.render() + + diff --git a/sources/shiboken2/doc/projectfile.rst b/sources/shiboken2/doc/projectfile.rst new file mode 100644 index 000000000..6c9808da4 --- /dev/null +++ b/sources/shiboken2/doc/projectfile.rst @@ -0,0 +1,65 @@ +.. _project-file: + +******************** +Binding Project File +******************** + +Instead of directing the Generator behaviour via command line, the binding developer +can write a text project file describing the same information, and avoid the hassle +of a long stream of command line arguments. + +.. _project-file-structure: + +The project file structure +========================== + +Here follows a comprehensive example of a generator project file. + + .. code-block:: ini + + [generator-project] + generator-set = path/to/generator/CHOICE_GENERATOR + header-file = DIR/global.h" /> + typesystem-file = DIR/typesystem_for_your_binding.xml + output-directory location="OUTPUTDIR" /> + include-path = path/to/library/being/wrapped/headers/1 + include-path = path/to/library/being/wrapped/headers/2 + typesystem-path = path/to/directory/containing/type/system/files/1 + typesystem-path = path/to/directory/containing/type/system/files/2 + enable-parent-ctor-heuristic + + +Project file tags +================= + +The generator project file tags are in direct relation to the +:ref:`command line arguments `. All of the current command line +options provided by |project| were already seen on the :ref:`project-file-structure`, +for new command line options provided by additional generator modules (e.g.: qtdoc, +Shiboken) could also be used in the generator project file following simple conversion rules. + +For tags without options, just write as an empty tag without any attributes. Example: + + .. code-block:: bash + + --BOOLEAN-ARGUMENT + +becomes + + .. code-block:: ini + + BOOLEAN-ARGUMENT + +and + + .. code-block:: bash + + --VALUE-ARGUMENT=VALUE + +becomes + + .. code-block:: ini + + VALUE-ARGUMENT = VALUE + + diff --git a/sources/shiboken2/doc/sequenceprotocol.rst b/sources/shiboken2/doc/sequenceprotocol.rst new file mode 100644 index 000000000..587c0f95b --- /dev/null +++ b/sources/shiboken2/doc/sequenceprotocol.rst @@ -0,0 +1,23 @@ +Sequence Protocol +----------------- + +Support for the sequence protocol is achieved adding functions with special names, this is done using the add-function tag. + +The special function names are: + + ============= =============================================== ==================== =================== + Function name Parameters Return type CPython equivalent + ============= =============================================== ==================== =================== + __len__ PyObject* self Py_ssize_t PySequence_Size + __getitem__ PyObject* self, Py_ssize_t _i PyObject* PySequence_GetItem + __setitem__ PyObject* self, Py_ssize_t _i, PyObject* _value int PySequence_SetItem + __contains__ PyObject* self, PyObject* _value int PySequence_Contains + __concat__ PyObject* self, PyObject* _other PyObject* PySequence_Concat + ============= =============================================== ==================== =================== + +You just need to inform the function name to the add-function tag, without any parameter or return type information, when you do it, |project| will create a C function with parameters and return type definied by the table above. + +The function needs to follow the same semantics of the *CPython equivalent* function, the only way to do it is using the :doc:`inject-code ` tag. + +A concrete exemple how to add sequence protocol support to a class can be found on shiboken tests, more precisely in the definition of the Str class in ``tests/samplebinding/typesystem_sample.xml``. + diff --git a/sources/shiboken2/doc/shiboken2.1 b/sources/shiboken2/doc/shiboken2.1 new file mode 100644 index 000000000..e017bd9a9 --- /dev/null +++ b/sources/shiboken2/doc/shiboken2.1 @@ -0,0 +1,73 @@ +.TH SHIBOKEN "1" "March 2010" "shiboken v0.2.0" "User Commands" +.SH NAME +shiboken \- CPython bindings generator for C++ libraries +.SH DESCRIPTION +.SS "Usage:" +.IP +shiboken [options] header\-file typesystem\-file +.SS "General options:" +.TP +\fB\-\-debug\-level\fR=\fI[sparse\fR|medium|full] +Set the debug level +.TP +\fB\-\-documentation\-only\fR +Do not generates any code, just the documentation +.TP +\fB\-\-generatorSet\fR +generatorSet to be used. e.g. qtdoc +.TP +\fB\-\-help\fR +Display this help and exit +.TP +\fB\-\-include\-paths=\fR[::...] +Include paths used by the C++ parser +.TP +\fB\-\-license\-file\fR=\fI[licensefile]\fR +File used for copyright headers of generated files +.TP +\fB\-\-no\-suppress\-warnings\fR +Show all warnings +.TP +\fB\-\-output\-directory\fR=\fI[dir]\fR +The directory where the generated files will be written +.TP +\fB\-\-silent\fR +Avoid printing any message +.TP +\fB\-\-typesystem\-paths=\fR[::...] +Paths used when searching for typesystems +.TP +\fB\-\-version\fR +Output version information and exit +.SS "Shiboken options:" +.TP +\fB\-\-disable\-verbose\-error\-messages\fR +Disable verbose error messages. Turn the python code hard to debug but safe few kB on the generated bindings. +.TP +\fB\-\-enable\-parent\-ctor\-heuristic\fR +Enable heuristics to detect parent relationship on constructors. +.TP +\fB\-\-enable\-pyside\-extensions\fR +Enable PySide extensions, such as support for signal/slots, use this if you are creating a binding for a Qt\-based library. +.TP +\fB\-\-enable\-return\-value\-heuristic\fR +Enable heuristics to detect parent relationship on return values (USE WITH CAUTION!) +.SS "Shiboken options:" +.TP +\fB\-\-disable\-verbose\-error\-messages\fR +Disable verbose error messages. Turn the python code hard to debug but safe few kB on the generated bindings. +.TP +\fB\-\-enable\-parent\-ctor\-heuristic\fR +Enable heuristics to detect parent relationship on constructors. +.TP +\fB\-\-enable\-pyside\-extensions\fR +Enable PySide extensions, such as support for signal/slots, use this if you are creating a binding for a Qt\-based library. +.TP +\fB\-\-enable\-return\-value\-heuristic\fR +Enable heuristics to detect parent relationship on return values (USE WITH CAUTION!) +.SH COPYRIGHT +Copyright \(co 2016 The Qt Company Ltd. +.SH AUTHOR +.PP +This manpage was written for Debian, starting with a help2man output, by +Didier Raboud , on the 26. March 2010. diff --git a/sources/shiboken2/doc/shibokenmodule.rst b/sources/shiboken2/doc/shibokenmodule.rst new file mode 100644 index 000000000..150998ccd --- /dev/null +++ b/sources/shiboken2/doc/shibokenmodule.rst @@ -0,0 +1,79 @@ +.. module:: shiboken + +.. |maya| unicode:: Maya U+2122 + +Shiboken module +*************** + +Functions +^^^^^^^^^ + +.. container:: function_list + + * def :meth:`isValid` (obj) + * def :meth:`wrapInstance` (address, type) + * def :meth:`getCppPointer` (obj) + * def :meth:`delete` (obj) + * def :meth:`isOwnedByPython` (obj) + * def :meth:`wasCreatedByPython` (obj) + * def :meth:`dump` (obj) + +Detailed description +^^^^^^^^^^^^^^^^^^^^ + +This Python module can be used to access internal information related to our +binding technology. Access to this internal information is required to e.g.: +integrate PySide with Qt based programs that offer Python scripting like |maya| +or just for debug purposes. + +Some function description refer to "Shiboken based objects", wich means +Python objects instances of any Python Type created using Shiboken. + + +.. function:: isValid(obj) + + Given a Python object, returns True if the object methods can be called + without an exception being thrown. A Python wrapper becomes invalid when + the underlying C++ object is destroyed or unreachable. + +.. function:: wrapInstance(address, type) + + Creates a Python wrapper for a C++ object instantiated at a given memory + address - the returned object type will be the same given by the user. + + The type must be a Shiboken type, the C++ object will not be + destroyed when the returned Python object reach zero references. + + If the address is invalid or doesn't point to a C++ object of given type + the behavior is undefined. + +.. function:: getCppPointer(obj) + + Returns a tuple of longs that contain the memory addresses of the + C++ instances wrapped by the given object. + +.. function:: delete(obj) + + Deletes the C++ object wrapped by the given Python object. + +.. function:: isOwnedByPython(obj) + + Given a Python object, returns True if Python is responsible for deleting + the underlying C++ object, False otherwise. + + If the object was not a Shiboken based object, a TypeError is + thrown. + +.. function:: wasCreatedByPython(obj) + + Returns true if the given Python object was created by Python. + +.. function:: dump(obj) + + Returns a string with implementation-defined information about the + object. + This method should be used **only** for debug purposes by developers + creating their own bindings as no guarantee is provided that + the string format will be the same across different versions. + + If the object is not a Shiboken based object, a TypeError is thrown. diff --git a/sources/shiboken2/doc/typeconverters.rst b/sources/shiboken2/doc/typeconverters.rst new file mode 100644 index 000000000..3779b26d7 --- /dev/null +++ b/sources/shiboken2/doc/typeconverters.rst @@ -0,0 +1,288 @@ +**************************** +User Defined Type Conversion +**************************** + +In the process of creating Python bindings of a C++ library, most of the C++ classes will have wrappers representing them in Python land. But there may be other classes that are very simple and/or have a Python type as a direct counter part. (Example: a "Complex" class, that represents complex numbers, has a Python equivalent in the "complex" type.) Such classes, instead of getting a Python wrapper, normally have conversions rules, from Python to C++ and vice-versa. + + .. code-block:: c++ + + // C++ class + struct Complex { + Complex(double real, double imag); + double real() const; + double imag() const; + }; + + // Converting from C++ to Python using the CPython API: + PyObject* pyCpxObj = PyComplex_FromDoubles(complex.real(), complex.imag()); + + // Converting from Python to C++: + double real = PyComplex_RealAsDouble(pyCpxObj); + double imag = PyComplex_ImagAsDouble(pyCpxObj); + Complex cpx(real, imag); + + +For the user defined conversion code to be inserted in the proper places, the "" tag must be used. + + .. code-block:: xml + + + + + + + + return PyComplex_FromDoubles(%in.real(), %in.imag()); + + + + + + double real = PyComplex_RealAsDouble(%in); + double imag = PyComplex_ImagAsDouble(%in); + %out = %OUTTYPE(real, imag); + + + + + + + + +The details will be given later, but the gist of it are the tags +` `_, +which has only one conversion from C++ to Python, and +` `_, +that may define the conversion of multiple Python types to C++'s "Complex" type. + +.. image:: images/converter.png + :height: 240px + :align: center + +|project| expects the code for ` `_, +to directly return the Python result of the conversion, and the added conversions inside the +` `_ +must attribute the Python to C++ conversion result to the :ref:`%out ` variable. + + +Expanding on the last example, if the binding developer want a Python 2-tuple of numbers to be accepted +by wrapped C++ functions with "Complex" arguments, an +` `_ +tag and a custom check must be added. Here's how to do it: + + .. code-block:: xml + + + + static bool Check2TupleOfNumbers(PyObject* pyIn) { + if (!PySequence_Check(pyIn) || !(PySequence_Size(pyIn) == 2)) + return false; + Shiboken::AutoDecRef pyReal(PySequence_GetItem(pyIn, 0)); + if (!SbkNumber_Check(pyReal)) + return false; + Shiboken::AutoDecRef pyImag(PySequence_GetItem(pyIn, 1)); + if (!SbkNumber_Check(pyImag)) + return false; + return true; + } + + + + + + + + + return PyComplex_FromDoubles(%in.real(), %in.imag()); + + + + + + double real = PyComplex_RealAsDouble(%in); + double imag = PyComplex_ImagAsDouble(%in); + %out = %OUTTYPE(real, imag); + + + + Shiboken::AutoDecRef pyReal(PySequence_GetItem(%in, 0)); + Shiboken::AutoDecRef pyImag(PySequence_GetItem(%in, 1)); + double real = %CONVERTTOCPP[double](pyReal); + double imag = %CONVERTTOCPP[double](pyImag); + %out = %OUTTYPE(real, imag); + + + + + + + + + + +.. _container_conversions: + +Container Conversions +===================== + +Converters for +` `_ +are pretty much the same as for other type, except that they make use of the type system variables +:ref:`%INTYPE_# ` and :ref:`%OUTTYPE_# `. |project| combines the conversion code for +containers with the conversion defined (or automatically generated) for the containees. + + + .. code-block:: xml + + + + + + + + PyObject* %out = PyDict_New(); + %INTYPE::const_iterator it = %in.begin(); + for (; it != %in.end(); ++it) { + %INTYPE_0 key = it->first; + %INTYPE_1 value = it->second; + PyDict_SetItem(%out, + %CONVERTTOPYTHON[%INTYPE_0](key), + %CONVERTTOPYTHON[%INTYPE_1](value)); + } + return %out; + + + + + + PyObject* key; + PyObject* value; + Py_ssize_t pos = 0; + while (PyDict_Next(%in, &pos, &key, &value)) { + %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key); + %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value); + %out.insert(%OUTTYPE::value_type(cppKey, cppValue)); + } + + + + + + + +.. _variables_and_functions: + +Variables & Functions +===================== + + +.. _in: + +**%in** + + Variable replaced by the C++ input variable. + + +.. _out: + +**%out** + + Variable replaced by the C++ output variable. Needed to convey the + result of a Python to C++ conversion. + + +.. _intype: + +**%INTYPE** + + Used in Python to C++ conversions. It is replaced by the name of type for + which the conversion is being defined. Don't use the type's name directly. + + +.. _intype_n: + +**%INTYPE_#** + + Replaced by the name of the #th type used in a container. + + +.. _outtype: + +**%OUTTYPE** + + Used in Python to C++ conversions. It is replaced by the name of type for + which the conversion is being defined. Don't use the type's name directly. + + +.. _outtype_n: + +**%OUTTYPE_#** + + Replaced by the name of the #th type used in a container. + + +.. _checktype: + +**%CHECKTYPE[CPPTYPE]** + + Replaced by a |project| type checking function for a Python variable. + The C++ type is indicated by ``CPPTYPE``. + + +.. _oldconverters: + +Converting The Old Converters +============================= + +If you use |project| for your bindings, and has defined some type conversions +using the ``Shiboken::Converter`` template, then you must update your converters +to the new scheme. + +Previously your conversion rules were declared in one line, like this: + + + .. code-block:: xml + + + + + + + +And implemented in a separate C++ file, like this: + + + .. code-block:: c++ + + namespace Shiboken { + template<> struct Converter + { + static inline bool checkType(PyObject* pyObj) { + return PyComplex_Check(pyObj); + } + static inline bool isConvertible(PyObject* pyObj) { + return PyComplex_Check(pyObj); + } + static inline PyObject* toPython(void* cppobj) { + return toPython(*reinterpret_cast(cppobj)); + } + static inline PyObject* toPython(const Complex& cpx) { + return PyComplex_FromDoubles(cpx.real(), cpx.imag()); + } + static inline Complex toCpp(PyObject* pyobj) { + double real = PyComplex_RealAsDouble(pyobj); + double imag = PyComplex_ImagAsDouble(pyobj); + return Complex(real, imag); + } + }; + } + + +In this case, the parts of the implementation that will be used in the new conversion-rule +are the ones in the two last method ``static inline PyObject* toPython(const Complex& cpx)`` +and ``static inline Complex toCpp(PyObject* pyobj)``. The ``isConvertible`` method is gone, +and the ``checkType`` is now an attribute of the +` `_ +tag. Refer back to the first example in this page and you will be able to correlate the above template +with the new scheme of conversion rule definition. diff --git a/sources/shiboken2/doc/typesystemvariables.rst b/sources/shiboken2/doc/typesystemvariables.rst new file mode 100644 index 000000000..205430550 --- /dev/null +++ b/sources/shiboken2/doc/typesystemvariables.rst @@ -0,0 +1,336 @@ +********************* +Type System Variables +********************* + +User written code can be placed in arbitrary places using the +:doc:`inject-code ` tag. To ease the binding developer +work, the injected code can make use of special variables that will be replaced +by the correct values. This also shields the developer from some |project| +implementation specifics. + + +.. _variables: + +Variables +========= + + +.. _cpp_return_argument: + +**%0** + + Replaced by the C++ return variable of the Python method/function wrapper. + + +.. _arg_number: + +**%#** + + Replaced by the name of a C++ argument in the position indicated by ``#``. + The argument counting starts with ``%1``, since ``%0`` represents the return + variable name. If the number indicates a variable that was removed in the + type system description, but there is a default value for it, this value will + be used. Consider this example: + + .. code-block:: c++ + + void argRemoval(int a0, int a1 = 123); + + + .. code-block:: xml + + + + + + + + The ``%1`` will be replaced by the C++ argument name, and ``%2`` will get the + value ``123``. + + +.. _argument_names: + +**%ARGUMENT_NAMES** + + Replaced by a comma separated list with the names of all C++ arguments that + were not removed on the type system description for the method/function. When + the removed argument has a default value (original or provided in the type + system), this value will be inserted in the argument list. If you want to remove + the argument so completely that it doesn't appear in any form on the + ``%ARGUMENT_NAMES`` replacement, don't forget to remove also its default value + with the ` + `_ + type system tag. + + Take the following method and related type system description as an example: + + .. code-block:: c++ + + void argRemoval(int a0, Point a1 = Point(1, 2), bool a2 = true, Point a3 = Point(3, 4), int a4 = 56); + + + .. code-block:: xml + + + + + + + + + + + + As seen on the XML description, the function's ``a1`` and ``a3`` arguments + were removed. If any ``inject-code`` for this function uses ``%ARGUMENT_NAMES`` + the resulting list will be the equivalent of using individual argument type + system variables this way: + + .. code-block:: c++ + + %1, Point(6, 9), %3, Point(3, 4), %5 + + +.. _arg_type: + +**%ARG#_TYPE** + + Replaced by the type of a C++ argument in the position indicated by ``#``. + The argument counting starts with ``%1``, since ``%0`` represents the return + variable in other contexts, but ``%ARG0_TYPE`` will not translate to the + return type, as this is already done by the + :ref:`%RETURN_TYPE ` variable. + Example: + + .. code-block:: c++ + + void argRemoval(int a0, int a1 = 123); + + + .. code-block:: xml + + + + + + + + The ``%1`` will be replaced by the C++ argument name, and ``%2`` will get the + value ``123``. + + +.. _converttocpp: + +**%CONVERTTOCPP[CPPTYPE]** + + Replaced by a |project| conversion call that converts a Python variable + to a C++ variable of the type indicated by ``CPPTYPE``. + + +.. _converttopython: + +**%CONVERTTOPYTHON[CPPTYPE]** + + Replaced by a |project| conversion call that converts a C++ variable of the + type indicated by ``CPPTYPE`` to the proper Python object. + + +.. _isconvertible: + +**%ISCONVERTIBLE[CPPTYPE]** + + Replaced by a |project| "isConvertible" call that checks if a Python + variable is convertible (via an implicit conversion or cast operator call) + to a C++ variable of the type indicated by ``CPPTYPE``. + + +.. _checktype: + +**%CHECKTYPE[CPPTYPE]** + + Replaced by a |project| "checkType" call that verifies if a Python + if of the type indicated by ``CPPTYPE``. + + +.. _cppself: + +**%CPPSELF** + + Replaced by the wrapped C++ object instance that owns the method in which the + code with this variable was inserted. + +.. _cpptype: + +**%CPPTYPE** + + Replaced by the original name of the C++ class, without any namespace prefix, + that owns the method in which the code with this variable was inserted. It will + work on class level code injections also. Notice that ``CPPTYPE`` differs from + the :ref:`%TYPE ` variable, for this latter may be translated to the original + C++ class name or to the C++ wrapper class name. + + Namespaces will are treated as classes, so ``CPPTYPE`` will work for them and their + enclosed functions as well. + +.. _function_name: + +**%FUNCTION_NAME** + + Replaced by the name of a function or method. + + + +.. _py_return_argument: + +**%PYARG_0** + + Replaced by the name of the Python return variable of the Python method/function wrapper. + + +.. _pyarg: + +**%PYARG_#** + + Similar to ``%#``, but is replaced by the Python arguments (PyObjects) + received by the Python wrapper method. + + If used in the context of a native code injection, i.e. in a virtual method + override, ``%PYARG_#`` will be translated to one item of the Python tuple + holding the arguments that should be passed to the Python override for this + virtual method. + + The example + + .. code-block:: c++ + + long a = PyInt_AS_LONG(%PYARG_1); + + + is equivalent of + + .. code-block:: c++ + + long a = PyInt_AS_LONG(PyTuple_GET_ITEM(%PYTHON_ARGUMENTS, 0)); + + + The generator tries to be smart with attributions, but it will work for the + only simplest cases. + + This example + + .. code-block:: c++ + + Py_DECREF(%PYARG_1); + %PYARG_1 = PyInt_FromLong(10); + + + is equivalent of + + .. code-block:: c++ + + Py_DECREF(PyTuple_GET_ITEM(%PYTHON_ARGUMENTS, 0)); + PyTuple_SET_ITEM(%PYTHON_ARGUMENTS, 0, PyInt_FromLong(10)); + + +.. _pyself: + +**%PYSELF** + + Replaced by the Python wrapper variable (a PyObject) representing the instance + bounded to the Python wrapper method which receives the custom code. + + +.. _python_arguments: + +**%PYTHON_ARGUMENTS** + + Replaced by the pointer to the Python tuple with Python objects converted from + the C++ arguments received on the binding override of a virtual method. + This tuple is the same passed as arguments to the Python method overriding the + C++ parent's one. + + +.. _python_method_override: + +**%PYTHON_METHOD_OVERRIDE** + + This variable is used only on :ref:`native method code injections + `, i.e. on the binding overrides for C++ virtual + methods. It is replaced by a pointer to the Python method override. + + +.. _pythontypeobject: + +**%PYTHONTYPEOBJECT** + + Replaced by the Python type object for the context in which it is inserted: + method or class modification. + + +.. _beginallowthreads: + +**%BEGIN_ALLOW_THREADS** + + Replaced by a thread state saving procedure. + Must match with a :ref:`%END_ALLOW_THREADS ` variable. + + +.. _endallowthreads: + +**%END_ALLOW_THREADS** + + Replaced by a thread state restoring procedure. + Must match with a :ref:`%BEGIN_ALLOW_THREADS ` variable. + + +.. _return_type: + +**%RETURN_TYPE** + + Replaced by the type returned by a function or method. + + +.. _type: + +**%TYPE** + + Replaced by the name of the class to which a function belongs. May be used + in code injected at method or class level. + + +.. _example: + +Example +======= + +Just to illustrate the usage of the variables described in the previous +sections, below is an excerpt from the type system description of a |project| +test. It changes a method that received ``argc/argv`` arguments into something +that expects a Python sequence instead. + + .. code-block:: xml + + + + + + + + + + int argc; + char** argv; + if (!PySequence_to_argc_argv(%PYARG_1, &argc, &argv)) { + PyErr_SetString(PyExc_TypeError, "error"); + return 0; + } + %RETURN_TYPE foo = %CPPSELF.%FUNCTION_NAME(argc, argv); + %0 = %CONVERTTOPYTHON[%RETURN_TYPE](foo); + + for (int i = 0; i < argc; ++i) + delete[] argv[i]; + delete[] argv; + + + diff --git a/sources/shiboken2/doc/wordsofadvice.rst b/sources/shiboken2/doc/wordsofadvice.rst new file mode 100644 index 000000000..b66799338 --- /dev/null +++ b/sources/shiboken2/doc/wordsofadvice.rst @@ -0,0 +1,109 @@ +.. _words-of-advice: + +*************** +Words of Advice +*************** + +When writing or using Python bindings there is some things you must keep in mind. + + +.. _duck-punching-and-virtual-methods: + +Duck punching and virtual methods +================================= + +The combination of duck punching, the practice of altering class characteristics +of already instantiated objects, and virtual methods of wrapped C++ classes, can +be tricky. That was an optimistic statement. + +Let's see duck punching in action for educational purposes. + + .. code-block:: python + + import types + import Binding + + obj = Binding.CppClass() + + # CppClass has a virtual method called 'virtualMethod', + # but we don't like it anymore. + def myVirtualMethod(self_obj, arg): + pass + + obj.virtualMethod = types.MethodType(myVirtualMethod, obj, Binding.CppClass) + + +If some C++ code happens to call `CppClass::virtualMethod(...)` on the C++ object +held by "obj" Python object, the new duck punched "virtualMethod" method will be +properly called. That happens because the underlying C++ object is in fact an instance +of a generated C++ class that inherits from `CppClass`, let's call it `CppClassWrapper`, +responsible for receiving the C++ virtual method calls and finding out the proper Python +override to which handle such a call. + +Now that you know this, consider the case when C++ has a factory method that gives you +new C++ objects originated somewhere in C++-land, in opposition to the ones generated in +Python-land by the usage of class constructors, like in the example above. + +Brief interruption to show what I was saying: + + .. code-block:: python + + import types + import Binding + + obj = Binding.createCppClass() + def myVirtualMethod(self_obj, arg): + pass + + # Punching a dead duck... + obj.virtualMethod = types.MethodType(myVirtualMethod, obj, Binding.CppClass) + + +The `Binding.createCppClass()` factory method is just an example, C++ created objects +can pop out for a number of other reasons. Objects created this way have a Python wrapper +holding them as usual, but the object held is not a `CppClassWrapper`, but a regular +`CppClass`. All virtual method calls originated in C++ will stay in C++ and never reach +a Python virtual method overridden via duck punching. + +Although duck punching is an interesting Python feature, it don't mix well with wrapped +C++ virtual methods, specially when you can't tell the origin of every single wrapped +C++ object. In summary: don't do it! + + +.. _pyside-old-style-class: + +Python old style classes and PySide +=================================== + +Because of some architectural decisions and deprecated Python types. Since PySide 1.1 old style classes are not supported with multiple inheritance. + +Below you can check the examples: + +Example with old style class: + + .. code-block:: python + + from PySide2 import QtCore + + class MyOldStyleObject: + pass + + class MyObject(QtCore, MyOldStyleObject): + pass + + +this example will raise a 'TypeError' due to the limitation on PySide, to fix this you will need use the new style class: + + + .. code-block:: python + + from PySide2 import QtCore + + class MyOldStyleObject(object): + pass + + class MyObject(QtCore, MyOldStyleObject): + pass + + +All classes used for multiple inheritance with other PySide types need to have 'object' as base class. diff --git a/sources/shiboken2/generator/CMakeLists.txt b/sources/shiboken2/generator/CMakeLists.txt new file mode 100644 index 000000000..032118666 --- /dev/null +++ b/sources/shiboken2/generator/CMakeLists.txt @@ -0,0 +1,40 @@ +project(shibokengenerator) + +find_package(Qt5Xml) +find_package(Qt5XmlPatterns) + +set(shiboken2_SRC +generator.cpp +shiboken2/cppgenerator.cpp +shiboken2/headergenerator.cpp +shiboken2/overloaddata.cpp +shiboken2/shibokengenerator.cpp +main.cpp +) + +if (NOT DISABLE_DOCSTRINGS) + set(shiboken2_SRC ${shiboken2_SRC} qtdoc/qtdocgenerator.cpp) + add_definitions(-DDOCSTRINGS_ENABLED) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shiboken2 + ${CMAKE_CURRENT_SOURCE_DIR}/qtdoc + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${apiextractor_SOURCE_DIR} + ${Qt5Core_INCLUDE_DIRS} + ${Qt5XmlPatterns_INCLUDE_DIRS} + ) + +add_executable(shiboken2 ${shiboken2_SRC}) +add_dependencies(shiboken2 apiextractor) +set_target_properties(shiboken2 PROPERTIES OUTPUT_NAME shiboken2${shiboken2_SUFFIX}) +target_link_libraries(shiboken2 + apiextractor + ${Qt5Core_LIBRARIES} + ${Qt5XmlPatterns_LIBRARIES} + ) + +configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY) + +install(TARGETS shiboken2 DESTINATION bin) diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp new file mode 100644 index 000000000..76d104c12 --- /dev/null +++ b/sources/shiboken2/generator/generator.cpp @@ -0,0 +1,864 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "generator.h" +#include "abstractmetalang.h" +#include "reporthandler.h" +#include "fileout.h" +#include "apiextractor.h" +#include "typesystem.h" + +#include +#include +#include +#include +#include +#include + +struct Generator::GeneratorPrivate { + const ApiExtractor* apiextractor; + QString outDir; + // License comment + QString licenseComment; + QString packageName; + int numGenerated; + QStringList instantiatedContainersNames; + QStringList instantiatedSmartPointerNames; + QVector instantiatedContainers; + QVector instantiatedSmartPointers; + +}; + +Generator::Generator() : m_d(new GeneratorPrivate) +{ + m_d->numGenerated = 0; +} + +Generator::~Generator() +{ + delete m_d; +} + +bool Generator::setup(const ApiExtractor& extractor, const QMap< QString, QString > args) +{ + m_d->apiextractor = &extractor; + TypeEntryHash allEntries = TypeDatabase::instance()->allEntries(); + 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) + break; + } + if (entryFound) + m_d->packageName = entryFound->name(); + else + qCWarning(lcShiboken) << "Couldn't find the package name!!"; + + collectInstantiatedContainersAndSmartPointers(); + + return doSetup(args); +} + +QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType* type) +{ + const QString signature = type->cppSignature(); + if (!type->typeEntry()->isContainer() && !type->typeEntry()->isSmartPointer()) + return signature; + QString typeName = signature; + if (type->isConstant()) + typeName.remove(0, sizeof("const ") / sizeof(char) - 1); + switch (type->referenceType()) { + case NoReference: + break; + case LValueReference: + typeName.chop(1); + break; + case RValueReference: + typeName.chop(2); + break; + } + while (typeName.endsWith(QLatin1Char('*')) || typeName.endsWith(QLatin1Char(' '))) + typeName.chop(1); + return typeName; +} + +void Generator::addInstantiatedContainersAndSmartPointers(const AbstractMetaType *type, + const QString &context) +{ + if (!type) + return; + const AbstractMetaTypeList &instantiations = type->instantiations(); + for (const AbstractMetaType* t : instantiations) + addInstantiatedContainersAndSmartPointers(t, context); + if (!type->typeEntry()->isContainer() && !type->typeEntry()->isSmartPointer()) + return; + bool isContainer = type->typeEntry()->isContainer(); + if (type->hasTemplateChildren()) { + QString piece = isContainer ? QStringLiteral("container") : QStringLiteral("smart pointer"); + QString warning = + QString::fromLatin1("Skipping instantiation of %1 '%2' because it has template" + " arguments.").arg(piece).arg(type->originalTypeDescription()); + if (!context.isEmpty()) + warning.append(QStringLiteral(" Calling context: %1").arg(context)); + + qCWarning(lcShiboken).noquote().nospace() << warning; + return; + + } + QString typeName = getSimplifiedContainerTypeName(type); + if (isContainer) { + if (!m_d->instantiatedContainersNames.contains(typeName)) { + m_d->instantiatedContainersNames.append(typeName); + m_d->instantiatedContainers.append(type); + } + } else { + // Is smart pointer. + if (!m_d->instantiatedSmartPointerNames.contains(typeName)) { + m_d->instantiatedSmartPointerNames.append(typeName); + m_d->instantiatedSmartPointers.append(type); + } + } + +} + +void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction *func) +{ + addInstantiatedContainersAndSmartPointers(func->type(), func->signature()); + const AbstractMetaArgumentList &arguments = func->arguments(); + for (const AbstractMetaArgument *arg : arguments) + addInstantiatedContainersAndSmartPointers(arg->type(), func->signature()); +} + +void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass) +{ + if (!metaClass->typeEntry()->generateCode()) + return; + const AbstractMetaFunctionList &funcs = metaClass->functions(); + for (const AbstractMetaFunction *func : funcs) + collectInstantiatedContainersAndSmartPointers(func); + const AbstractMetaFieldList &fields = metaClass->fields(); + for (const AbstractMetaField *field : fields) + addInstantiatedContainersAndSmartPointers(field->type(), field->name()); + const AbstractMetaClassList &innerClasses = metaClass->innerClasses(); + for (AbstractMetaClass *innerClass : innerClasses) + collectInstantiatedContainersAndSmartPointers(innerClass); +} + +void Generator::collectInstantiatedContainersAndSmartPointers() +{ + const AbstractMetaFunctionList &funcs = globalFunctions(); + for (const AbstractMetaFunction *func : funcs) + collectInstantiatedContainersAndSmartPointers(func); + const AbstractMetaClassList &classList = classes(); + for (const AbstractMetaClass *metaClass : classList) + collectInstantiatedContainersAndSmartPointers(metaClass); +} + +QVector Generator::instantiatedContainers() const +{ + return m_d->instantiatedContainers; +} + +QVector Generator::instantiatedSmartPointers() const +{ + return m_d->instantiatedSmartPointers; +} + +QMap< QString, QString > Generator::options() const +{ + return QMap(); +} + +AbstractMetaClassList Generator::classes() const +{ + return m_d->apiextractor->classes(); +} + +AbstractMetaClassList Generator::classesTopologicalSorted(const Dependencies &additionalDependencies) const +{ + return m_d->apiextractor->classesTopologicalSorted(additionalDependencies); +} + +AbstractMetaFunctionList Generator::globalFunctions() const +{ + return m_d->apiextractor->globalFunctions(); +} + +AbstractMetaEnumList Generator::globalEnums() const +{ + return m_d->apiextractor->globalEnums(); +} + +PrimitiveTypeEntryList Generator::primitiveTypes() const +{ + return m_d->apiextractor->primitiveTypes(); +} + +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); +} + +QSet< QString > Generator::qtMetaTypeDeclaredTypeNames() const +{ + return m_d->apiextractor->qtMetaTypeDeclaredTypeNames(); +} + +QString Generator::licenseComment() const +{ + return m_d->licenseComment; +} + +void Generator::setLicenseComment(const QString& licenseComment) +{ + m_d->licenseComment = licenseComment; +} + +QString Generator::packageName() const +{ + return m_d->packageName; +} + +QString Generator::moduleName() const +{ + QString& pkgName = m_d->packageName; + return QString(pkgName).remove(0, pkgName.lastIndexOf(QLatin1Char('.')) + 1); +} + +QString Generator::outputDirectory() const +{ + return m_d->outDir; +} + +void Generator::setOutputDirectory(const QString &outDir) +{ + m_d->outDir = outDir; +} + +int Generator::numGenerated() const +{ + return m_d->numGenerated; +} + +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(); + + if (!shouldGenerate(cls)) + return true; + + const QString fileName = fileNameForContext(context); + if (fileName.isEmpty()) + return true; + if (ReportHandler::isDebug(ReportHandler::SparseDebug)) + qCDebug(lcShiboken) << "generating: " << fileName; + + QString filePath = outputDirectory() + QLatin1Char('/') + subDirectoryForClass(cls) + + QLatin1Char('/') + fileName; + FileOut fileOut(filePath); + + generateClass(fileOut.stream, context); + + FileOut::State state = fileOut.done(); + switch (state) { + case FileOut::Failure: + return false; + case FileOut::Unchanged: + // Even if contents is unchanged, the last file modification time should be updated, + // so that the build system can rely on the fact the generated file is up-to-date. + touchFile(filePath); + break; + case FileOut::Success: + break; + } + + ++m_d->numGenerated; + return true; +} + +QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType, + const AbstractMetaClass *smartPointerClass) const +{ + const AbstractMetaType *innerType = smartPointerType->getSmartPointerInnerType(); + QString fileName = smartPointerClass->qualifiedCppName().toLower(); + fileName.replace(QLatin1String("::"), QLatin1String("_")); + fileName.append(QLatin1String("_")); + fileName.append(innerType->name().toLower()); + + return fileName; +} + +bool Generator::generate() +{ + const AbstractMetaClassList &classList = m_d->apiextractor->classes(); + for (AbstractMetaClass *cls : classList) { + GeneratorContext context(cls); + if (!generateFileForContext(context)) + return false; + } + + for (const AbstractMetaType *type : qAsConst(m_d->instantiatedSmartPointers)) { + AbstractMetaClass *smartPointerClass = + AbstractMetaClass::findClass(m_d->apiextractor->smartPointers(), type->name()); + GeneratorContext context(smartPointerClass, type, true); + if (!generateFileForContext(context)) + return false; + } + return finishGeneration(); +} + +bool Generator::shouldGenerateTypeEntry(const TypeEntry* type) const +{ + return type->codeGeneration() & TypeEntry::GenerateTargetLang; +} + +bool Generator::shouldGenerate(const AbstractMetaClass* metaClass) const +{ + return shouldGenerateTypeEntry(metaClass->typeEntry()); +} + +void verifyDirectoryFor(const QFile &file) +{ + QDir dir = QFileInfo(file).dir(); + if (!dir.exists()) { + if (!dir.mkpath(dir.absolutePath())) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("unable to create directory '%1'").arg(dir.absolutePath()); + } + } +} + +void Generator::replaceTemplateVariables(QString &code, const AbstractMetaFunction *func) +{ + const AbstractMetaClass *cpp_class = func->ownerClass(); + if (cpp_class) + code.replace(QLatin1String("%TYPE"), cpp_class->name()); + + const AbstractMetaArgumentList &argument = func->arguments(); + for (AbstractMetaArgument *arg : argument) + code.replace(QLatin1Char('%') + QString::number(arg->argumentIndex() + 1), arg->name()); + + //template values + code.replace(QLatin1String("%RETURN_TYPE"), translateType(func->type(), cpp_class)); + code.replace(QLatin1String("%FUNCTION_NAME"), func->originalName()); + + if (code.contains(QLatin1String("%ARGUMENT_NAMES"))) { + QString str; + QTextStream aux_stream(&str); + writeArgumentNames(aux_stream, func, Generator::SkipRemovedArguments); + code.replace(QLatin1String("%ARGUMENT_NAMES"), str); + } + + if (code.contains(QLatin1String("%ARGUMENTS"))) { + QString str; + QTextStream aux_stream(&str); + writeFunctionArguments(aux_stream, func, Options(SkipDefaultValues) | SkipRemovedArguments); + code.replace(QLatin1String("%ARGUMENTS"), str); + } +} + +QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor) +{ + // detect number of spaces before the first character + const QStringList lst(code.split(QLatin1Char('\n'))); + static const QRegularExpression nonSpaceRegex(QStringLiteral("[^\\s]")); + Q_ASSERT(nonSpaceRegex.isValid()); + int spacesToRemove = 0; + for (const QString &line : lst) { + if (!line.trimmed().isEmpty()) { + spacesToRemove = line.indexOf(nonSpaceRegex); + if (spacesToRemove == -1) + spacesToRemove = 0; + break; + } + } + + static const QRegularExpression emptyLine(QStringLiteral("^\\s*[\\r]?[\\n]?\\s*$")); + Q_ASSERT(emptyLine.isValid()); + + for (QString line : lst) { + if (!line.isEmpty() && !emptyLine.match(line).hasMatch()) { + while (line.end()->isSpace()) + line.chop(1); + int limit = 0; + for(int i = 0; i < spacesToRemove; ++i) { + if (!line[i].isSpace()) + break; + limit++; + } + + s << indentor << line.remove(0, limit); + } + s << endl; + } + return s; +} + +AbstractMetaFunctionList Generator::implicitConversions(const TypeEntry* type) const +{ + if (type->isValue()) { + if (const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), type)) + return metaClass->implicitConversions(); + } + return AbstractMetaFunctionList(); +} + +AbstractMetaFunctionList Generator::implicitConversions(const AbstractMetaType* metaType) const +{ + return implicitConversions(metaType->typeEntry()); +} + +bool Generator::isObjectType(const TypeEntry* type) +{ + if (type->isComplex()) + return Generator::isObjectType((const ComplexTypeEntry*)type); + return type->isObject(); +} +bool Generator::isObjectType(const ComplexTypeEntry* type) +{ + return type->isObject() || type->isQObject(); +} +bool Generator::isObjectType(const AbstractMetaClass* metaClass) +{ + return Generator::isObjectType(metaClass->typeEntry()); +} +bool Generator::isObjectType(const AbstractMetaType* metaType) +{ + return isObjectType(metaType->typeEntry()); +} + +bool Generator::isPointer(const AbstractMetaType* type) +{ + return type->indirections() > 0 + || type->isNativePointer() + || type->isValuePointer(); +} + +bool Generator::isCString(const AbstractMetaType* type) +{ + return type->isNativePointer() + && type->indirections() == 1 + && type->name() == QLatin1String("char"); +} + +bool Generator::isVoidPointer(const AbstractMetaType* type) +{ + return type->isNativePointer() + && type->indirections() == 1 + && type->name() == QLatin1String("void"); +} + +QString Generator::getFullTypeName(const TypeEntry* type) const +{ + return type->isCppPrimitive() + ? type->qualifiedCppName() + : (QLatin1String("::") + type->qualifiedCppName()); +} + +QString Generator::getFullTypeName(const AbstractMetaType* type) const +{ + if (isCString(type)) + return QLatin1String("const char*"); + if (isVoidPointer(type)) + return QLatin1String("void*"); + if (type->typeEntry()->isContainer()) + return QLatin1String("::") + type->cppSignature(); + QString typeName; + if (type->typeEntry()->isComplex() && type->hasInstantiations()) + typeName = getFullTypeNameWithoutModifiers(type); + else + typeName = getFullTypeName(type->typeEntry()); + return typeName + QString::fromLatin1("*").repeated(type->indirections()); +} + +QString Generator::getFullTypeName(const AbstractMetaClass* metaClass) const +{ + return QLatin1String("::") + metaClass->qualifiedCppName(); +} + +QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType* type) const +{ + if (isCString(type)) + return QLatin1String("const char*"); + if (isVoidPointer(type)) + return QLatin1String("void*"); + if (!type->hasInstantiations()) + return getFullTypeName(type->typeEntry()); + QString typeName = type->cppSignature(); + if (type->isConstant()) + typeName.remove(0, sizeof("const ") / sizeof(char) - 1); + switch (type->referenceType()) { + case NoReference: + break; + case LValueReference: + typeName.chop(1); + break; + case RValueReference: + typeName.chop(2); + break; + } + while (typeName.endsWith(QLatin1Char('*')) || typeName.endsWith(QLatin1Char(' '))) + typeName.chop(1); + return QLatin1String("::") + typeName; +} + +QString Generator::minimalConstructor(const AbstractMetaType* type) const +{ + if (!type || (type->referenceType() == LValueReference && Generator::isObjectType(type))) + return QString(); + + if (type->isContainer()) { + QString ctor = type->cppSignature(); + if (ctor.endsWith(QLatin1Char('*'))) + return QLatin1String("0"); + 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("()"); + } + + if (type->isNativePointer()) + return QLatin1String("static_cast<") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)"); + if (Generator::isPointer(type)) + return QLatin1String("static_cast< ::") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)"); + + if (type->typeEntry()->isComplex()) { + const ComplexTypeEntry* cType = reinterpret_cast(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)); + return ctor; + } + + return minimalConstructor(type->typeEntry()); +} + +QString Generator::minimalConstructor(const TypeEntry* type) const +{ + if (!type) + return QString(); + + if (type->isCppPrimitive()) { + const QString &name = type->qualifiedCppName(); + return name == QLatin1String("bool") + ? QLatin1String("false") : name + QLatin1String("(0)"); + } + + if (type->isEnum()) + return QLatin1String("static_cast< ::") + type->qualifiedCppName() + QLatin1String(">(0)"); + + if (type->isFlags()) + return type->qualifiedCppName() + QLatin1String("(0)"); + + if (type->isPrimitive()) { + QString ctor = reinterpret_cast(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; + } + + if (type->isComplex()) + return minimalConstructor(AbstractMetaClass::findClass(classes(), type)); + + return QString(); +} + +QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const +{ + if (!metaClass) + return QString(); + + const ComplexTypeEntry* cType = reinterpret_cast(metaClass->typeEntry()); + if (cType->hasDefaultConstructor()) + return cType->defaultConstructor(); + + 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 &templateArguments = metaClass->templateArguments(); + for (TypeEntry *templateType : templateArguments) + templateTypes << templateType->qualifiedCppName(); + + // Empty constructor. + if (maxArgs == 0) + return QLatin1String("::") + qualifiedCppName + QLatin1String("()"); + + QVector 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 (!args.isEmpty()) + return QString::fromLatin1("::%1(%2)").arg(qualifiedCppName, args.join(QLatin1String(", "))); + + candidates << 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)) { + QStringList args; + const AbstractMetaArgumentList &arguments = ctor->arguments(); + for (const AbstractMetaArgument *arg : arguments) { + if (arg->type()->typeEntry() == metaClass->typeEntry()) { + args.clear(); + 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(", "))); + } + } + + return QString(); +} + +QString Generator::translateType(const AbstractMetaType *cType, + const AbstractMetaClass *context, + Options options) const +{ + QString s; + static int constLen = strlen("const"); + + if (context && cType && + context->typeEntry()->isGenericClass() && + cType->originalTemplateType()) { + cType = cType->originalTemplateType(); + } + + if (!cType) { + s = QLatin1String("void"); + } else if (cType->isArray()) { + s = translateType(cType->arrayElementType(), context, options) + QLatin1String("[]"); + } else if (options & Generator::EnumAsInts && (cType->isEnum() || cType->isFlags())) { + s = QLatin1String("int"); + } else { + if (options & Generator::OriginalName) { + s = cType->originalTypeDescription().trimmed(); + if ((options & Generator::ExcludeReference) && s.endsWith(QLatin1Char('&'))) + s.chop(1); + + // remove only the last const (avoid remove template const) + if (options & Generator::ExcludeConst) { + int index = s.lastIndexOf(QLatin1String("const")); + + if (index >= (s.size() - (constLen + 1))) // (VarType const) or (VarType const[*|&]) + s = s.remove(index, constLen); + } + } else if (options & Generator::ExcludeConst || options & Generator::ExcludeReference) { + AbstractMetaType* copyType = cType->copy(); + + if (options & Generator::ExcludeConst) + copyType->setConstant(false); + + if (options & Generator::ExcludeReference) + copyType->setReferenceType(NoReference); + + s = copyType->cppSignature(); + if (!copyType->typeEntry()->isVoid() && !copyType->typeEntry()->isCppPrimitive()) + s.prepend(QLatin1String("::")); + delete copyType; + } else { + s = cType->cppSignature(); + } + } + + return s; +} + + +QString Generator::subDirectoryForClass(const AbstractMetaClass* clazz) const +{ + return subDirectoryForPackage(clazz->package()); +} + +QString Generator::subDirectoryForPackage(QString packageName) const +{ + if (packageName.isEmpty()) + packageName = m_d->packageName; + return QString(packageName).replace(QLatin1Char('.'), QDir::separator()); +} + +template +static QString getClassTargetFullName_(const T* t, bool includePackageName) +{ + QString name = t->name(); + const AbstractMetaClass* context = t->enclosingClass(); + while (context) { + name.prepend(QLatin1Char('.')); + name.prepend(context->name()); + context = context->enclosingClass(); + } + if (includePackageName) { + name.prepend(QLatin1Char('.')); + name.prepend(t->package()); + } + return name; +} + +QString getClassTargetFullName(const AbstractMetaClass* metaClass, bool includePackageName) +{ + return getClassTargetFullName_(metaClass, includePackageName); +} + +QString getClassTargetFullName(const AbstractMetaEnum* metaEnum, bool includePackageName) +{ + return getClassTargetFullName_(metaEnum, includePackageName); +} + +QString getClassTargetFullName(const AbstractMetaType *metaType, bool includePackageName) +{ + QString name = metaType->cppSignature(); + name.replace(QLatin1String("::"), QLatin1String("_")); + name.replace(QLatin1Char('<'), QLatin1Char('_')); + name.remove(QLatin1Char('>')); + name.remove(QLatin1Char(' ')); + if (includePackageName) { + name.prepend(QLatin1Char('.')); + name.prepend(metaType->package()); + } + return name; +} + +QString getFilteredCppSignatureString(QString signature) +{ + signature.replace(QLatin1String("::"), QLatin1String("_")); + signature.replace(QLatin1Char('<'), QLatin1Char('_')); + signature.replace(QLatin1Char('>'), QLatin1Char('_')); + signature.replace(QLatin1Char(' '), QLatin1Char('_')); + return signature; +} diff --git a/sources/shiboken2/generator/generator.h b/sources/shiboken2/generator/generator.h new file mode 100644 index 000000000..5ff5d6ae5 --- /dev/null +++ b/sources/shiboken2/generator/generator.h @@ -0,0 +1,448 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 GENERATOR_H +#define GENERATOR_H + +#include +#include +#include +#include +#include +#include +#include + +class ApiExtractor; +class AbstractMetaBuilder; +class AbstractMetaFunction; +class AbstractMetaClass; +class AbstractMetaEnum; +class TypeEntry; +class ComplexTypeEntry; +class AbstractMetaType; +class EnumTypeEntry; +class FlagsTypeEntry; + +QT_BEGIN_NAMESPACE +class QFile; +QT_END_NAMESPACE + +class PrimitiveTypeEntry; +class ContainerTypeEntry; +class Indentor; + +QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor); +void verifyDirectoryFor(const QFile &file); + +QString getClassTargetFullName(const AbstractMetaClass* metaClass, bool includePackageName = true); +QString getClassTargetFullName(const AbstractMetaEnum* metaEnum, bool includePackageName = true); +QString getClassTargetFullName(const AbstractMetaType *metaType, bool includePackageName = true); +QString getFilteredCppSignatureString(QString signature); + +/** + * PYSIDE-504: Handling the "protected hack" + * + * The problem: Creating wrappers when the class has private destructors. + * You can see an example on Windows in qclipboard_wrapper.h and others. + * Simply search for the text "// C++11: need to declare (unimplemented) destructor". + * + * The protected hack is the definition "#define protected public". + * For most compilers, this "hack" is enabled, because the problem of private + * destructors simply vanishes. + * + * If one does not want to use this hack, then a new problem arises: + * C++11 requires that a destructor is declared in a wrapper class when it is + * private in the base class. There is no implementation allowed! + * + * Unfortunately, MSVC in recent versions supports C++11, and due to restrictive + * rules, it is impossible to use the hack with this compiler. + * More unfortunate: Clang, when C++11 is enabled, also enforces a declaration + * of a private destructor, but it falsely then creates a linker error! + * + * Originally, we wanted to remove the protected hack. But due to the Clang + * problem, we gave up on removal of the protected hack and use it always + * when we can. This might change again when the Clang problem is solved. + */ + +#ifdef Q_CC_MSVC +const int alwaysGenerateDestructor = 1; +#else +const int alwaysGenerateDestructor = 0; +#endif + +/** + * A GeneratorContext object contains a pointer to an AbstractMetaClass and/or a specialized + * AbstractMetaType, for which code is currently being generated. + * + * The main case is when the context contains only an AbstractMetaClass pointer, which is used + * by different methods to generate appropriate expressions, functions, type names, etc. + * + * The second case is for generation of code for smart pointers. In this case the m_metaClass member + * contains the generic template class of the smart pointer, and the m_preciseClassType member + * contains the instantiated template type, e.g. a concrete shared_ptr. To + * distinguish this case, the member m_forSmartPointer is set to true. + * + * In the future the second case might be generalized for all template type instantiations. + */ +class GeneratorContext { +public: + GeneratorContext() : m_metaClass(0), m_preciseClassType(0), m_forSmartPointer(false) {} + GeneratorContext(AbstractMetaClass *metaClass, + const AbstractMetaType *preciseType = 0, + bool forSmartPointer = false) + : m_metaClass(metaClass), + m_preciseClassType(preciseType), + m_forSmartPointer(forSmartPointer) {} + + + AbstractMetaClass *metaClass() const { return m_metaClass; } + bool forSmartPointer() const { return m_forSmartPointer; } + const AbstractMetaType *preciseType() const { return m_preciseClassType; } + +private: + AbstractMetaClass *m_metaClass; + const AbstractMetaType *m_preciseClassType; + bool m_forSmartPointer; +}; + +/** + * Base class for all generators. The default implementations does nothing, + * you must subclass this to create your own generators. + */ +class Generator +{ +public: + /// Optiosn used around the generator code + enum Option { + NoOption = 0x00000000, + BoxedPrimitive = 0x00000001, + ExcludeConst = 0x00000002, + ExcludeReference = 0x00000004, + UseNativeIds = 0x00000008, + + EnumAsInts = 0x00000010, + SkipName = 0x00000020, + NoCasts = 0x00000040, + SkipReturnType = 0x00000080, + OriginalName = 0x00000100, + ShowStatic = 0x00000200, + UnderscoreSpaces = 0x00000400, + ForceEnumCast = 0x00000800, + ArrayAsPointer = 0x00001000, + VirtualCall = 0x00002000, + SkipTemplateParameters = 0x00004000, + SkipAttributes = 0x00008000, + OriginalTypeDescription = 0x00010000, + SkipRemovedArguments = 0x00020000, + IncludeDefaultExpression = 0x00040000, + NoReturnStatement = 0x00080000, + NoBlockedSlot = 0x00100000, + + SuperCall = 0x00200000, + + GlobalRefJObject = 0x00100000, + + SkipDefaultValues = 0x00400000, + + WriteSelf = 0x00800000, + ExcludeMethodConst = 0x01000000, + + ForceValueType = ExcludeReference | ExcludeConst + }; + Q_DECLARE_FLAGS(Options, Option) + + Generator(); + virtual ~Generator(); + + bool setup(const ApiExtractor& extractor, const QMap args); + + virtual QMap options() const; + + /// Returns the classes used to generate the binding code. + AbstractMetaClassList classes() const; + + /// 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 + /// their parent classes. + AbstractMetaClassList classesTopologicalSorted(const Dependencies &additionalDependencies = Dependencies()) const; + + /// Returns all global functions found by APIExtractor + AbstractMetaFunctionList globalFunctions() const; + + /// Returns all global enums found by APIExtractor + AbstractMetaEnumList globalEnums() const; + + /// Returns all primitive types found by APIExtractor + PrimitiveTypeEntryList primitiveTypes() const; + + /// 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); + + /// Returns the file base name for a smart pointer. + QString getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType, + const AbstractMetaClass *smartPointerClass) const; + + /// Returns the number of generated items + int numGenerated() const; + + /// 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; + + /// Returns true if the generator should generate any code for the AbstractMetaClass. + virtual bool shouldGenerate(const AbstractMetaClass *) const; + + /// Returns the subdirectory used to write the binding code of an AbstractMetaClass. + virtual QString subDirectoryForClass(const AbstractMetaClass* clazz) const; + + /** + * Translate metatypes to binding source format. + * \param metatype a pointer to metatype + * \param context the current meta class + * \param option some extra options + * \return the metatype translated to binding source format + */ + QString translateType(const AbstractMetaType *metatype, + const AbstractMetaClass *context, + Options options = NoOption) const; + + /** + * Function used to write the fucntion arguments on the class buffer. + * \param s the class output buffer + * \param metafunction the pointer to metafunction information + * \param count the number of function arguments + * \param options some extra options used during the parser + */ + virtual void writeFunctionArguments(QTextStream &s, + const AbstractMetaFunction *metafunction, + Options options = NoOption) const = 0; + + virtual void writeArgumentNames(QTextStream &s, + const AbstractMetaFunction *metafunction, + Options options = NoOption) const = 0; + + void replaceTemplateVariables(QString &code, const AbstractMetaFunction *func); + + // QtScript + QSet qtMetaTypeDeclaredTypeNames() const; + + /** + * 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; + QString getFullTypeName(const AbstractMetaClass* metaClass) const; + + /** + * Returns the full qualified C++ name for an AbstractMetaType, but removing modifiers + * as 'const', '&', and '*' (except if the class is not derived from a template). + * This is useful for instantiated templates. + */ + QString getFullTypeNameWithoutModifiers(const AbstractMetaType* type) const; + + /** + * Tries to build a minimal constructor for the type. + * It will check first for a user defined default constructor. + * Returns a null string if it fails. + */ + QString minimalConstructor(const TypeEntry* type) const; + QString minimalConstructor(const AbstractMetaType* type) const; + QString minimalConstructor(const AbstractMetaClass* metaClass) const; + +protected: + /** + * Returns the file name used to write the binding code of an AbstractMetaClass/Type. + * \param context the GeneratorContext which contains an AbstractMetaClass or AbstractMetaType + * for which the file name must be returned + * \return the file name used to write the binding code for the class + */ + virtual QString fileNamePrefix() const = 0; + virtual QString fileNameForContext(GeneratorContext &context) const = 0; + + + virtual bool doSetup(const QMap& args) = 0; + + /** + * Write the bindding code for an AbstractMetaClass. + * This is called by generate method. + * \param s text stream to write the generated output + * \param metaClass the class that should be generated + */ + virtual void generateClass(QTextStream& s, GeneratorContext &classContext) = 0; + virtual bool finishGeneration() = 0; + + /** + * Returns the subdirectory path for a given package + * (aka module, aka library) name. + * If the target language separates the package modules with characters other + * than dots ('.') the generator subclass must overload this method. + * /param packageName complete package name for which to return the subdirectory path + * or nothing the use the name of the currently processed package + * /return a string representing the subdirectory path for the given package + */ + virtual QString subDirectoryForPackage(QString packageName = QString()) const; + + QVector instantiatedContainers() const; + QVector instantiatedSmartPointers() const; + + static QString getSimplifiedContainerTypeName(const AbstractMetaType *type); + void addInstantiatedContainersAndSmartPointers(const AbstractMetaType *type, + const QString &context); + +private: + struct GeneratorPrivate; + GeneratorPrivate* m_d; + void collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction* func); + void collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass); + void collectInstantiatedContainersAndSmartPointers(); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Options) +typedef QSharedPointer GeneratorPtr; +typedef QVector Generators; + +/** +* Utility class to store the identation level, use it in a QTextStream. +*/ +class Indentor +{ +public: + Indentor() : indent(0) {} + int indent; +}; + +/** +* Class that use the RAII idiom to set and unset the identation level. +*/ +class Indentation +{ +public: + Indentation(Indentor &indentor) : indentor(indentor) + { + indentor.indent++; + } + ~Indentation() + { + indentor.indent--; + } + +private: + Indentor &indentor; +}; + +inline QTextStream &operator <<(QTextStream &s, const Indentor &indentor) +{ + for (int i = 0; i < indentor.indent; ++i) + s << " "; + return s; +} + +#endif // GENERATOR_H + diff --git a/sources/shiboken2/generator/main.cpp b/sources/shiboken2/generator/main.cpp new file mode 100644 index 000000000..25b50b04e --- /dev/null +++ b/sources/shiboken2/generator/main.cpp @@ -0,0 +1,552 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include "generator.h" +#include "shibokenconfig.h" +#include "cppgenerator.h" +#include "headergenerator.h" +#include "qtdocgenerator.h" + +#ifdef _WINDOWS + #define PATH_SPLITTER ";" +#else + #define PATH_SPLITTER ":" +#endif + +namespace { + +class ArgsHandler +{ +public: + explicit ArgsHandler(const QMap& other); + virtual ~ArgsHandler(); + + inline QMap& 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); + + 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* m_args; +}; + +ArgsHandler::ArgsHandler(const QMap& other) + : m_args(new QMap(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); + } + + return retval; +} + +QString ArgsHandler::errorMessage() const +{ + typedef QMap::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; +} +} + +static void printOptions(QTextStream& s, const QMap& options) +{ + QMap::const_iterator it = options.constBegin(); + s.setFieldAlignment(QTextStream::AlignLeft); + for (; it != options.constEnd(); ++it) { + s << " --"; + s.setFieldWidth(38); + s << it.key() << it.value(); + s.setFieldWidth(0); + s << endl; + } +} + +typedef void (*getGeneratorsFunc)(QLinkedList*); + +static bool processProjectFile(QFile& projectFile, QMap& args) +{ + QByteArray line = projectFile.readLine().trimmed(); + if (line.isEmpty() || line != "[generator-project]") + return false; + + QStringList includePaths; + QStringList frameworkIncludePaths; + QStringList typesystemPaths; + QStringList apiVersions; + + while (!projectFile.atEnd()) { + line = projectFile.readLine().trimmed(); + if (line.isEmpty()) + continue; + + int split = line.indexOf('='); + QByteArray key; + QString value; + if (split > 0) { + key = line.left(split - 1).trimmed(); + value = QString::fromUtf8(line.mid(split + 1).trimmed()); + } else { + key = line; + } + + if (key == "include-path") + includePaths << QDir::toNativeSeparators(value); + else if (key == "framework-include-path") + frameworkIncludePaths << QDir::toNativeSeparators(value); + else if (key == "typesystem-path") + typesystemPaths << QDir::toNativeSeparators(value); + else if (key == "api-version") + apiVersions << value; + else if (key == "header-file") + args.insert(QLatin1String("arg-1"), value); + else if (key == "typesystem-file") + args.insert(QLatin1String("arg-2"), value); + else + args.insert(QString::fromUtf8(key), value); + } + + if (!includePaths.isEmpty()) + args.insert(QLatin1String("include-paths"), includePaths.join(QLatin1String(PATH_SPLITTER))); + + if (!frameworkIncludePaths.isEmpty()) + args.insert(QLatin1String("framework-include-paths"), + frameworkIncludePaths.join(QLatin1String(PATH_SPLITTER))); + + if (!typesystemPaths.isEmpty()) + args.insert(QLatin1String("typesystem-paths"), typesystemPaths.join(QLatin1String(PATH_SPLITTER))); + if (!apiVersions.isEmpty()) + args.insert(QLatin1String("api-version"), apiVersions.join(QLatin1Char('|'))); + return true; +} + +static QMap getInitializedArguments() +{ + QMap args; + QStringList arguments = QCoreApplication::arguments(); + QString appName = arguments.first(); + arguments.removeFirst(); + + QString projectFileName; + for (const QString &arg : qAsConst(arguments)) { + if (arg.startsWith(QLatin1String("--project-file"))) { + int split = arg.indexOf(QLatin1Char('=')); + if (split > 0) + projectFileName = arg.mid(split + 1).trimmed(); + break; + } + } + + if (projectFileName.isNull()) + return args; + + if (!QFile::exists(projectFileName)) { + std::cerr << qPrintable(appName) << ": Project file \""; + std::cerr << qPrintable(projectFileName) << "\" not found."; + std::cerr << std::endl; + return args; + } + + QFile projectFile(projectFileName); + if (!projectFile.open(QIODevice::ReadOnly)) + return args; + + if (!processProjectFile(projectFile, args)) { + std::cerr << qPrintable(appName) << ": first line of project file \""; + std::cerr << qPrintable(projectFileName) << "\" must be the string \"[generator-project]\""; + std::cerr << std::endl; + return args; + } + + return args; +} + +static QMap getCommandLineArgs() +{ + QMap args = getInitializedArguments(); + QStringList arguments = QCoreApplication::arguments(); + arguments.removeFirst(); + + int argNum = 0; + for (const QString &carg : qAsConst(arguments)) { + const QString &arg = carg.trimmed(); + if (arg.startsWith(QLatin1String("--"))) { + int split = arg.indexOf(QLatin1Char('=')); + if (split > 0) + args[arg.mid(2).left(split-2)] = arg.mid(split + 1).trimmed(); + else + args[arg.mid(2)] = QString(); + } else if (arg.startsWith(QLatin1Char('-'))) { + args[arg.mid(1)] = QString(); + } else { + argNum++; + args[QString::fromLatin1("arg-%1").arg(argNum)] = arg; + } + } + return args; +} + +static inline Generators docGenerators() +{ + Generators result; +#ifdef DOCSTRINGS_ENABLED + result.append(GeneratorPtr(new QtDocGenerator)); +#endif + return result; +} + +static inline Generators shibokenGenerators() +{ + Generators result; + result << GeneratorPtr(new CppGenerator) << GeneratorPtr(new HeaderGenerator); + return result; +} + +void printUsage() +{ + QTextStream s(stdout); + s << "Usage:\n " + << "shiboken [options] header-file typesystem-file\n\n" + << "General options:\n"; + QMap generalOptions; + generalOptions.insert(QLatin1String("project-file="), + QLatin1String("text file containing a description of the binding project. Replaces and overrides command line arguments")); + generalOptions.insert(QLatin1String("debug-level=[sparse|medium|full]"), + QLatin1String("Set the debug level")); + generalOptions.insert(QLatin1String("silent"), + QLatin1String("Avoid printing any message")); + generalOptions.insert(QLatin1String("help"), + QLatin1String("Display this help and exit")); + generalOptions.insert(QLatin1String("no-suppress-warnings"), + QLatin1String("Show all warnings")); + generalOptions.insert(QLatin1String("output-directory="), + QLatin1String("The directory where the generated files will be written")); + generalOptions.insert(QLatin1String("include-paths=[" PATH_SPLITTER "" PATH_SPLITTER "...]"), + QLatin1String("Include paths used by the C++ parser")); + generalOptions.insert(QLatin1String("framework-include-paths=[" PATH_SPLITTER "" PATH_SPLITTER "...]"), + QLatin1String("Framework include paths used by the C++ parser")); + generalOptions.insert(QLatin1String("typesystem-paths=[" PATH_SPLITTER "" PATH_SPLITTER "...]"), + QLatin1String("Paths used when searching for typesystems")); + generalOptions.insert(QLatin1String("documentation-only"), + QLatin1String("Do not generates any code, just the documentation")); + generalOptions.insert(QLatin1String("license-file="), + QLatin1String("File used for copyright headers of generated files")); + generalOptions.insert(QLatin1String("version"), + QLatin1String("Output version information and exit")); + generalOptions.insert(QLatin1String("generator-set=<\"generator module\">"), + QLatin1String("generator-set to be used. e.g. qtdoc")); + generalOptions.insert(QLatin1String("api-version=<\"package mask\">,<\"version\">"), + QLatin1String("Specify the supported api version used to generate the bindings")); + generalOptions.insert(QLatin1String("drop-type-entries=\"[;TypeEntry1;...]\""), + QLatin1String("Semicolon separated list of type system entries (classes, namespaces, global functions and enums) to be dropped from generation.")); + printOptions(s, generalOptions); + + const Generators generators = shibokenGenerators() + docGenerators(); + for (const GeneratorPtr &generator : generators) { + QMap options = generator->options(); + if (!options.isEmpty()) { + s << endl << generator->name() << " options:\n"; + printOptions(s, generator->options()); + } + } +} + +static inline void printVerAndBanner() +{ + std::cout << "shiboken v" SHIBOKEN_VERSION << std::endl; + std::cout << "Copyright (C) 2016 The Qt Company Ltd." << std::endl; +} + +static inline void errorPrint(const QString& s) +{ + QStringList arguments = QCoreApplication::arguments(); + arguments.pop_front(); + std::cerr << "shiboken: " << qPrintable(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('.'); +} + +int main(int argc, char *argv[]) +{ + QElapsedTimer timer; + timer.start(); + // needed by qxmlpatterns + QCoreApplication app(argc, argv); + ReportHandler::install(); + qCDebug(lcShiboken()).noquote().nospace() << QCoreApplication::arguments().join(QLatin1Char(' ')); + + // Store command arguments in a map + QMap args = getCommandLineArgs(); + ArgsHandler argsHandler(args); + Generators generators; + + if (argsHandler.argExistsRemove(QLatin1String("version"))) { + 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")); + + // Pre-defined generator sets. + if (generatorSet == QLatin1String("qtdoc")) { + generators = docGenerators(); + if (generators.isEmpty()) { + errorPrint(QLatin1String("Doc strings extractions was not enabled in this shiboken build.")); + return EXIT_FAILURE; + } + } else if (generatorSet.isEmpty() || generatorSet == QLatin1String("shiboken")) { + generators = shibokenGenerators(); + } else { + errorPrint(QLatin1String("Unknown generator set, try \"shiboken\" or \"qtdoc\".")); + return EXIT_FAILURE; + } + + if (argsHandler.argExistsRemove(QLatin1String("help"))) { + printUsage(); + return EXIT_SUCCESS; + } + + 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()); + } else { + errorPrint(QStringLiteral("Couldn't find the file containing the license heading: %1"). + arg(licenseFileName)); + return EXIT_FAILURE; + } + } + + QString outputDirectory = argsHandler.removeArg(QLatin1String("output-directory")); + if (outputDirectory.isEmpty()) + outputDirectory = QLatin1String("out"); + + if (!QDir(outputDirectory).exists()) { + if (!QDir().mkpath(outputDirectory)) { + qCWarning(lcShiboken).noquote().nospace() + << "Can't create output directory: " << QDir::toNativeSeparators(outputDirectory); + return EXIT_FAILURE; + } + } + + // Create and set-up API Extractor + ApiExtractor extractor; + extractor.setLogDirectory(outputDirectory); + + if (argsHandler.argExistsRemove(QLatin1String("silent"))) { + extractor.setSilent(true); + } else { + QString level = argsHandler.removeArg(QLatin1String("debug-level")); + if (!level.isEmpty()) { + if (level == QLatin1String("sparse")) + extractor.setDebugLevel(ReportHandler::SparseDebug); + else if (level == QLatin1String("medium")) + extractor.setDebugLevel(ReportHandler::MediumDebug); + else if (level == QLatin1String("full")) + extractor.setDebugLevel(ReportHandler::FullDebug); + } + } + if (argsHandler.argExistsRemove(QLatin1String("no-suppress-warnings"))) + extractor.setSuppressWarnings(false); + + if (argsHandler.argExists(QLatin1String("api-version"))) { + const QStringList &versions = argsHandler.removeArg(QLatin1String("api-version")).split(QLatin1Char('|')); + for (const QString &fullVersion : versions) { + QStringList parts = fullVersion.split(QLatin1Char(',')); + QString package; + QString version; + // avoid constFirst to stay Qt 5.5 compatible + package = parts.count() == 1 ? QLatin1String("*") : parts.first(); + version = parts.last(); + if (!extractor.setApiVersion(package, version)) { + errorPrint(msgInvalidVersion(package, version)); + return EXIT_FAILURE; + } + } + } + + if (argsHandler.argExists(QLatin1String("drop-type-entries"))) + extractor.setDropTypeEntries(argsHandler.removeArg(QLatin1String("drop-type-entries"))); + + QString path = argsHandler.removeArg(QLatin1String("typesystem-paths")); + if (!path.isEmpty()) + extractor.addTypesystemSearchPath(path.split(QLatin1String(PATH_SPLITTER))); + + path = argsHandler.removeArg(QLatin1String("include-paths")); + if (!path.isEmpty()) { + const QStringList includePathListList = path.split(QLatin1String(PATH_SPLITTER)); + for (const QString &s : qAsConst(includePathListList)) { + const bool isFramework = false; + extractor.addIncludePath(HeaderPath(s, isFramework)); + } + } + + path = argsHandler.removeArg(QLatin1String("framework-include-paths")); + if (!path.isEmpty()) { + const QStringList frameworkPathList = path.split(QLatin1String(PATH_SPLITTER)); + const bool isFramework = true; + for (const QString &s : qAsConst(frameworkPathList)) { + extractor.addIncludePath(HeaderPath(s, isFramework)); + } + } + + QString cppFileName = argsHandler.removeArg(QLatin1String("arg-1")); + QString typeSystemFileName = argsHandler.removeArg(QLatin1String("arg-2")); + + /* 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 projectFileArgs = getInitializedArguments(); + if (!projectFileArgs.isEmpty()) { + QMap::const_iterator it = + projectFileArgs.constBegin(); + for ( ; it != projectFileArgs.constEnd(); ++it) + argsHandler.removeArg(it.key()); + } + for (const GeneratorPtr &generator : qAsConst(generators)) { + QMap options = generator->options(); + if (!options.isEmpty()) { + QMap::const_iterator it = options.constBegin(); + for ( ; it != options.constEnd(); ++it) + argsHandler.removeArg(it.key()); + } + } + + if (!argsHandler.noArgs()) { + errorPrint(argsHandler.errorMessage()); + std::cout << "Note: use --help option for more information." << std::endl; + return EXIT_FAILURE; + } + + extractor.setCppFileName(cppFileName); + extractor.setTypeSystem(typeSystemFileName); + if (!extractor.run()) { + errorPrint(QLatin1String("Error running ApiExtractor.")); + return EXIT_FAILURE; + } + + if (!extractor.classCount()) + qCWarning(lcShiboken) << "No C++ classes found!"; + + qCDebug(lcShiboken) << extractor; + + 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; + } + } + } + + QByteArray doneMessage = "Done, " + QByteArray::number(timer.elapsed()) + "ms"; + if (const int w = ReportHandler::warningCount()) + doneMessage += ", " + QByteArray::number(w) + " warnings"; + if (const int sw = ReportHandler::suppressedCount()) + doneMessage += " (" + QByteArray::number(sw) + " known issues)"; + qCDebug(lcShiboken()).noquote().nospace() << doneMessage; + std::cout << doneMessage.constData() << std::endl; + + return EXIT_SUCCESS; +} diff --git a/sources/shiboken2/generator/qtdoc/CMakeLists.txt b/sources/shiboken2/generator/qtdoc/CMakeLists.txt new file mode 100644 index 000000000..1361ba8f1 --- /dev/null +++ b/sources/shiboken2/generator/qtdoc/CMakeLists.txt @@ -0,0 +1,21 @@ +project(qtdoc_generator) + +set(qtdoc_generator_SRC +qtdocgenerator.cpp +) + +include_directories(${generators_SOURCE_DIR} + ${Qt5Core_INCLUDE_DIRS} + ${APIEXTRACTOR_INCLUDE_DIR}) +add_executable(docgenerator main.cpp) +set_target_properties(docgenerator PROPERTIES OUTPUT_NAME docgenerator${generator_SUFFIX}) + +target_link_libraries(docgenerator ${Qt5Core_LIBRARES}) + +add_library(qtdoc_generator SHARED ${qtdoc_generator_SRC}) +target_link_libraries(qtdoc_generator ${APIEXTRACTOR_LIBRARY} ${Qt5Core_LIBRARES} genrunner) +set_property(TARGET qtdoc_generator PROPERTY PREFIX "") + +install(TARGETS qtdoc_generator DESTINATION ${generator_plugin_DIR}) +install(TARGETS docgenerator DESTINATION bin) + diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp new file mode 100644 index 000000000..02fd40354 --- /dev/null +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp @@ -0,0 +1,1715 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "qtdocgenerator.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static Indentor INDENT; + +static bool shouldSkip(const AbstractMetaFunction* func) +{ + bool skipable = func->isConstructor() + || func->isModifiedRemoved() + || func->declaringClass() != func->ownerClass() + || func->isCastOperator() + || func->name() == QLatin1String("operator="); + + // Search a const clone + if (!skipable && !func->isConstant()) { + const AbstractMetaArgumentList funcArgs = func->arguments(); + const AbstractMetaFunctionList &ownerFunctions = func->ownerClass()->functions(); + for (AbstractMetaFunction *f : ownerFunctions) { + if (f != func + && f->isConstant() + && f->name() == func->name() + && f->arguments().count() == funcArgs.count()) { + // Compare each argument + bool cloneFound = true; + + const AbstractMetaArgumentList fargs = f->arguments(); + for (int i = 0, max = funcArgs.count(); i < max; ++i) { + if (funcArgs.at(i)->type()->typeEntry() != fargs.at(i)->type()->typeEntry()) { + cloneFound = false; + break; + } + } + if (cloneFound) + return true; + } + } + } + return skipable; +} + +static bool functionSort(const AbstractMetaFunction* func1, const AbstractMetaFunction* func2) +{ + return func1->name() < func2->name(); +} + +static QString createRepeatedChar(int i, char c) +{ + QString out; + for (int j = 0; j < i; ++j) + out += QLatin1Char(c); + + return out; +} + +static QString escape(QString str) +{ + str.replace(QLatin1Char('*'), QLatin1String("\\*")); + str.replace(QLatin1Char('_'), QLatin1String("\\_")); + return str; +} + +static QString escape(const QStringRef& strref) +{ + QString str = strref.toString(); + return escape(str); +} + + +QtXmlToSphinx::QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context) + : 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); + m_handlerMap.insert(QLatin1String("para"), &QtXmlToSphinx::handleParaTag); + m_handlerMap.insert(QLatin1String("italic"), &QtXmlToSphinx::handleItalicTag); + m_handlerMap.insert(QLatin1String("bold"), &QtXmlToSphinx::handleBoldTag); + m_handlerMap.insert(QLatin1String("see-also"), &QtXmlToSphinx::handleSeeAlsoTag); + m_handlerMap.insert(QLatin1String("snippet"), &QtXmlToSphinx::handleSnippetTag); + m_handlerMap.insert(QLatin1String("dots"), &QtXmlToSphinx::handleDotsTag); + m_handlerMap.insert(QLatin1String("codeline"), &QtXmlToSphinx::handleDotsTag); + m_handlerMap.insert(QLatin1String("table"), &QtXmlToSphinx::handleTableTag); + m_handlerMap.insert(QLatin1String("header"), &QtXmlToSphinx::handleRowTag); + m_handlerMap.insert(QLatin1String("row"), &QtXmlToSphinx::handleRowTag); + m_handlerMap.insert(QLatin1String("item"), &QtXmlToSphinx::handleItemTag); + m_handlerMap.insert(QLatin1String("argument"), &QtXmlToSphinx::handleArgumentTag); + m_handlerMap.insert(QLatin1String("teletype"), &QtXmlToSphinx::handleArgumentTag); + m_handlerMap.insert(QLatin1String("link"), &QtXmlToSphinx::handleLinkTag); + m_handlerMap.insert(QLatin1String("inlineimage"), &QtXmlToSphinx::handleImageTag); + m_handlerMap.insert(QLatin1String("image"), &QtXmlToSphinx::handleImageTag); + m_handlerMap.insert(QLatin1String("list"), &QtXmlToSphinx::handleListTag); + m_handlerMap.insert(QLatin1String("term"), &QtXmlToSphinx::handleTermTag); + m_handlerMap.insert(QLatin1String("raw"), &QtXmlToSphinx::handleRawTag); + m_handlerMap.insert(QLatin1String("underline"), &QtXmlToSphinx::handleItalicTag); + m_handlerMap.insert(QLatin1String("superscript"), &QtXmlToSphinx::handleSuperScriptTag); + m_handlerMap.insert(QLatin1String("code"), &QtXmlToSphinx::handleCodeTag); + m_handlerMap.insert(QLatin1String("badcode"), &QtXmlToSphinx::handleCodeTag); + m_handlerMap.insert(QLatin1String("legalese"), &QtXmlToSphinx::handleCodeTag); + m_handlerMap.insert(QLatin1String("section"), &QtXmlToSphinx::handleAnchorTag); + m_handlerMap.insert(QLatin1String("quotefile"), &QtXmlToSphinx::handleQuoteFileTag); + + // ignored tags + m_handlerMap.insert(QLatin1String("generatedlist"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("tableofcontents"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("quotefromfile"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("skipto"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("target"), &QtXmlToSphinx::handleIgnoredTag); + + // useless tags + m_handlerMap.insert(QLatin1String("description"), &QtXmlToSphinx::handleUselessTag); + m_handlerMap.insert(QLatin1String("definition"), &QtXmlToSphinx::handleUselessTag); + m_handlerMap.insert(QLatin1String("printuntil"), &QtXmlToSphinx::handleUselessTag); + m_handlerMap.insert(QLatin1String("relation"), &QtXmlToSphinx::handleUselessTag); + + // Doxygen tags + m_handlerMap.insert(QLatin1String("title"), &QtXmlToSphinx::handleHeadingTag); + m_handlerMap.insert(QLatin1String("ref"), &QtXmlToSphinx::handleParaTag); + m_handlerMap.insert(QLatin1String("computeroutput"), &QtXmlToSphinx::handleParaTag); + m_handlerMap.insert(QLatin1String("detaileddescription"), &QtXmlToSphinx::handleParaTag); + m_handlerMap.insert(QLatin1String("name"), &QtXmlToSphinx::handleParaTag); + m_handlerMap.insert(QLatin1String("listitem"), &QtXmlToSphinx::handleItemTag); + m_handlerMap.insert(QLatin1String("parametername"), &QtXmlToSphinx::handleItemTag); + m_handlerMap.insert(QLatin1String("parameteritem"), &QtXmlToSphinx::handleItemTag); + m_handlerMap.insert(QLatin1String("ulink"), &QtXmlToSphinx::handleLinkTag); + m_handlerMap.insert(QLatin1String("itemizedlist"), &QtXmlToSphinx::handleListTag); + m_handlerMap.insert(QLatin1String("parameternamelist"), &QtXmlToSphinx::handleListTag); + m_handlerMap.insert(QLatin1String("parameterlist"), &QtXmlToSphinx::handleListTag); + + // Doxygen ignored tags + m_handlerMap.insert(QLatin1String("highlight"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("linebreak"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("programlisting"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("xreftitle"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("sp"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("entry"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("simplesect"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("verbatim"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("xrefsect"), &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert(QLatin1String("xrefdescription"), &QtXmlToSphinx::handleIgnoredTag); + + m_result = transform(doc); +} + +void QtXmlToSphinx::pushOutputBuffer() +{ + QString* buffer = new QString(); + m_buffers << buffer; + m_output.setString(buffer); +} + +QString QtXmlToSphinx::popOutputBuffer() +{ + Q_ASSERT(!m_buffers.isEmpty()); + QString* str = m_buffers.pop(); + QString strcpy(*str); + delete str; + m_output.setString(m_buffers.isEmpty() ? 0 : m_buffers.top()); + return strcpy; +} + +QString QtXmlToSphinx::expandFunction(const QString& function) +{ + QStringList functionSpec = function.split(QLatin1Char('.')); + QString className = functionSpec.first(); + const AbstractMetaClass* metaClass = 0; + const AbstractMetaClassList &classes = m_generator->classes(); + for (const AbstractMetaClass *cls : classes) { + if (cls->name() == className) { + metaClass = cls; + break; + } + } + + if (metaClass) { + functionSpec.removeFirst(); + return metaClass->typeEntry()->qualifiedTargetLangName() + + QLatin1Char('.') + functionSpec.join(QLatin1Char('.')); + } else { + return function; + } +} + +QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName) +{ + // avoid constLast to stay Qt 5.5 compatible + QString currentClass = m_context.split(QLatin1Char('.')).last(); + + const AbstractMetaClass* metaClass = 0; + const AbstractMetaClassList &classes = m_generator->classes(); + for (const AbstractMetaClass *cls : classes) { + if (cls->name() == currentClass) { + metaClass = cls; + break; + } + } + + if (metaClass) { + QList funcList; + const AbstractMetaFunctionList &methods = metaClass->queryFunctionsByName(methodName); + for (const AbstractMetaFunction *func : methods) { + if (methodName == func->name()) + funcList.append(func); + } + + const AbstractMetaClass* implementingClass = 0; + for (const AbstractMetaFunction *func : qAsConst(funcList)) { + implementingClass = func->implementingClass(); + if (implementingClass->name() == currentClass) + break; + } + + if (implementingClass) + return implementingClass->typeEntry()->qualifiedTargetLangName(); + } + + return QLatin1Char('~') + m_context; +} + +QString QtXmlToSphinx::transform(const QString& doc) +{ + Q_ASSERT(m_buffers.isEmpty()); + Indentation indentation(INDENT); + if (doc.trimmed().isEmpty()) + return doc; + + pushOutputBuffer(); + + QXmlStreamReader reader(doc); + + while (!reader.atEnd()) { + QXmlStreamReader::TokenType token = reader.readNext(); + if (reader.hasError()) { + const QString message = QLatin1String("XML Error: ") + reader.errorString() + + QLatin1Char('\n') + doc; + m_output << INDENT << message; + qCWarning(lcShiboken).noquote().nospace() << message; + break; + } + + if (token == QXmlStreamReader::StartElement) { + QStringRef tagName = reader.name(); + TagHandler handler = m_handlerMap.value(tagName.toString(), &QtXmlToSphinx::handleUnknownTag); + if (!m_handlers.isEmpty() && ( (m_handlers.top() == &QtXmlToSphinx::handleIgnoredTag) || + (m_handlers.top() == &QtXmlToSphinx::handleRawTag)) ) + handler = &QtXmlToSphinx::handleIgnoredTag; + + m_handlers.push(handler); + } + if (!m_handlers.isEmpty()) + (this->*(m_handlers.top()))(reader); + + if (token == QXmlStreamReader::EndElement) { + m_handlers.pop(); + m_lastTagName = reader.name().toString(); + } + } + m_output.flush(); + QString retval = popOutputBuffer(); + Q_ASSERT(m_buffers.isEmpty()); + return retval; +} + +QString QtXmlToSphinx::readFromLocations(const QStringList& locations, const QString& path, const QString& identifier) +{ + QString result; + bool ok; + for (QString location : locations) { + location.append(QLatin1Char('/')); + location.append(path); + result = readFromLocation(location, identifier, &ok); + if (ok) + break; + } + if (!ok) { + qCDebug(lcShiboken).noquote().nospace() << "Couldn't read code snippet file: {" + << locations.join(QLatin1Char('|')) << '}' << path; + } + return result; + +} + +QString QtXmlToSphinx::readFromLocation(const QString& location, const QString& identifier, bool* ok) +{ + QFile inputFile; + inputFile.setFileName(location); + if (!inputFile.open(QIODevice::ReadOnly)) { + if (!ok) { + qCDebug(lcShiboken).noquote().nospace() << "Couldn't read code snippet file: " + << QDir::toNativeSeparators(inputFile.fileName()); + } else { + *ok = false; + } + return QString(); + } + + QRegExp searchString(QLatin1String("//!\\s*\\[") + identifier + QLatin1String("\\]")); + QRegExp codeSnippetCode(QLatin1String("//!\\s*\\[[\\w\\d\\s]+\\]")); + QString code; + + bool identifierIsEmpty = identifier.isEmpty(); + bool getCode = false; + + while (!inputFile.atEnd()) { + QString line = QString::fromUtf8(inputFile.readLine()); + if (identifierIsEmpty) { + code += line; + } else if (getCode && !line.contains(searchString)) { + line.remove(codeSnippetCode); + code += line; + } else if (line.contains(searchString)) { + if (getCode) + break; + else + getCode = true; + } + } + + if (!identifierIsEmpty && !getCode) { + qCDebug(lcShiboken).noquote().nospace() << "Code snippet file found (" + << location << "), but snippet " << identifier << " not found."; + } + + if (ok) + *ok = true; + return code; +} + +void QtXmlToSphinx::handleHeadingTag(QXmlStreamReader& reader) +{ + static QString heading; + static char type; + static char types[] = { '-', '^' }; + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + uint typeIdx = reader.attributes().value(QLatin1String("level")).toString().toInt(); + if (typeIdx >= sizeof(types)) + type = types[sizeof(types)-1]; + else + type = types[typeIdx]; + } else if (token == QXmlStreamReader::EndElement) { + m_output << createRepeatedChar(heading.length(), type) << endl << endl; + } else if (token == QXmlStreamReader::Characters) { + heading = escape(reader.text()).trimmed(); + m_output << endl << endl << heading << endl; + } +} + +void QtXmlToSphinx::handleParaTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + pushOutputBuffer(); + } else if (token == QXmlStreamReader::EndElement) { + QString result = popOutputBuffer().simplified(); + if (result.startsWith(QLatin1String("**Warning:**"))) + result.replace(0, 12, QLatin1String(".. warning:: ")); + else if (result.startsWith(QLatin1String("**Note:**"))) + result.replace(0, 9, QLatin1String(".. note:: ")); + + m_output << INDENT << result << endl << endl; + } else if (token == QXmlStreamReader::Characters) { + QString text = escape(reader.text()); + if (!m_output.string()->isEmpty()) { + QChar start = text[0]; + QChar end = m_output.string()->at(m_output.string()->length() - 1); + if ((end == QLatin1Char('*') || end == QLatin1Char('`')) && start != QLatin1Char(' ') && !start.isPunct()) + m_output << '\\'; + } + m_output << INDENT << text; + } +} + +void QtXmlToSphinx::handleItalicTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement) { + m_insideItalic = !m_insideItalic; + m_output << '*'; + } else if (token == QXmlStreamReader::Characters) { + m_output << escape(reader.text()).trimmed(); + } +} + +void QtXmlToSphinx::handleBoldTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement) { + m_insideBold = !m_insideBold; + m_output << "**"; + } else if (token == QXmlStreamReader::Characters) { + m_output << escape(reader.text()).trimmed(); + } +} + +void QtXmlToSphinx::handleArgumentTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement) + m_output << "``"; + else if (token == QXmlStreamReader::Characters) + m_output << reader.text().toString().trimmed(); +} + +void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) + m_output << INDENT << ".. seealso:: "; + else if (token == QXmlStreamReader::EndElement) + m_output << endl; +} + +void QtXmlToSphinx::handleSnippetTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + const bool consecutiveSnippet = m_lastTagName == QLatin1String("snippet") + || m_lastTagName == QLatin1String("dots") || m_lastTagName == QLatin1String("codeline"); + if (consecutiveSnippet) { + m_output.flush(); + m_output.string()->chop(2); + } + QString location = reader.attributes().value(QLatin1String("location")).toString(); + QString identifier = reader.attributes().value(QLatin1String("identifier")).toString(); + QString code = readFromLocations(m_generator->codeSnippetDirs(), location, identifier); + if (!consecutiveSnippet) + m_output << INDENT << "::\n\n"; + + Indentation indentation(INDENT); + if (code.isEmpty()) { + m_output << INDENT << "" << endl; + } else { + const QStringList lines = code.split(QLatin1Char('\n')); + for (const QString &line : lines) { + if (!QString(line).trimmed().isEmpty()) + m_output << INDENT << line; + + m_output << endl; + } + } + m_output << endl; + } +} +void QtXmlToSphinx::handleDotsTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + const bool consecutiveSnippet = m_lastTagName == QLatin1String("snippet") + || m_lastTagName == QLatin1String("dots") || m_lastTagName == QLatin1String("codeline"); + if (consecutiveSnippet) { + m_output.flush(); + m_output.string()->chop(2); + } + Indentation indentation(INDENT); + pushOutputBuffer(); + m_output << INDENT; + int indent = reader.attributes().value(QLatin1String("indent")).toString().toInt(); + for (int i = 0; i < indent; ++i) + m_output << ' '; + } else if (token == QXmlStreamReader::Characters) { + m_output << reader.text().toString(); + } else if (token == QXmlStreamReader::EndElement) { + m_output << popOutputBuffer() << "\n\n\n"; + } +} + +void QtXmlToSphinx::handleTableTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + m_currentTable.clear(); + m_tableHasHeader = false; + } else if (token == QXmlStreamReader::EndElement) { + // write the table on m_output + m_currentTable.enableHeader(m_tableHasHeader); + m_currentTable.normalize(); + m_output << m_currentTable; + m_currentTable.clear(); + } +} + +void QtXmlToSphinx::handleTermTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + pushOutputBuffer(); + } else if (token == QXmlStreamReader::Characters) { + m_output << reader.text().toString().replace(QLatin1String("::"), QLatin1String(".")); + } else if (token == QXmlStreamReader::EndElement) { + TableCell cell; + cell.data = popOutputBuffer().trimmed(); + m_currentTable << (TableRow() << cell); + } +} + + +void QtXmlToSphinx::handleItemTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + if (m_currentTable.isEmpty()) + m_currentTable << TableRow(); + TableRow& row = m_currentTable.last(); + TableCell cell; + cell.colSpan = reader.attributes().value(QLatin1String("colspan")).toString().toShort(); + cell.rowSpan = reader.attributes().value(QLatin1String("rowspan")).toString().toShort(); + row << cell; + pushOutputBuffer(); + } else if (token == QXmlStreamReader::EndElement) { + QString data = popOutputBuffer().trimmed(); + if (!m_currentTable.isEmpty()) { + TableRow& row = m_currentTable.last(); + if (!row.isEmpty()) + row.last().data = data; + } + } +} + +void QtXmlToSphinx::handleRowTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + m_tableHasHeader = reader.name() == QLatin1String("header"); + m_currentTable << TableRow(); + } +} + +void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader) +{ + // BUG We do not support a list inside a table cell + static QString listType; + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + listType = reader.attributes().value(QLatin1String("type")).toString(); + if (listType == QLatin1String("enum")) { + m_currentTable << (TableRow() << "Constant" << "Description"); + m_tableHasHeader = true; + } + INDENT.indent--; + } else if (token == QXmlStreamReader::EndElement) { + INDENT.indent++; + if (!m_currentTable.isEmpty()) { + if (listType == QLatin1String("bullet")) { + m_output << endl; + for (const TableCell &cell : m_currentTable.constFirst()) { + QStringList itemLines = cell.data.split(QLatin1Char('\n')); + m_output << INDENT << "* " << itemLines.first() << endl; + for (int i = 1, max = itemLines.count(); i < max; ++i) + m_output << INDENT << " " << itemLines[i] << endl; + } + m_output << endl; + } else if (listType == QLatin1String("enum")) { + m_currentTable.enableHeader(m_tableHasHeader); + m_currentTable.normalize(); + m_output << m_currentTable; + } + } + m_currentTable.clear(); + } +} + +void QtXmlToSphinx::handleLinkTag(QXmlStreamReader& reader) +{ + static QString l_linktag; + static QString l_linkref; + static QString l_linktext; + static QString l_linktagending; + static QString l_type; + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + l_linktagending = QLatin1String("` "); + if (m_insideBold) { + l_linktag.prepend(QLatin1String("**")); + l_linktagending.append(QLatin1String("**")); + } else if (m_insideItalic) { + l_linktag.prepend(QLatin1Char('*')); + l_linktagending.append(QLatin1Char('*')); + } + l_type = reader.attributes().value(QLatin1String("type")).toString(); + + // TODO: create a flag PROPERTY-AS-FUNCTION to ask if the properties + // are recognized as such or not in the binding + if (l_type == QLatin1String("property")) + l_type = QLatin1String("function"); + + if (l_type == QLatin1String("typedef")) + l_type = QLatin1String("class"); + + QString linkSource; + if (l_type == QLatin1String("function") || l_type == QLatin1String("class")) { + linkSource = QLatin1String("raw"); + } else if (l_type == QLatin1String("enum")) { + linkSource = QLatin1String("enum"); + } else if (l_type == QLatin1String("page")) { + linkSource = QLatin1String("page"); + } else { + linkSource = QLatin1String("href"); + } + + l_linkref = reader.attributes().value(linkSource).toString(); + l_linkref.replace(QLatin1String("::"), QLatin1String(".")); + l_linkref.remove(QLatin1String("()")); + + if (l_type == QLatin1String("function") && !m_context.isEmpty()) { + l_linktag = QLatin1String(" :meth:`"); + QStringList rawlinklist = l_linkref.split(QLatin1Char('.')); + if (rawlinklist.size() == 1 || rawlinklist.first() == m_context) { + QString context = resolveContextForMethod(rawlinklist.last()); + if (!l_linkref.startsWith(context)) + l_linkref.prepend(context + QLatin1Char('.')); + } else { + l_linkref = expandFunction(l_linkref); + } + } else if (l_type == QLatin1String("function") && m_context.isEmpty()) { + l_linktag = QLatin1String(" :func:`"); + } else if (l_type == QLatin1String("class")) { + l_linktag = QLatin1String(" :class:`"); + TypeEntry* type = TypeDatabase::instance()->findType(l_linkref); + if (type) { + l_linkref = type->qualifiedTargetLangName(); + } else { // fall back to the old heuristic if the type wasn't found. + QStringList rawlinklist = l_linkref.split(QLatin1Char('.')); + QStringList splittedContext = m_context.split(QLatin1Char('.')); + if (rawlinklist.size() == 1 || rawlinklist.first() == splittedContext.last()) { + splittedContext.removeLast(); + l_linkref.prepend(QLatin1Char('~') + splittedContext.join(QLatin1Char('.')) + + QLatin1Char('.')); + } + } + } else if (l_type == QLatin1String("enum")) { + l_linktag = QLatin1String(" :attr:`"); + } else if (l_type == QLatin1String("page") && l_linkref == m_generator->moduleName()) { + l_linktag = QLatin1String(" :mod:`"); + } else { + l_linktag = QLatin1String(" :ref:`"); + } + + } else if (token == QXmlStreamReader::Characters) { + QString linktext = reader.text().toString(); + linktext.replace(QLatin1String("::"), QLatin1String(".")); + // avoid constLast to stay Qt 5.5 compatible + QString item = l_linkref.split(QLatin1Char('.')).last(); + if (l_linkref == linktext + || (l_linkref + QLatin1String("()")) == linktext + || item == linktext + || (item + QLatin1String("()")) == linktext) + l_linktext.clear(); + else + l_linktext = linktext + QLatin1Char('<'); + } else if (token == QXmlStreamReader::EndElement) { + if (!l_linktext.isEmpty()) + l_linktagending.prepend(QLatin1Char('>')); + m_output << l_linktag << l_linktext << escape(l_linkref) << l_linktagending; + } +} + +void QtXmlToSphinx::handleImageTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + QString href = reader.attributes().value(QLatin1String("href")).toString(); + QString packageName = m_generator->packageName(); + packageName.replace(QLatin1Char('.'), QLatin1Char('/')); + QDir dir(m_generator->outputDirectory() + QLatin1Char('/') + packageName); + QString imgPath = dir.relativeFilePath(m_generator->libSourceDir() + QLatin1String("/doc/src/")) + + QLatin1Char('/') + href; + + if (reader.name() == QLatin1String("image")) + m_output << INDENT << ".. image:: " << imgPath << endl << endl; + else + m_output << ".. image:: " << imgPath << ' '; + } +} + +void QtXmlToSphinx::handleRawTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + QString format = reader.attributes().value(QLatin1String("format")).toString(); + m_output << INDENT << ".. raw:: " << format.toLower() << endl << endl; + } else if (token == QXmlStreamReader::Characters) { + const QStringList lst(reader.text().toString().split(QLatin1Char('\n'))); + for (const QString &row : lst) + m_output << INDENT << INDENT << row << endl; + } else if (token == QXmlStreamReader::EndElement) { + m_output << endl << endl; + } +} + +void QtXmlToSphinx::handleCodeTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + QString format = reader.attributes().value(QLatin1String("format")).toString(); + m_output << INDENT << "::" << endl << endl; + INDENT.indent++; + } else if (token == QXmlStreamReader::Characters) { + const QStringList lst(reader.text().toString().split(QLatin1Char('\n'))); + for (const QString row : lst) + m_output << INDENT << INDENT << row << endl; + } else if (token == QXmlStreamReader::EndElement) { + m_output << endl << endl; + INDENT.indent--; + } +} + +void QtXmlToSphinx::handleUnknownTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) + qCDebug(lcShiboken).noquote().nospace() << "Unknown QtDoc tag: \"" << reader.name().toString() << "\"."; +} + +void QtXmlToSphinx::handleSuperScriptTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + m_output << " :sup:`"; + pushOutputBuffer(); + } else if (token == QXmlStreamReader::Characters) { + m_output << reader.text().toString(); + } else if (token == QXmlStreamReader::EndElement) { + m_output << popOutputBuffer(); + m_output << '`'; + } +} + +void QtXmlToSphinx::handleIgnoredTag(QXmlStreamReader&) +{ +} + +void QtXmlToSphinx::handleUselessTag(QXmlStreamReader&) +{ + // Tag "description" just marks the init of "Detailed description" title. + // Tag "definition" just marks enums. We have a different way to process them. +} + +void QtXmlToSphinx::handleAnchorTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + QString anchor; + if (reader.attributes().hasAttribute(QLatin1String("id"))) + anchor = reader.attributes().value(QLatin1String("id")).toString(); + else if (reader.attributes().hasAttribute(QLatin1String("name"))) + anchor = reader.attributes().value(QLatin1String("name")).toString(); + if (!anchor.isEmpty() && m_opened_anchor != anchor) { + m_opened_anchor = anchor; + m_output << INDENT << ".. _" << m_context << "_" << anchor.toLower() << ":" << endl << endl; + } + } else if (token == QXmlStreamReader::EndElement) { + m_opened_anchor.clear(); + } +} + +void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::Characters) { + QString location = reader.text().toString(); + QString identifier; + location.prepend(m_generator->libSourceDir() + QLatin1Char('/')); + QString code = readFromLocation(location, identifier); + + m_output << INDENT << "::\n\n"; + Indentation indentation(INDENT); + if (code.isEmpty()) { + m_output << INDENT << "" << endl; + } else { + const QStringList lines = code.split(QLatin1Char('\n')); + for (const QString &line : lines) { + if (!QString(line).trimmed().isEmpty()) + m_output << INDENT << line; + + m_output << endl; + } + } + m_output << endl; + } +} + +void QtXmlToSphinx::Table::normalize() +{ + if (m_normalized || isEmpty()) + return; + + int row; + int col; + QtXmlToSphinx::Table& self = *this; + + //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(); + // add col spans + for (row = 0; row < count(); ++row) { + for (col = 0; col < at(row).count(); ++col) { + QtXmlToSphinx::TableCell& cell = self[row][col]; + bool mergeCols = (col >= maxCols); + if (cell.colSpan > 0) { + QtXmlToSphinx::TableCell newCell; + newCell.colSpan = -1; + for (int i = 0, max = cell.colSpan-1; i < max; ++i) { + self[row].insert(col+1, newCell); + } + cell.colSpan = 0; + col++; + } else if (mergeCols) { + self[row][maxCols - 1].data += QLatin1Char(' ') + cell.data; + } + } + } + + // row spans + const int numCols = first().count(); + for (col = 0; col < numCols; ++col) { + for (row = 0; row < count(); ++row) { + if (col < self[row].count()) { + QtXmlToSphinx::TableCell& cell = self[row][col]; + if (cell.rowSpan > 0) { + QtXmlToSphinx::TableCell newCell; + newCell.rowSpan = -1; + int max = std::min(cell.rowSpan - 1, count()); + cell.rowSpan = 0; + for (int i = 0; i < max; ++i) { + self[row+i+1].insert(col, newCell); + } + row++; + } + } + } + } + m_normalized = true; +} + +QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table) +{ + if (table.isEmpty()) + return s; + + if (!table.isNormalized()) { + qCDebug(lcShiboken) << "Attempt to print an unnormalized table!"; + return s; + } + + // calc width and height of each column and row + QVector colWidths(table.first().count()); + QVector rowHeights(table.count()); + for (int i = 0, maxI = table.count(); i < maxI; ++i) { + const QtXmlToSphinx::TableRow& row = table[i]; + for (int j = 0, maxJ = std::min(row.count(), colWidths.size()); j < maxJ; ++j) { + const QStringList rowLines = row[j].data.split(QLatin1Char('\n')); // cache this would be a good idea + for (const QString &str : rowLines) + colWidths[j] = std::max(colWidths[j], str.count()); + rowHeights[i] = std::max(rowHeights[i], row[j].data.count(QLatin1Char('\n')) + 1); + } + } + + if (!*std::max_element(colWidths.begin(), colWidths.end())) + return s; // empty table (table with empty cells) + + // create a horizontal line to be used later. + QString horizontalLine = QLatin1String("+"); + for (int i = 0, max = colWidths.count(); i < max; ++i) { + horizontalLine += createRepeatedChar(colWidths[i], '-'); + horizontalLine += QLatin1Char('+'); + } + + // write table rows + for (int i = 0, maxI = table.count(); i < maxI; ++i) { // for each row + const QtXmlToSphinx::TableRow& row = table[i]; + + // print line + s << INDENT << '+'; + for (int col = 0, max = colWidths.count(); col < max; ++col) { + char c; + if (col >= row.length() || row[col].rowSpan == -1) + c = ' '; + else if (i == 1 && table.hasHeader()) + c = '='; + else + c = '-'; + s << createRepeatedChar(colWidths[col], c) << '+'; + } + s << endl; + + + // Print the table cells + for (int rowLine = 0; rowLine < rowHeights[i]; ++rowLine) { // for each line in a row + for (int j = 0, maxJ = std::min(row.count(), colWidths.size()); j < maxJ; ++j) { // for each column + const QtXmlToSphinx::TableCell& cell = row[j]; + QStringList rowLines = cell.data.split(QLatin1Char('\n')); // FIXME: Cache this!!! + if (!j) // First column, so we need print the identation + s << INDENT; + + if (!j || !cell.colSpan) + s << '|'; + else + s << ' '; + s << qSetFieldWidth(colWidths[j]) << left; + s << (rowLine < rowLines.count() ? rowLines[rowLine] : QString()); + s << qSetFieldWidth(0); + } + s << '|' << endl; + } + } + s << INDENT << horizontalLine << endl; + s << endl; + return s; +} + +static QString getFuncName(const AbstractMetaFunction* cppFunc) { + static bool hashInitialized = false; + static QHash operatorsHash; + if (!hashInitialized) { + operatorsHash.insert(QLatin1String("operator+"), QLatin1String("__add__")); + operatorsHash.insert(QLatin1String("operator+="), QLatin1String("__iadd__")); + operatorsHash.insert(QLatin1String("operator-"), QLatin1String("__sub__")); + operatorsHash.insert(QLatin1String("operator-="), QLatin1String("__isub__")); + operatorsHash.insert(QLatin1String("operator*"), QLatin1String("__mul__")); + operatorsHash.insert(QLatin1String("operator*="), QLatin1String("__imul__")); + operatorsHash.insert(QLatin1String("operator/"), QLatin1String("__div__")); + operatorsHash.insert(QLatin1String("operator/="), QLatin1String("__idiv__")); + operatorsHash.insert(QLatin1String("operator%"), QLatin1String("__mod__")); + operatorsHash.insert(QLatin1String("operator%="), QLatin1String("__imod__")); + operatorsHash.insert(QLatin1String("operator<<"), QLatin1String("__lshift__")); + operatorsHash.insert(QLatin1String("operator<<="), QLatin1String("__ilshift__")); + operatorsHash.insert(QLatin1String("operator>>"), QLatin1String("__rshift__")); + operatorsHash.insert(QLatin1String("operator>>="), QLatin1String("__irshift__")); + operatorsHash.insert(QLatin1String("operator&"), QLatin1String("__and__")); + operatorsHash.insert(QLatin1String("operator&="), QLatin1String("__iand__")); + operatorsHash.insert(QLatin1String("operator|"), QLatin1String("__or__")); + operatorsHash.insert(QLatin1String("operator|="), QLatin1String("__ior__")); + operatorsHash.insert(QLatin1String("operator^"), QLatin1String("__xor__")); + operatorsHash.insert(QLatin1String("operator^="), QLatin1String("__ixor__")); + operatorsHash.insert(QLatin1String("operator=="), QLatin1String("__eq__")); + operatorsHash.insert(QLatin1String("operator!="), QLatin1String("__ne__")); + operatorsHash.insert(QLatin1String("operator<"), QLatin1String("__lt__")); + operatorsHash.insert(QLatin1String("operator<="), QLatin1String("__le__")); + operatorsHash.insert(QLatin1String("operator>"), QLatin1String("__gt__")); + operatorsHash.insert(QLatin1String("operator>="), QLatin1String("__ge__")); + hashInitialized = true; + } + + QHash::const_iterator it = operatorsHash.find(cppFunc->name()); + QString result = it != operatorsHash.end() ? it.value() : cppFunc->name(); + result.replace(QLatin1String("::"), QLatin1String(".")); + return result; +} + +QtDocGenerator::QtDocGenerator() : m_docParser(0) +{ +} + +QtDocGenerator::~QtDocGenerator() +{ + delete m_docParser; +} + +QString QtDocGenerator::fileNamePrefix() const +{ + return QLatin1String(".rst"); +} + +QString QtDocGenerator::fileNameForContext(GeneratorContext &context) const +{ + const AbstractMetaClass *metaClass = context.metaClass(); + if (!context.forSmartPointer()) { + return getClassTargetFullName(metaClass, false) + fileNamePrefix(); + } else { + const AbstractMetaType *smartPointerType = context.preciseType(); + QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass); + return fileNameBase + fileNamePrefix(); + } +} + +void QtDocGenerator::writeFormatedText(QTextStream& s, const Documentation& doc, const AbstractMetaClass* metaClass) +{ + QString metaClassName; + + if (metaClass) + metaClassName = getClassTargetFullName(metaClass); + + if (doc.format() == Documentation::Native) { + QtXmlToSphinx x(this, doc.value(), metaClassName); + s << x; + } else { + const QStringList lines = doc.value().split(QLatin1Char('\n')); + QRegExp regex(QLatin1String("\\S")); // non-space character + int typesystemIndentation = std::numeric_limits().max(); + // check how many spaces must be removed from the begining of each line + for (const QString &line : lines) { + int idx = line.indexOf(regex); + if (idx >= 0) + typesystemIndentation = qMin(typesystemIndentation, idx); + } + for (QString line : lines) + s << INDENT << line.remove(0, typesystemIndentation) << endl; + } + + s << endl; +} + +static void writeInheritedByList(QTextStream& s, const AbstractMetaClass* metaClass, const AbstractMetaClassList& allClasses) +{ + AbstractMetaClassList res; + for (AbstractMetaClass *c : allClasses) { + if (c != metaClass && c->inheritsFrom(metaClass)) + res << c; + } + + if (res.isEmpty()) + return; + + s << "**Inherited by:** "; + QStringList classes; + for (AbstractMetaClass *c : qAsConst(res)) + classes << QLatin1String(":ref:`") + getClassTargetFullName(c, false) + QLatin1Char('`'); + s << classes.join(QLatin1String(", ")) << endl << endl; +} + +void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) +{ + AbstractMetaClass *metaClass = classContext.metaClass(); + qCDebug(lcShiboken).noquote().nospace() << "Generating Documentation for " << metaClass->fullName(); + + m_packages[metaClass->package()] << fileNameForContext(classContext); + + m_docParser->setPackageName(metaClass->package()); + m_docParser->fillDocumentation(const_cast(metaClass)); + + s << ".. module:: " << metaClass->package() << endl; + QString className = getClassTargetFullName(metaClass, false); + s << ".. _" << className << ":" << endl << endl; + + s << className << endl; + s << createRepeatedChar(className.count(), '*') << endl << endl; + + s << ".. inheritance-diagram:: " << className << endl + << " :parts: 2" << endl << endl; // TODO: This would be a parameter in the future... + + + writeInheritedByList(s, metaClass, classes()); + + if (metaClass->typeEntry() && (metaClass->typeEntry()->version() != 0)) + s << ".. note:: This class was introduced in Qt " << metaClass->typeEntry()->version() << endl; + + writeFunctionList(s, metaClass); + + //Function list + AbstractMetaFunctionList functionList = metaClass->functions(); + qSort(functionList.begin(), functionList.end(), functionSort); + + s << "Detailed Description\n" + "--------------------\n\n"; + + writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass, 0); + if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass, 0)) + writeFormatedText(s, metaClass->documentation(), metaClass); + + if (!metaClass->isNamespace()) + writeConstructors(s, metaClass); + writeEnums(s, metaClass); + if (!metaClass->isNamespace()) + writeFields(s, metaClass); + + + for (AbstractMetaFunction *func : qAsConst(functionList)) { + if (shouldSkip(func)) + continue; + + if (func->isStatic()) + s << ".. staticmethod:: "; + else + s << ".. method:: "; + + writeFunction(s, true, metaClass, func); + } + + writeInjectDocumentation(s, TypeSystem::DocModificationAppend, metaClass, 0); +} + +void QtDocGenerator::writeFunctionList(QTextStream& s, const AbstractMetaClass* cppClass) +{ + QStringList functionList; + QStringList virtualList; + QStringList signalList; + QStringList slotList; + QStringList staticFunctionList; + + const AbstractMetaFunctionList &classFunctions = cppClass->functions(); + for (AbstractMetaFunction *func : classFunctions) { + if (shouldSkip(func)) + continue; + + QString className; + if (!func->isConstructor()) + className = getClassTargetFullName(cppClass) + QLatin1Char('.'); + else if (func->implementingClass() && func->implementingClass()->enclosingClass()) + className = getClassTargetFullName(func->implementingClass()->enclosingClass()) + QLatin1Char('.'); + QString funcName = getFuncName(func); + + QString str = QLatin1String("def :meth:`"); + + str += funcName; + str += QLatin1Char('<'); + if (!funcName.startsWith(className)) + str += className; + str += funcName; + str += QLatin1String(">` ("); + str += parseArgDocStyle(cppClass, func); + str += QLatin1Char(')'); + + if (func->isStatic()) + staticFunctionList << str; + else if (func->isVirtual()) + virtualList << str; + else if (func->isSignal()) + signalList << str; + else if (func->isSlot()) + slotList << str; + else + functionList << str; + } + + if ((functionList.size() > 0) || (staticFunctionList.size() > 0)) { + QtXmlToSphinx::Table functionTable; + QtXmlToSphinx::TableRow row; + + s << "Synopsis" << endl + << "--------" << endl << endl; + + writeFunctionBlock(s, QLatin1String("Functions"), functionList); + writeFunctionBlock(s, QLatin1String("Virtual functions"), virtualList); + writeFunctionBlock(s, QLatin1String("Slots"), slotList); + writeFunctionBlock(s, QLatin1String("Signals"), signalList); + writeFunctionBlock(s, QLatin1String("Static functions"), staticFunctionList); + } +} + +void QtDocGenerator::writeFunctionBlock(QTextStream& s, const QString& title, QStringList& functions) +{ + if (functions.size() > 0) { + s << title << endl + << QString(title.size(), QLatin1Char('^')) << endl; + + qSort(functions); + + s << ".. container:: function_list" << endl << endl; + Indentation indentation(INDENT); + for (const QString &func : qAsConst(functions)) + s << '*' << INDENT << func << endl; + + s << endl << endl; + } +} + +void QtDocGenerator::writeEnums(QTextStream& s, const AbstractMetaClass* cppClass) +{ + static const QString section_title = QLatin1String(".. attribute:: "); + + const AbstractMetaEnumList &enums = cppClass->enums(); + for (AbstractMetaEnum *en : enums) { + s << section_title << getClassTargetFullName(cppClass) << '.' << en->name() << endl << endl; + writeFormatedText(s, en->documentation(), cppClass); + + if (en->typeEntry() && (en->typeEntry()->version() != 0)) + s << ".. note:: This enum was introduced or modified in Qt " << en->typeEntry()->version() << endl; + } + +} + +void QtDocGenerator::writeFields(QTextStream& s, const AbstractMetaClass* cppClass) +{ + static const QString section_title = QLatin1String(".. attribute:: "); + + const AbstractMetaFieldList &fields = cppClass->fields(); + for (AbstractMetaField *field : fields) { + s << section_title << getClassTargetFullName(cppClass) << "." << field->name() << endl << endl; + //TODO: request for member ‘documentation’ is ambiguous + writeFormatedText(s, field->AbstractMetaAttributes::documentation(), cppClass); + } +} + +void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass* cppClass) +{ + static const QString sectionTitle = QLatin1String(".. class:: "); + static const QString sectionTitleSpace = QString(sectionTitle.size(), QLatin1Char(' ')); + + const AbstractMetaFunctionList lst = cppClass->queryFunctions(AbstractMetaClass::Constructors | AbstractMetaClass::Visible); + + bool first = true; + QHash arg_map; + + for (AbstractMetaFunction *func : lst) { + if (func->isModifiedRemoved()) + continue; + + if (first) { + first = false; + s << sectionTitle; + } else { + s << sectionTitleSpace; + } + writeFunction(s, false, cppClass, func); + const AbstractMetaArgumentList &arguments = func->arguments(); + for (AbstractMetaArgument *arg : arguments) { + if (!arg_map.contains(arg->name())) { + arg_map.insert(arg->name(), arg); + } + } + } + + s << endl; + + for (QHash::const_iterator it = arg_map.cbegin(), end = arg_map.cend(); it != end; ++it) { + Indentation indentation(INDENT); + writeParamerteType(s, cppClass, it.value()); + } + + s << endl; + + for (AbstractMetaFunction *func : lst) + writeFormatedText(s, func->documentation(), cppClass); +} + +QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass* cppClass, const AbstractMetaFunction* func) +{ + QString ret; + int optArgs = 0; + + const AbstractMetaArgumentList &arguments = func->arguments(); + for (AbstractMetaArgument *arg : arguments) { + + if (func->argumentRemoved(arg->argumentIndex() + 1)) + continue; + + bool thisIsoptional = !arg->defaultValueExpression().isEmpty(); + if (optArgs || thisIsoptional) { + ret += QLatin1Char('['); + optArgs++; + } + + if (arg->argumentIndex() > 0) + ret += QLatin1String(", "); + + ret += arg->name(); + + if (thisIsoptional) { + QString defValue = arg->defaultValueExpression(); + if (defValue == QLatin1String("QString()")) { + defValue = QLatin1String("\"\""); + } else if (defValue == QLatin1String("QStringList()") + || defValue.startsWith(QLatin1String("QVector")) + || defValue.startsWith(QLatin1String("QList"))) { + defValue = QLatin1String("list()"); + } else if (defValue == QLatin1String("QVariant()")) { + defValue = QLatin1String("None"); + } else { + defValue.replace(QLatin1String("::"), QLatin1String(".")); + if (defValue == QLatin1String("0") && (arg->type()->isQObject() || arg->type()->isObject())) + defValue = QLatin1String("None"); + } + ret += QLatin1Char('=') + defValue; + } + } + + ret += QString(optArgs, QLatin1Char(']')); + return ret; +} + +void QtDocGenerator::writeDocSnips(QTextStream &s, + const CodeSnipList &codeSnips, + TypeSystem::CodeSnipPosition position, + TypeSystem::Language language) +{ + Indentation indentation(INDENT); + QStringList invalidStrings; + const static QString startMarkup = QLatin1String("[sphinx-begin]"); + const static QString endMarkup = QLatin1String("[sphinx-end]"); + + invalidStrings << QLatin1String("*") << QLatin1String("//") << QLatin1String("/*") << QLatin1String("*/"); + + for (const CodeSnip &snip : codeSnips) { + if ((snip.position != position) || + !(snip.language & language)) + continue; + + QString code = snip.code(); + while (code.contains(startMarkup) && code.contains(endMarkup)) { + int startBlock = code.indexOf(startMarkup) + startMarkup.size(); + int endBlock = code.indexOf(endMarkup); + + if ((startBlock == -1) || (endBlock == -1)) + break; + + QString codeBlock = code.mid(startBlock, endBlock - startBlock); + const QStringList rows = codeBlock.split(QLatin1Char('\n')); + int currenRow = 0; + int offset = 0; + + for (QString row : rows) { + for (const QString &invalidString : qAsConst(invalidStrings)) + row.remove(invalidString); + + if (row.trimmed().size() == 0) { + if (currenRow == 0) + continue; + else + s << endl; + } + + if (currenRow == 0) { + //find offset + for (int i=0, i_max = row.size(); i < i_max; i++) { + if (row[i] == QLatin1Char(' ')) + offset++; + else if (row[i] == QLatin1Char('\n')) + offset = 0; + else + break; + } + } + row = row.mid(offset); + s << row << endl; + currenRow++; + } + + code = code.mid(endBlock+endMarkup.size()); + } + } +} + +bool QtDocGenerator::writeInjectDocumentation(QTextStream& s, + TypeSystem::DocModificationMode mode, + const AbstractMetaClass* cppClass, + const AbstractMetaFunction* func) +{ + Indentation indentation(INDENT); + bool didSomething = false; + + const DocModificationList &mods = cppClass->typeEntry()->docModifications(); + for (const DocModification &mod : mods) { + if (mod.mode() == mode) { + bool modOk = func ? mod.signature() == func->minimalSignature() : mod.signature().isEmpty(); + + if (modOk) { + Documentation doc; + Documentation::Format fmt; + + if (mod.format == TypeSystem::NativeCode) + fmt = Documentation::Native; + else if (mod.format == TypeSystem::TargetLangCode) + fmt = Documentation::Target; + else + continue; + + doc.setValue(mod.code() , fmt); + writeFormatedText(s, doc, cppClass); + didSomething = true; + } + } + } + + s << endl; + + // TODO: Deprecate the use of doc string on glue code. + // This is pre "add-function" and "inject-documentation" tags. + const TypeSystem::CodeSnipPosition pos = mode == TypeSystem::DocModificationPrepend + ? TypeSystem::CodeSnipPositionBeginning : TypeSystem::CodeSnipPositionEnd; + if (func) + writeDocSnips(s, func->injectedCodeSnips(), pos, TypeSystem::TargetLangCode); + else + writeDocSnips(s, cppClass->typeEntry()->codeSnips(), pos, TypeSystem::TargetLangCode); + return didSomething; +} + +void QtDocGenerator::writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func) +{ + QString className; + if (!func->isConstructor()) + className = getClassTargetFullName(cppClass) + QLatin1Char('.'); + else if (func->implementingClass() && func->implementingClass()->enclosingClass()) + className = getClassTargetFullName(func->implementingClass()->enclosingClass()) + QLatin1Char('.'); + + QString funcName = getFuncName(func); + if (!funcName.startsWith(className)) + funcName = className + funcName; + + s << funcName << "(" << parseArgDocStyle(cppClass, func) << ")"; +} + +QString QtDocGenerator::translateToPythonType(const AbstractMetaType* type, const AbstractMetaClass* cppClass) +{ + QString strType; + if (type->name() == QLatin1String("QString")) { + strType = QLatin1String("unicode"); + } else if (type->name() == QLatin1String("QVariant")) { + strType = QLatin1String("object"); + } else if (type->name() == QLatin1String("QStringList")) { + strType = QLatin1String("list of strings"); + } else if (type->isConstant() && type->name() == QLatin1String("char") && type->indirections() == 1) { + strType = QLatin1String("str"); + } else if (type->name().startsWith(QLatin1String("unsigned short"))) { + strType = QLatin1String("int"); + } else if (type->name().startsWith(QLatin1String("unsigned "))) { // uint and ulong + strType = QLatin1String("long"); + } else if (type->isContainer()) { + QString strType = translateType(type, cppClass, Options(ExcludeConst) | ExcludeReference); + strType.remove(QLatin1Char('*')); + strType.remove(QLatin1Char('>')); + strType.remove(QLatin1Char('<')); + strType.replace(QLatin1String("::"), QLatin1String(".")); + if (strType.contains(QLatin1String("QList")) || strType.contains(QLatin1String("QVector"))) { + strType.replace(QLatin1String("QList"), QLatin1String("list of ")); + strType.replace(QLatin1String("QVector"), QLatin1String("list of ")); + } else if (strType.contains(QLatin1String("QHash")) || strType.contains(QLatin1String("QMap"))) { + strType.remove(QLatin1String("QHash")); + strType.remove(QLatin1String("QMap")); + QStringList types = strType.split(QLatin1Char(',')); + strType = QString::fromLatin1("Dictionary with keys of type %1 and values of type %2.") + .arg(types[0], types[1]); + } + } else { + QString refTag; + if (type->isEnum()) + refTag = QLatin1String("attr"); + else + refTag = QLatin1String("class"); + strType = QLatin1Char(':') + refTag + QLatin1String(":`") + type->fullName() + QLatin1Char('`'); + } + return strType; +} + +void QtDocGenerator::writeParamerteType(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaArgument* arg) +{ + s << INDENT << ":param " << arg->name() << ": " + << translateToPythonType(arg->type(), cppClass) << endl; +} + +void QtDocGenerator::writeFunctionParametersType(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func) +{ + Indentation indentation(INDENT); + + s << endl; + const AbstractMetaArgumentList &funcArgs = func->arguments(); + for (AbstractMetaArgument *arg : funcArgs) { + + if (func->argumentRemoved(arg->argumentIndex() + 1)) + continue; + + writeParamerteType(s, cppClass, arg); + } + + if (!func->isConstructor() && func->type()) { + + QString retType; + // check if the return type was modified + const FunctionModificationList &mods = func->modifications(); + for (const FunctionModification &mod : mods) { + for (const ArgumentModification &argMod : mod.argument_mods) { + if (argMod.index == 0) { + retType = argMod.modified_type; + break; + } + } + } + + if (retType.isEmpty()) + retType = translateToPythonType(func->type(), cppClass); + s << INDENT << ":rtype: " << retType << endl; + } + s << endl; +} + +void QtDocGenerator::writeFunction(QTextStream& s, bool writeDoc, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func) +{ + writeFunctionSignature(s, cppClass, func); + s << endl; + + if (func->typeEntry() && (func->typeEntry()->version() != 0)) + s << ".. note:: This method was introduced in Qt " << func->typeEntry()->version() << endl; + + if (writeDoc) { + s << endl; + writeFunctionParametersType(s, cppClass, func); + s << endl; + writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, cppClass, func); + if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, cppClass, func)) + writeFormatedText(s, func->documentation(), cppClass); + writeInjectDocumentation(s, TypeSystem::DocModificationAppend, cppClass, func); + } +} + +static void writeFancyToc(QTextStream& s, const QStringList& items, int cols = 4) +{ + typedef QMap TocMap; + TocMap tocMap; + QChar Q = QLatin1Char('Q'); + QChar idx; + for (QString item : items) { + if (item.isEmpty()) + continue; + if (item.startsWith(Q) && item.length() > 1) + idx = item[1]; + item.chop(4); // Remove the .rst extension + tocMap[idx] << item; + } + QtXmlToSphinx::Table table; + QtXmlToSphinx::TableRow row; + + int itemsPerCol = (items.size() + tocMap.size()*2) / cols; + QString currentColData; + int i = 0; + QTextStream ss(¤tColData); + QMutableMapIterator it(tocMap); + while (it.hasNext()) { + it.next(); + qSort(it.value()); + + if (i) + ss << endl; + + ss << "**" << it.key() << "**" << endl << endl; + i += 2; // a letter title is equivalent to two entries in space + for (const QString &item : qAsConst(it.value())) { + ss << "* :doc:`" << item << "`" << endl; + ++i; + + // end of column detected! + if (i > itemsPerCol) { + ss.flush(); + QtXmlToSphinx::TableCell cell(currentColData); + row << cell; + currentColData.clear(); + i = 0; + } + } + } + if (i) { + ss.flush(); + QtXmlToSphinx::TableCell cell(currentColData); + row << cell; + currentColData.clear(); + i = 0; + } + table << row; + table.normalize(); + s << ".. container:: pysidetoc" << endl << endl; + s << table; +} + +bool QtDocGenerator::finishGeneration() +{ + if (classes().isEmpty()) + return true; + + QMap::iterator it = m_packages.begin(); + for (; it != m_packages.end(); ++it) { + QString key = it.key(); + key.replace(QLatin1Char('.'), QLatin1Char('/')); + QString outputDir = outputDirectory() + QLatin1Char('/') + key; + FileOut output(outputDir + QLatin1String("/index.rst")); + QTextStream& s = output.stream; + + s << ".. module:: " << it.key() << endl << endl; + + QString title = it.key(); + s << title << endl; + s << createRepeatedChar(title.length(), '*') << endl << endl; + + /* Avoid showing "Detailed Description for *every* class in toc tree */ + Indentation indentation(INDENT); + + // Search for extra-sections + if (!m_extraSectionDir.isEmpty()) { + QDir extraSectionDir(m_extraSectionDir); + QStringList fileList = extraSectionDir.entryList(QStringList() << (it.key() + QLatin1String("?*.rst")), QDir::Files); + QStringList::iterator it2 = fileList.begin(); + for (; it2 != fileList.end(); ++it2) { + QString origFileName(*it2); + it2->remove(0, it.key().count() + 1); + QString newFilePath = outputDir + QLatin1Char('/') + *it2; + if (QFile::exists(newFilePath)) + QFile::remove(newFilePath); + if (!QFile::copy(m_extraSectionDir + QLatin1Char('/') + origFileName, newFilePath)) { + qCDebug(lcShiboken).noquote().nospace() << "Error copying extra doc " + << QDir::toNativeSeparators(m_extraSectionDir + QLatin1Char('/') + origFileName) + << " to " << QDir::toNativeSeparators(newFilePath); + } + } + it.value().append(fileList); + } + + writeFancyToc(s, it.value()); + + s << INDENT << ".. container:: hide" << endl << endl; + { + Indentation indentation(INDENT); + s << INDENT << ".. toctree::" << endl; + Indentation deeperIndentation(INDENT); + s << INDENT << ":maxdepth: 1" << endl << endl; + for (const QString &className : qAsConst(it.value())) + s << INDENT << className << endl; + s << endl << endl; + } + + s << "Detailed Description" << endl; + s << "--------------------" << endl << endl; + + // module doc is always wrong and C++istic, so go straight to the extra directory! + QFile moduleDoc(m_extraSectionDir + QLatin1Char('/') + it.key() + QLatin1String(".rst")); + if (moduleDoc.open(QIODevice::ReadOnly | QIODevice::Text)) { + s << moduleDoc.readAll(); + moduleDoc.close(); + } else { + // try the normal way + Documentation moduleDoc = m_docParser->retrieveModuleDocumentation(it.key()); + if (moduleDoc.format() == Documentation::Native) { + QString context = it.key(); + context.remove(0, context.lastIndexOf(QLatin1Char('.')) + 1); + QtXmlToSphinx x(this, moduleDoc.value(), context); + s << x; + } else { + s << moduleDoc.value(); + } + } + } + return true; +} + +bool QtDocGenerator::doSetup(const QMap& 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(new DoxygenParser) + : static_cast(new QtDocParser); + qCDebug(lcShiboken).noquote().nospace() << "doc-parser: " << args.value(QLatin1String("doc-parser")); + + 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); + } + return true; +} + + +QMap QtDocGenerator::options() const +{ + QMap options; + options.insert(QLatin1String("doc-parser"), + QLatin1String("The documentation parser used to interpret the documentation input files (qdoc3|doxygen)")); + options.insert(QLatin1String("library-source-dir"), + QLatin1String("Directory where library source code is located")); + options.insert(QLatin1String("documentation-data-dir"), + QLatin1String("Directory with XML files generated by documentation tool (qdoc3 or Doxygen)")); + options.insert(QLatin1String("documentation-code-snippets-dir"), + QLatin1String("Directory used to search code snippets used by the documentation")); + options.insert(QLatin1String("documentation-extra-sections-dir"), + QLatin1String("Directory used to search for extra documentation sections")); + return options; +} + diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h new file mode 100644 index 000000000..fa8524b21 --- /dev/null +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 DOCGENERATOR_H +#define DOCGENERATOR_H + +#include +#include +#include +#include +#include "generator.h" +#include "docparser.h" +#include "typesystem_enums.h" +#include "typesystem_typedefs.h" + +class QtDocParser; +class AbstractMetaFunction; +class AbstractMetaClass; +QT_BEGIN_NAMESPACE +class QXmlStreamReader; +QT_END_NAMESPACE +class QtDocGenerator; + +class QtXmlToSphinx +{ +public: + struct TableCell + { + short rowSpan; + short colSpan; + QString data; + + TableCell(const QString& text = QString()) : rowSpan(0), colSpan(0), data(text) {} + TableCell(const char* text) : rowSpan(0), colSpan(0), data(QLatin1String(text)) {} + }; + + typedef QList TableRow; + class Table : public QList + { + public: + Table() : m_hasHeader(false), m_normalized(false) + { + } + + void enableHeader(bool enable) + { + m_hasHeader = enable; + } + + bool hasHeader() const + { + return m_hasHeader; + } + + void normalize(); + + bool isNormalized() const + { + return m_normalized; + } + + void clear() { + m_normalized = false; + QList::clear(); + } + + private: + bool m_hasHeader; + bool m_normalized; + }; + + QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context = QString()); + + QString result() const + { + return m_result; + } + +private: + QString resolveContextForMethod(const QString& methodName); + QString expandFunction(const QString& function); + QString transform(const QString& doc); + + void handleHeadingTag(QXmlStreamReader& reader); + void handleParaTag(QXmlStreamReader& reader); + void handleItalicTag(QXmlStreamReader& reader); + void handleBoldTag(QXmlStreamReader& reader); + void handleArgumentTag(QXmlStreamReader& reader); + void handleSeeAlsoTag(QXmlStreamReader& reader); + void handleSnippetTag(QXmlStreamReader& reader); + void handleDotsTag(QXmlStreamReader& reader); + void handleLinkTag(QXmlStreamReader& reader); + void handleImageTag(QXmlStreamReader& reader); + void handleListTag(QXmlStreamReader& reader); + void handleTermTag(QXmlStreamReader& reader); + void handleSuperScriptTag(QXmlStreamReader& reader); + void handleQuoteFileTag(QXmlStreamReader& reader); + + // table tagsvoid QtXmlToSphinx::handleValueTag(QXmlStreamReader& reader) + + void handleTableTag(QXmlStreamReader& reader); + void handleRowTag(QXmlStreamReader& reader); + void handleItemTag(QXmlStreamReader& reader); + void handleRawTag(QXmlStreamReader& reader); + void handleCodeTag(QXmlStreamReader& reader); + + void handleIgnoredTag(QXmlStreamReader& reader); + void handleUnknownTag(QXmlStreamReader& reader); + void handleUselessTag(QXmlStreamReader& reader); + void handleAnchorTag(QXmlStreamReader& reader); + + typedef void (QtXmlToSphinx::*TagHandler)(QXmlStreamReader&); + QHash m_handlerMap; + QStack m_handlers; + QTextStream m_output; + QString m_result; + + QStack m_buffers; + + + Table m_currentTable; + bool m_tableHasHeader; + QString m_context; + QtDocGenerator* m_generator; + bool m_insideBold; + bool m_insideItalic; + QString m_lastTagName; + QString m_opened_anchor; + + QString readFromLocations(const QStringList& locations, const QString& path, const QString& identifier); + QString readFromLocation(const QString& location, const QString& identifier, bool* ok = 0); + void pushOutputBuffer(); + QString popOutputBuffer(); + void writeTable(Table& table); +}; + +inline QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx& xmlToSphinx) +{ + return s << xmlToSphinx.result(); +} + +QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table); + +/** +* The DocGenerator generates documentation from library being binded. +*/ +class QtDocGenerator : public Generator +{ +public: + QtDocGenerator(); + ~QtDocGenerator(); + + QString libSourceDir() const + { + return m_libSourceDir; + } + + bool doSetup(const QMap& args); + + const char* name() const + { + return "QtDocGenerator"; + } + + QMap options() const; + + QStringList codeSnippetDirs() const + { + return m_codeSnippetDirs; + } + +protected: + QString fileNamePrefix() const; + QString fileNameForContext(GeneratorContext &context) const; + void generateClass(QTextStream &s, GeneratorContext &classContext); + bool finishGeneration(); + + void writeFunctionArguments(QTextStream&, const AbstractMetaFunction*, Options) const {} + void writeArgumentNames(QTextStream&, const AbstractMetaFunction*, Options) const {} + +private: + void writeEnums(QTextStream& s, const AbstractMetaClass* cppClass); + + void writeFields(QTextStream &s, const AbstractMetaClass *cppClass); + void writeArguments(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction *func); + void writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func); + void writeFunction(QTextStream& s, bool writeDoc, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func); + void writeFunctionParametersType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction* func); + void writeFunctionList(QTextStream& s, const AbstractMetaClass* cppClass); + void writeFunctionBlock(QTextStream& s, const QString& title, QStringList& functions); + void writeParamerteType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaArgument *arg); + + void writeConstructors(QTextStream &s, const AbstractMetaClass *cppClass); + void writeFormatedText(QTextStream& s, const Documentation& doc, const AbstractMetaClass* metaclass = 0); + bool writeInjectDocumentation(QTextStream& s, TypeSystem::DocModificationMode mode, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func); + void writeDocSnips(QTextStream &s, const CodeSnipList &codeSnips, TypeSystem::CodeSnipPosition position, TypeSystem::Language language); + + + QString parseArgDocStyle(const AbstractMetaClass *cppClass, const AbstractMetaFunction *func); + QString translateToPythonType(const AbstractMetaType *type, const AbstractMetaClass *cppClass); + + QString m_docDataDir; + QString m_libSourceDir; + QStringList m_codeSnippetDirs; + QString m_extraSectionDir; + QStringList m_functionList; + QMap m_packages; + DocParser* m_docParser; +}; + +#endif // DOCGENERATOR_H diff --git a/sources/shiboken2/generator/shiboken2/CMakeLists.txt b/sources/shiboken2/generator/shiboken2/CMakeLists.txt new file mode 100644 index 000000000..5c1b612dd --- /dev/null +++ b/sources/shiboken2/generator/shiboken2/CMakeLists.txt @@ -0,0 +1,28 @@ +project(shibokengenerator) + +set(shiboken_SRC +../generator.cpp +cppgenerator.cpp +headergenerator.cpp +overloaddata.cpp +shibokengenerator.cpp +main.cpp +) + +include_directories(${generators_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${APIEXTRACTOR_INCLUDE_DIR} + ${Qt5Core_INCLUDE_DIRS} + ) + +add_executable(shiboken2 ${shiboken_SRC}) +set_target_properties(shiboken2 PROPERTIES OUTPUT_NAME shiboken2${shiboken_SUFFIX}) +target_link_libraries(shiboken2 + ${APIEXTRACTOR_LIBRARY} + ${Qt5Core_LIBRARIES} + ) + +configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY) + +install(TARGETS shiboken2 DESTINATION bin) diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp new file mode 100644 index 000000000..6aa2c83df --- /dev/null +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -0,0 +1,5755 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 + +#include "cppgenerator.h" +#include "overloaddata.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +QHash CppGenerator::m_nbFuncs = QHash(); +QHash CppGenerator::m_sqFuncs = QHash(); +QHash CppGenerator::m_mpFuncs = QHash(); +QString CppGenerator::m_currentErrorCode(QLatin1String("0")); + +// utility functions +inline AbstractMetaType* getTypeWithoutContainer(AbstractMetaType* arg) +{ + if (arg && arg->typeEntry()->isContainer()) { + AbstractMetaTypeList lst = arg->instantiations(); + // only support containers with 1 type + if (lst.size() == 1) + return lst[0]; + } + return arg; +} + +CppGenerator::CppGenerator() +{ + // Number protocol structure members names + m_nbFuncs.insert(QLatin1String("__add__"), QLatin1String("nb_add")); + m_nbFuncs.insert(QLatin1String("__sub__"), QLatin1String("nb_subtract")); + m_nbFuncs.insert(QLatin1String("__mul__"), QLatin1String("nb_multiply")); + m_nbFuncs.insert(QLatin1String("__div__"), QLatin1String("nb_divide")); + m_nbFuncs.insert(QLatin1String("__mod__"), QLatin1String("nb_remainder")); + m_nbFuncs.insert(QLatin1String("__neg__"), QLatin1String("nb_negative")); + m_nbFuncs.insert(QLatin1String("__pos__"), QLatin1String("nb_positive")); + m_nbFuncs.insert(QLatin1String("__invert__"), QLatin1String("nb_invert")); + m_nbFuncs.insert(QLatin1String("__lshift__"), QLatin1String("nb_lshift")); + m_nbFuncs.insert(QLatin1String("__rshift__"), QLatin1String("nb_rshift")); + m_nbFuncs.insert(QLatin1String("__and__"), QLatin1String("nb_and")); + m_nbFuncs.insert(QLatin1String("__xor__"), QLatin1String("nb_xor")); + m_nbFuncs.insert(QLatin1String("__or__"), QLatin1String("nb_or")); + m_nbFuncs.insert(QLatin1String("__iadd__"), QLatin1String("nb_inplace_add")); + m_nbFuncs.insert(QLatin1String("__isub__"), QLatin1String("nb_inplace_subtract")); + m_nbFuncs.insert(QLatin1String("__imul__"), QLatin1String("nb_inplace_multiply")); + m_nbFuncs.insert(QLatin1String("__idiv__"), QLatin1String("nb_inplace_divide")); + m_nbFuncs.insert(QLatin1String("__imod__"), QLatin1String("nb_inplace_remainder")); + m_nbFuncs.insert(QLatin1String("__ilshift__"), QLatin1String("nb_inplace_lshift")); + m_nbFuncs.insert(QLatin1String("__irshift__"), QLatin1String("nb_inplace_rshift")); + m_nbFuncs.insert(QLatin1String("__iand__"), QLatin1String("nb_inplace_and")); + m_nbFuncs.insert(QLatin1String("__ixor__"), QLatin1String("nb_inplace_xor")); + m_nbFuncs.insert(QLatin1String("__ior__"), QLatin1String("nb_inplace_or")); + m_nbFuncs.insert(QLatin1String("bool"), QLatin1String("nb_nonzero")); + + // sequence protocol functions + typedef QPair StrPair; + m_sequenceProtocol.insert(QLatin1String("__len__"), + StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR), QLatin1String("Py_ssize_t"))); + m_sequenceProtocol.insert(QLatin1String("__getitem__"), + StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", 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"))); + m_sequenceProtocol.insert(QLatin1String("__getslice__"), + StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", 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"))); + m_sequenceProtocol.insert(QLatin1String("__contains__"), + StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _value"), + QLatin1String("int"))); + m_sequenceProtocol.insert(QLatin1String("__concat__"), + StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _other"), + QLatin1String("PyObject*"))); + + // Sequence protocol structure members names + m_sqFuncs.insert(QLatin1String("__concat__"), QLatin1String("sq_concat")); + m_sqFuncs.insert(QLatin1String("__contains__"), QLatin1String("sq_contains")); + m_sqFuncs.insert(QLatin1String("__getitem__"), QLatin1String("sq_item")); + m_sqFuncs.insert(QLatin1String("__getslice__"), QLatin1String("sq_slice")); + m_sqFuncs.insert(QLatin1String("__len__"), QLatin1String("sq_length")); + m_sqFuncs.insert(QLatin1String("__setitem__"), QLatin1String("sq_ass_item")); + m_sqFuncs.insert(QLatin1String("__setslice__"), QLatin1String("sq_ass_slice")); + + // mapping protocol function + m_mappingProtocol.insert(QLatin1String("__mlen__"), + StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR), + QLatin1String("Py_ssize_t"))); + m_mappingProtocol.insert(QLatin1String("__mgetitem__"), + StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key"), + QLatin1String("PyObject*"))); + m_mappingProtocol.insert(QLatin1String("__msetitem__"), + StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key, PyObject* _value"), + QLatin1String("int"))); + + // Sequence protocol structure members names + m_mpFuncs.insert(QLatin1String("__mlen__"), QLatin1String("mp_length")); + m_mpFuncs.insert(QLatin1String("__mgetitem__"), QLatin1String("mp_subscript")); + m_mpFuncs.insert(QLatin1String("__msetitem__"), QLatin1String("mp_ass_subscript")); +} + +QString CppGenerator::fileNamePrefix() const +{ + return QLatin1String("_wrapper.cpp"); +} + +QString CppGenerator::fileNameForContext(GeneratorContext &context) const +{ + const AbstractMetaClass *metaClass = context.metaClass(); + if (!context.forSmartPointer()) { + QString fileNameBase = metaClass->qualifiedCppName().toLower(); + fileNameBase.replace(QLatin1String("::"), QLatin1String("_")); + return fileNameBase + fileNamePrefix(); + } else { + const AbstractMetaType *smartPointerType = context.preciseType(); + QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass); + return fileNameBase + fileNamePrefix(); + } +} + +QVector CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass, + uint queryIn) +{ + // ( func_name, num_args ) => func_list + typedef QMap, AbstractMetaFunctionList> ResultMap; + ResultMap results; + const AbstractMetaClass::OperatorQueryOptions query(queryIn); + const AbstractMetaFunctionList &funcs = metaClass->operatorOverloads(query); + for (AbstractMetaFunction *func : funcs) { + if (func->isModifiedRemoved() + || func->usesRValueReferences() + || func->name() == QLatin1String("operator[]") + || func->name() == QLatin1String("operator->") + || func->name() == QLatin1String("operator!")) { + continue; + } + int args; + if (func->isComparisonOperator()) { + args = -1; + } else { + args = func->arguments().size(); + } + QPair op(func->name(), args); + results[op].append(func); + } + QVector result; + result.reserve(results.size()); + for (ResultMap::const_iterator it = results.cbegin(), end = results.cend(); it != end; ++it) + result.append(it.value()); + return result; +} + +bool CppGenerator::hasBoolCast(const AbstractMetaClass* metaClass) const +{ + if (!useIsNullAsNbNonZero()) + return false; + // 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; + const PrimitiveTypeEntry* pte = static_cast(func->type()->typeEntry()); + while (pte->referencedTypeEntry()) + pte = pte->referencedTypeEntry(); + return func && func->isConstant() && pte->name() == QLatin1String("bool") && func->arguments().isEmpty(); +} + +typedef QMap FunctionGroupMap; +typedef FunctionGroupMap::const_iterator FunctionGroupMapIt; + +// Prevent ELF symbol qt_version_tag from being generated into the source +static const char includeQDebug[] = +"#ifndef QT_NO_VERSION_TAGGING\n" +"# define QT_NO_VERSION_TAGGING\n" +"#endif\n" +"#include \n"; + +static QString chopType(QString s) +{ + if (s.endsWith(QLatin1String("_Type"))) + s.chop(5); + return s; +} + +/*! + Function used to write the class generated binding code on the buffer + \param s the output buffer + \param metaClass the pointer to metaclass information +*/ +void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) +{ + AbstractMetaClass *metaClass = classContext.metaClass(); + if (ReportHandler::isDebug(ReportHandler::SparseDebug)) + qCDebug(lcShiboken) << "Generating wrapper implementation for " << metaClass->fullName(); + + // write license comment + s << licenseComment() << endl; + + if (!avoidProtectedHack() && !metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) { + s << "//workaround to access protected functions" << endl; + s << "#define protected public" << endl << endl; + } + + // headers + s << "// default includes" << endl; + s << "#include " << endl; + if (usePySideExtensions()) { + s << includeQDebug; + s << "#include " << endl; + s << "#include " << endl; + s << "#include " << endl; + s << "#include " << endl; + } + + s << "#include " << endl; + s << "#include " << endl; + if (usePySideExtensions() && metaClass->isQObject()) { + s << "#include " << endl; + s << "#include " << endl; + } + + // The multiple inheritance initialization function + // needs the 'set' class from C++ STL. + if (hasMultipleInheritanceInAncestry(metaClass)) + s << "#include " << endl; + + s << endl << "// module include" << endl << "#include \"" << getModuleHeaderFileName() << '"' << endl; + + QString headerfile = fileNameForContext(classContext); + headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h")); + s << endl << "// main header" << endl << "#include \"" << headerfile << '"' << endl; + + // PYSIDE-500: Use also includes for inherited wrapper classes, because + // without the protected hack, we sometimes need to cast inherited wrappers. + s << endl << "// inherited wrapper classes" << endl; + AbstractMetaClass *basis = metaClass->baseClass(); + for (; basis; basis = basis->baseClass()) { + GeneratorContext basisContext(basis); + QString headerfile = fileNameForContext(basisContext); + headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h")); + s << "#include \"" << headerfile << '"' << endl; + } + + s << endl << "// inner classes" << endl; + const AbstractMetaClassList &innerClasses = metaClass->innerClasses(); + for (AbstractMetaClass *innerClass : innerClasses) { + GeneratorContext innerClassContext(innerClass); + if (shouldGenerate(innerClass)) { + QString headerfile = fileNameForContext(innerClassContext); + headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h")); + s << "#include \"" << headerfile << '"' << endl; + } + } + + AbstractMetaEnumList classEnums = metaClass->enums(); + for (AbstractMetaClass *innerClass : innerClasses) + lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass); + + //Extra includes + s << endl << "// Extra includes" << endl; + QVector includes = metaClass->typeEntry()->extraIncludes(); + for (AbstractMetaEnum *cppEnum : qAsConst(classEnums)) + includes.append(cppEnum->typeEntry()->extraIncludes()); + qSort(includes.begin(), includes.end()); + for (const Include &inc : qAsConst(includes)) + s << inc.toString() << endl; + s << endl; + + if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated) + s << "#Deprecated" << endl; + + // Use class base namespace + { + const AbstractMetaClass *context = metaClass->enclosingClass(); + while (context) { + if (context->isNamespace() && !context->enclosingClass()) { + s << "using namespace " << context->qualifiedCppName() << ";" << endl; + break; + } + context = context->enclosingClass(); + } + } + + s << endl; + + // Create string literal for smart pointer getter method. + if (classContext.forSmartPointer()) { + const SmartPointerTypeEntry *typeEntry = + static_cast(classContext.preciseType() + ->typeEntry()); + QString rawGetter = typeEntry->getter(); + s << "static const char * " SMART_POINTER_GETTER " = \"" << rawGetter << "\";"; + } + + // class inject-code native/beginning + if (!metaClass->typeEntry()->codeSnips().isEmpty()) { + writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, metaClass); + s << endl; + } + + // python conversion rules + if (metaClass->typeEntry()->hasTargetConversionRule()) { + s << "// Python Conversion" << endl; + s << metaClass->typeEntry()->conversionRule() << endl; + } + + if (shouldGenerateCppWrapper(metaClass)) { + s << "// Native ---------------------------------------------------------" << endl; + s << endl; + + if (avoidProtectedHack() && usePySideExtensions()) { + s << "void " << wrapperName(metaClass) << "::pysideInitQtMetaTypes()\n{\n"; + Indentation indent(INDENT); + writeInitQtMetaTypeFunctionBody(s, classContext); + s << "}\n\n"; + } + + const AbstractMetaFunctionList &funcs = filterFunctions(metaClass); + for (const AbstractMetaFunction *func : funcs) { + if ((func->isPrivate() && !visibilityModifiedToPrivate(func)) + || (func->isModifiedRemoved() && !func->isAbstract())) + continue; + if (func->functionType() == AbstractMetaFunction::ConstructorFunction && !func->isUserAdded()) + writeConstructorNative(s, func); + else if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) + && (func->isVirtual() || func->isAbstract())) + writeVirtualMethodNative(s, func); + } + + if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) { + if (usePySideExtensions() && metaClass->isQObject()) + writeMetaObjectMethod(s, metaClass); + writeDestructorNative(s, metaClass); + } + } + + Indentation indentation(INDENT); + + QString methodsDefinitions; + QTextStream md(&methodsDefinitions); + QString singleMethodDefinitions; + QTextStream smd(&singleMethodDefinitions); + + s << endl << "// Target ---------------------------------------------------------" << endl << endl; + s << "extern \"C\" {" << endl; + const FunctionGroupMap &functionGroups = getFunctionGroups(metaClass); + for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) { + AbstractMetaFunctionList overloads; + QSet seenSignatures; + for (AbstractMetaFunction *func : it.value()) { + if (!func->isAssignmentOperator() + && !func->usesRValueReferences() + && !func->isCastOperator() + && !func->isModifiedRemoved() + && (!func->isPrivate() || func->functionType() == AbstractMetaFunction::EmptyFunction) + && func->ownerClass() == func->implementingClass() + && (func->name() != QLatin1String("qt_metacall"))) { + // PYSIDE-331: Inheritance works correctly when there are disjoint functions. + // But when a function is both in a class and inherited in a subclass, + // then we need to search through all subclasses and collect the new signatures. + overloads << getFunctionAndInheritedOverloads(func, &seenSignatures); + } + } + + if (overloads.isEmpty()) + continue; + + const AbstractMetaFunction* rfunc = overloads.first(); + if (m_sequenceProtocol.contains(rfunc->name()) || m_mappingProtocol.contains(rfunc->name())) + continue; + + if (rfunc->isConstructor()) { + // @TODO: Implement constructor support for smart pointers, so that they can be + // instantiated in python code. + if (classContext.forSmartPointer()) + continue; + writeConstructorWrapper(s, overloads, classContext); + } + // call operators + else if (rfunc->name() == QLatin1String("operator()")) + writeMethodWrapper(s, overloads, classContext); + else if (!rfunc->isOperatorOverload()) { + + if (classContext.forSmartPointer()) { + const SmartPointerTypeEntry *smartPointerTypeEntry = + static_cast( + classContext.preciseType()->typeEntry()); + + if (smartPointerTypeEntry->getter() == rfunc->name()) { + // Replace the return type of the raw pointer getter method with the actual + // return type. + QString innerTypeName = + classContext.preciseType()->getSmartPointerInnerType()->name(); + QString pointerToInnerTypeName = innerTypeName + QLatin1Char('*'); + // @TODO: This possibly leaks, but there are a bunch of other places where this + // is done, so this will be fixed in bulk with all the other cases, because the + // ownership of the pointers is not clear at the moment. + AbstractMetaType *pointerToInnerType = + buildAbstractMetaTypeFromString(pointerToInnerTypeName); + + AbstractMetaFunction *mutableRfunc = overloads.first(); + mutableRfunc->replaceType(pointerToInnerType); + } else if (smartPointerTypeEntry->refCountMethodName().isEmpty() + || smartPointerTypeEntry->refCountMethodName() != rfunc->name()) { + // Skip all public methods of the smart pointer except for the raw getter and + // the ref count method. + continue; + } + } + + writeMethodWrapper(s, overloads, classContext); + if (OverloadData::hasStaticAndInstanceFunctions(overloads)) { + QString methDefName = cpythonMethodDefinitionName(rfunc); + smd << "static PyMethodDef " << methDefName << " = {" << endl; + smd << INDENT; + writeMethodDefinitionEntry(smd, overloads); + smd << endl << "};" << endl << endl; + } + writeMethodDefinition(md, overloads); + } + } + + const QString className = chopType(cpythonTypeName(metaClass)); + + if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) + writeCopyFunction(s, classContext); + + // Write single method definitions + s << singleMethodDefinitions; + + // Write methods definition + s << "static PyMethodDef " << className << "_methods[] = {" << endl; + s << methodsDefinitions << endl; + if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) + s << INDENT << "{\"__copy__\", (PyCFunction)" << className << "___copy__" << ", METH_NOARGS}," << endl; + s << INDENT << "{0} // Sentinel" << endl; + s << "};" << endl << endl; + + // Write tp_getattro function + if ((usePySideExtensions() && metaClass->qualifiedCppName() == QLatin1String("QObject"))) { + writeGetattroFunction(s, classContext); + s << endl; + writeSetattroFunction(s, classContext); + s << endl; + } else { + if (classNeedsGetattroFunction(metaClass)) { + writeGetattroFunction(s, classContext); + s << endl; + } + if (classNeedsSetattroFunction(metaClass)) { + writeSetattroFunction(s, classContext); + s << endl; + } + } + + if (hasBoolCast(metaClass)) { + ErrorCode errorCode(-1); + s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject* " PYTHON_SELF_VAR ")" << endl; + s << '{' << endl; + writeCppSelfDefinition(s, 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; + s << '}' << endl << endl; + } + + if (supportsNumberProtocol(metaClass) && !metaClass->typeEntry()->isSmartPointer()) { + const QVector opOverloads = filterGroupedOperatorFunctions( + metaClass, + AbstractMetaClass::ArithmeticOp + | AbstractMetaClass::LogicalOp + | AbstractMetaClass::BitwiseOp); + + for (const AbstractMetaFunctionList &allOverloads : opOverloads) { + AbstractMetaFunctionList overloads; + for (AbstractMetaFunction *func : allOverloads) { + if (!func->isModifiedRemoved() + && !func->isPrivate() + && (func->ownerClass() == func->implementingClass() || func->isAbstract())) + overloads.append(func); + } + + if (overloads.isEmpty()) + continue; + + writeMethodWrapper(s, overloads, classContext); + } + } + + if (supportsSequenceProtocol(metaClass)) { + writeSequenceMethods(s, metaClass, classContext); + } + + if (supportsMappingProtocol(metaClass)) { + writeMappingMethods(s, metaClass, classContext); + } + + if (metaClass->hasComparisonOperatorOverload()) { + s << "// Rich comparison" << endl; + writeRichCompareFunction(s, classContext); + } + + if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer()) { + const AbstractMetaFieldList &fields = metaClass->fields(); + for (const AbstractMetaField *metaField : fields) { + if (metaField->isStatic()) + continue; + writeGetterFunction(s, metaField, classContext); + if (!metaField->type()->isConstant()) + writeSetterFunction(s, metaField, classContext); + s << endl; + } + + s << "// Getters and Setters for " << metaClass->name() << endl; + s << "static PyGetSetDef " << cpythonGettersSettersDefinitionName(metaClass) << "[] = {" << endl; + for (const AbstractMetaField *metaField : fields) { + if (metaField->isStatic()) + continue; + + bool hasSetter = !metaField->type()->isConstant(); + s << INDENT << "{const_cast(\"" << metaField->name() << "\"), "; + s << cpythonGetterFunctionName(metaField); + s << ", " << (hasSetter ? cpythonSetterFunctionName(metaField) : QLatin1String("0")); + s << "}," << endl; + } + s << INDENT << "{0} // Sentinel" << endl; + s << "};" << endl << endl; + } + + s << "} // extern \"C\"" << endl << endl; + + if (!metaClass->typeEntry()->hashFunction().isEmpty()) + writeHashFunction(s, classContext); + + // Write tp_traverse and tp_clear functions. + writeTpTraverseFunction(s, metaClass); + writeTpClearFunction(s, metaClass); + + writeClassDefinition(s, metaClass, classContext); + s << endl; + + if (metaClass->isPolymorphic() && metaClass->baseClass()) + writeTypeDiscoveryFunction(s, metaClass); + + + for (AbstractMetaEnum *cppEnum : qAsConst(classEnums)) { + if (cppEnum->isAnonymous() || cppEnum->isPrivate()) + continue; + + bool hasFlags = cppEnum->typeEntry()->flags(); + if (hasFlags) { + writeFlagsMethods(s, cppEnum); + writeFlagsNumberMethodsDefinition(s, cppEnum); + s << endl; + } + } + s << endl; + + writeConverterFunctions(s, metaClass, classContext); + writeClassRegister(s, metaClass, classContext); + + // class inject-code native/end + if (!metaClass->typeEntry()->codeSnips().isEmpty()) { + writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, metaClass); + s << endl; + } +} + +void CppGenerator::writeConstructorNative(QTextStream& s, const AbstractMetaFunction* func) +{ + Indentation indentation(INDENT); + s << functionSignature(func, wrapperName(func->ownerClass()) + QLatin1String("::"), QString(), + OriginalTypeDescription | SkipDefaultValues); + s << " : "; + writeFunctionCall(s, func); + s << " {" << endl; + const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); + writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, func, lastArg); + s << INDENT << "// ... middle" << endl; + writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg); + s << '}' << endl << endl; +} + +void CppGenerator::writeDestructorNative(QTextStream &s, const AbstractMetaClass *metaClass) +{ + Indentation indentation(INDENT); + s << wrapperName(metaClass) << "::~" << wrapperName(metaClass) << "()" << endl << '{' << endl; + // kill pyobject + s << INDENT << "SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(this);" << endl; + s << INDENT << "Shiboken::Object::destroy(wrapper, this);" << endl; + s << '}' << endl; +} + +static bool allArgumentsRemoved(const AbstractMetaFunction* func) +{ + if (func->arguments().isEmpty()) + return false; + const AbstractMetaArgumentList &arguments = func->arguments(); + for (const AbstractMetaArgument *arg : arguments) { + if (!func->argumentRemoved(arg->argumentIndex() + 1)) + return false; + } + return true; +} + +QString CppGenerator::getVirtualFunctionReturnTypeName(const AbstractMetaFunction* func) +{ + if (!func->type()) + return QLatin1String("\"\""); + + if (!func->typeReplaced(0).isEmpty()) + return QLatin1Char('"') + func->typeReplaced(0) + QLatin1Char('"'); + + // SbkType would return null when the type is a container. + if (func->type()->typeEntry()->isContainer()) { + return QLatin1Char('"') + + reinterpret_cast(func->type()->typeEntry())->typeName() + + QLatin1Char('"'); + } + + if (avoidProtectedHack()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type()); + if (metaEnum && metaEnum->isProtected()) + return QLatin1Char('"') + protectedEnumSurrogateName(metaEnum) + QLatin1Char('"'); + } + + if (func->type()->isPrimitive()) + return QLatin1Char('"') + func->type()->name() + QLatin1Char('"'); + + return QString::fromLatin1("Shiboken::SbkType< %1 >()->tp_name").arg(func->type()->typeEntry()->qualifiedCppName()); +} + +void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFunction* func) +{ + //skip metaObject function, this will be written manually ahead + if (usePySideExtensions() && func->ownerClass() && func->ownerClass()->isQObject() && + ((func->name() == QLatin1String("metaObject")) || (func->name() == QLatin1String("qt_metacall")))) + return; + + const TypeEntry* retType = func->type() ? func->type()->typeEntry() : 0; + const QString funcName = func->isOperatorOverload() ? pythonOperatorFunctionName(func) : func->name(); + + QString prefix = wrapperName(func->ownerClass()) + QLatin1String("::"); + s << functionSignature(func, prefix, QString(), Generator::SkipDefaultValues|Generator::OriginalTypeDescription) + << endl << '{' << endl; + + Indentation indentation(INDENT); + + QString defaultReturnExpr; + if (retType) { + const FunctionModificationList &mods = func->modifications(); + for (const FunctionModification &mod : mods) { + for (const ArgumentModification &argMod : mod.argument_mods) { + if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) { + static const QRegularExpression regex(QStringLiteral("%(\\d+)")); + Q_ASSERT(regex.isValid()); + defaultReturnExpr = argMod.replacedDefaultExpression; + for (int offset = 0; ; ) { + const QRegularExpressionMatch match = regex.match(defaultReturnExpr, offset); + if (!match.hasMatch()) + break; + const int argId = match.capturedRef(1).toInt() - 1; + if (argId < 0 || argId > func->arguments().count()) { + qCWarning(lcShiboken) << "The expression used in return value contains an invalid index."; + break; + } + defaultReturnExpr.replace(match.captured(0), func->arguments()[argId]->name()); + offset = match.capturedStart(1); + } + } + } + } + if (defaultReturnExpr.isEmpty()) + defaultReturnExpr = minimalConstructor(func->type()); + if (defaultReturnExpr.isEmpty()) { + 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()); + qCWarning(lcShiboken).noquote().nospace() << errorMsg; + s << endl << INDENT << "#error " << errorMsg << endl; + } + } + + if (func->isAbstract() && func->isModifiedRemoved()) { + qCWarning(lcShiboken).noquote().nospace() + << 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 << '}' << endl << endl; + return; + } + + //Write declaration/native injected code + if (func->hasInjectedCode()) { + CodeSnipList snips = func->injectedCodeSnips(); + const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode, func, lastArg); + s << endl; + } + + s << INDENT << "Shiboken::GilState gil;" << endl; + + // Get out of virtual method call if someone already threw an error. + s << INDENT << "if (PyErr_Occurred())" << endl; + { + Indentation indentation(INDENT); + s << INDENT << "return " << defaultReturnExpr << ';' << endl; + } + + s << INDENT << "Shiboken::AutoDecRef " PYTHON_OVERRIDE_VAR "(Shiboken::BindingManager::instance().getOverride(this, \""; + s << funcName << "\"));" << endl; + + s << INDENT << "if (" PYTHON_OVERRIDE_VAR ".isNull()) {" << endl; + { + Indentation indentation(INDENT); + CodeSnipList snips; + if (func->hasInjectedCode()) { + snips = func->injectedCodeSnips(); + const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::ShellCode, func, lastArg); + s << endl; + } + + if (func->isAbstract()) { + s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '"; + s << func->ownerClass()->name() << '.' << funcName; + s << "()' not implemented.\");" << endl; + s << INDENT << "return " << (retType ? defaultReturnExpr : QString()); + } else { + s << INDENT << "gil.release();" << endl; + s << INDENT; + if (retType) + s << "return "; + s << "this->::" << func->implementingClass()->qualifiedCppName() << "::"; + writeFunctionCall(s, func, Generator::VirtualCall); + if (!retType) + s << ";\n" << INDENT << "return"; + } + } + s << ';' << endl; + s << INDENT << '}' << endl << endl; + + writeConversionRule(s, func, TypeSystem::TargetLangCode); + + s << INDENT << "Shiboken::AutoDecRef " PYTHON_ARGS "("; + + if (func->arguments().isEmpty() || allArgumentsRemoved(func)) { + s << "PyTuple_New(0));" << endl; + } else { + QStringList argConversions; + const AbstractMetaArgumentList &arguments = func->arguments(); + for (const AbstractMetaArgument *arg : arguments) { + if (func->argumentRemoved(arg->argumentIndex() + 1)) + continue; + + QString argConv; + QTextStream ac(&argConv); + const PrimitiveTypeEntry* argType = (const PrimitiveTypeEntry*) arg->type()->typeEntry(); + bool convert = argType->isObject() + || arg->type()->isQObject() + || argType->isValue() + || arg->type()->isValuePointer() + || arg->type()->isNativePointer() + || argType->isFlags() + || argType->isEnum() + || argType->isContainer() + || arg->type()->referenceType() == LValueReference; + + if (!convert && argType->isPrimitive()) { + if (argType->basicReferencedTypeEntry()) + argType = argType->basicReferencedTypeEntry(); + convert = !m_formatUnits.contains(argType->name()); + } + + Indentation indentation(INDENT); + ac << INDENT; + if (!func->conversionRule(TypeSystem::TargetLangCode, arg->argumentIndex() + 1).isEmpty()) { + // Has conversion rule. + ac << arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX); + } else { + QString argName = arg->name(); + if (convert) + writeToPythonConversion(ac, arg->type(), func->ownerClass(), argName); + else + ac << argName; + } + + argConversions << argConv; + } + + s << "Py_BuildValue(\"(" << getFormatUnitString(func, false) << ")\"," << endl; + s << argConversions.join(QLatin1String(",\n")) << endl; + s << INDENT << "));" << endl; + } + + bool invalidateReturn = false; + QSet invalidateArgs; + const FunctionModificationList &mods = func->modifications(); + for (const FunctionModification &funcMod : mods) { + for (const ArgumentModification &argMod : funcMod.argument_mods) { + 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; + } else if (argMod.index == 0 && argMod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::CppOwnership) { + invalidateReturn = true; + } + } + } + s << endl; + + CodeSnipList snips; + if (func->hasInjectedCode()) { + snips = func->injectedCodeSnips(); + + if (injectedCodeUsesPySelf(func)) + s << INDENT << "PyObject* pySelf = BindingManager::instance().retrieveWrapper(this);" << endl; + + const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, func, lastArg); + s << endl; + } + + if (!injectedCodeCallsPythonOverride(func)) { + s << INDENT; + 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; + { + Indentation indent(INDENT); + s << INDENT << "PyErr_Print();" << endl; + s << INDENT << "return " << defaultReturnExpr << ';' << endl; + } + s << INDENT << '}' << endl; + + if (retType) { + if (invalidateReturn) + 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; + { + 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 << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl; + s << INDENT << "return " << defaultReturnExpr << ';' << endl; + } + s << INDENT << '}' << endl; + + } else { + + s << INDENT << "// Check return type" << endl; + s << INDENT << "bool typeIsValid = "; + writeTypeCheck(s, func->type(), QLatin1String(PYTHON_RETURN_VAR), + isNumber(func->type()->typeEntry()), func->typeReplaced(0)); + s << ';' << endl; + s << INDENT << "if (!typeIsValid"; + s << (isPointerToWrapperType(func->type()) ? " && " 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 << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl; + s << INDENT << "return " << defaultReturnExpr << ';' << endl; + } + s << INDENT << '}' << endl; + + } + } + + if (!func->conversionRule(TypeSystem::NativeCode, 0).isEmpty()) { + // Has conversion rule. + writeConversionRule(s, func, TypeSystem::NativeCode, QLatin1String(CPP_RETURN_VAR)); + } else if (!injectedCodeHasReturnValueAttribution(func, TypeSystem::NativeCode)) { + writePythonToCppTypeConversion(s, func->type(), QLatin1String(PYTHON_RETURN_VAR), + QLatin1String(CPP_RETURN_VAR), func->implementingClass()); + } + } + } + + if (invalidateReturn) { + s << INDENT << "if (invalidateArg0)" << endl; + Indentation indentation(INDENT); + 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 << (argIndex - 1) << "));" << endl; + } + + + const FunctionModificationList &funcMods = func->modifications(); + for (const FunctionModification &funcMod : funcMods) { + 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; + Indentation indent(INDENT); + s << INDENT << "Shiboken::Object::releaseOwnership(" PYTHON_RETURN_VAR ");" << endl; + } + } + } + + if (func->hasInjectedCode()) { + s << endl; + const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg); + } + + if (retType) { + s << INDENT << "return "; + if (avoidProtectedHack() && retType->isEnum()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(retType); + bool isProtectedEnum = metaEnum && metaEnum->isProtected(); + if (isProtectedEnum) { + QString typeCast; + if (metaEnum->enclosingClass()) + typeCast += QLatin1String("::") + metaEnum->enclosingClass()->qualifiedCppName(); + typeCast += QLatin1String("::") + metaEnum->name(); + s << '(' << typeCast << ')'; + } + } + if (func->type()->referenceType() == LValueReference && !isPointer(func->type())) + s << '*'; + s << CPP_RETURN_VAR ";" << endl; + } + + s << '}' << endl << endl; +} + +void CppGenerator::writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass* metaClass) +{ + Indentation indentation(INDENT); + QString wrapperClassName = wrapperName(metaClass); + s << "const QMetaObject* " << wrapperClassName << "::metaObject() const" << endl; + s << '{' << endl; + s << INDENT << "if (QObject::d_ptr->metaObject)" << endl + << INDENT << INDENT << "return QObject::d_ptr->dynamicMetaObject();" << endl; + 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(pySelf));" << endl; + s << '}' << endl << endl; + + // qt_metacall function + s << "int " << wrapperClassName << "::qt_metacall(QMetaObject::Call call, int id, void** args)" << endl; + s << "{" << endl; + + AbstractMetaFunction *func = NULL; + AbstractMetaFunctionList list = metaClass->queryFunctionsByName(QLatin1String("qt_metacall")); + if (list.size() == 1) + func = list[0]; + + CodeSnipList snips; + if (func) { + snips = func->injectedCodeSnips(); + if (func->isUserAdded()) { + CodeSnipList snips = func->injectedCodeSnips(); + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode, func); + } + } + + s << INDENT << "int result = " << metaClass->qualifiedCppName() << "::qt_metacall(call, id, args);" << endl; + s << INDENT << "return result < 0 ? result : PySide::SignalManager::qt_metacall(this, call, id, args);" << endl; + s << "}" << endl << endl; + + // qt_metacast function + writeMetaCast(s, metaClass); +} + +void CppGenerator::writeMetaCast(QTextStream& s, const AbstractMetaClass* metaClass) +{ + Indentation indentation(INDENT); + QString wrapperClassName = wrapperName(metaClass); + s << "void* " << wrapperClassName << "::qt_metacast(const char* _clname)" << endl; + s << '{' << endl; + s << INDENT << "if (!_clname) return 0;" << endl; + s << INDENT << "SbkObject* pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);" << endl; + s << INDENT << "if (pySelf && PySide::inherits(Py_TYPE(pySelf), _clname))" << endl; + s << INDENT << INDENT << "return static_cast(const_cast< " << wrapperClassName << "* >(this));" << endl; + s << INDENT << "return " << metaClass->qualifiedCppName() << "::qt_metacast(_clname);" << endl; + s << "}" << endl << endl; +} + +void CppGenerator::writeEnumConverterFunctions(QTextStream& s, const AbstractMetaEnum* metaEnum) +{ + if (metaEnum->isPrivate() || metaEnum->isAnonymous()) + return; + writeEnumConverterFunctions(s, metaEnum->typeEntry()); +} + +void CppGenerator::writeEnumConverterFunctions(QTextStream& s, const TypeEntry* enumType) +{ + if (!enumType) + return; + QString enumFlagName = enumType->isFlags() ? QLatin1String("flag") : QLatin1String("enum"); + QString typeName = fixedCppTypeName(enumType); + QString enumPythonType = cpythonTypeNameExt(enumType); + QString cppTypeName = getFullTypeName(enumType).trimmed(); + if (avoidProtectedHack()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(enumType); + if (metaEnum && metaEnum->isProtected()) + cppTypeName = protectedEnumSurrogateName(metaEnum); + } + QString code; + QTextStream c(&code); + c << INDENT << "*((" << cppTypeName << "*)cppOut) = "; + if (enumType->isFlags()) + c << cppTypeName << "(QFlag((int)PySide::QFlags::getValue(reinterpret_cast(pyIn))))"; + else + c << "(" << cppTypeName << ") Shiboken::Enum::getValue(pyIn)"; + c << ';' << endl; + writePythonToCppFunction(s, code, typeName, typeName); + + QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, %1)").arg(enumPythonType); + writeIsPythonConvertibleToCppFunction(s, typeName, typeName, pyTypeCheck); + + code.clear(); + + c << INDENT << "int castCppIn = *((" << cppTypeName << "*)cppIn);" << endl; + c << INDENT; + c << "return "; + if (enumType->isFlags()) + c << "reinterpret_cast(PySide::QFlags::newObject(castCppIn, " << enumPythonType << "))"; + + else + c << "Shiboken::Enum::newItem(" << enumPythonType << ", castCppIn)"; + c << ';' << endl; + writeCppToPythonFunction(s, code, typeName, typeName); + s << endl; + + if (enumType->isFlags()) + return; + + const FlagsTypeEntry* flags = reinterpret_cast(enumType)->flags(); + if (!flags) + return; + + // QFlags part. + + writeEnumConverterFunctions(s, flags); + + code.clear(); + cppTypeName = getFullTypeName(flags).trimmed(); + c << INDENT << "*((" << cppTypeName << "*)cppOut) = " << cppTypeName; + c << "(QFlag((int)Shiboken::Enum::getValue(pyIn)));" << endl; + + QString flagsTypeName = fixedCppTypeName(flags); + writePythonToCppFunction(s, code, typeName, flagsTypeName); + writeIsPythonConvertibleToCppFunction(s, typeName, flagsTypeName, pyTypeCheck); + + code.clear(); + c << INDENT << "Shiboken::AutoDecRef pyLong(PyNumber_Long(pyIn));" << endl; + c << INDENT << "*((" << cppTypeName << "*)cppOut) = " << cppTypeName; + c << "(QFlag((int)PyLong_AsLong(pyLong.object())));" << endl; + writePythonToCppFunction(s, code, QLatin1String("number"), flagsTypeName); + writeIsPythonConvertibleToCppFunction(s, QLatin1String("number"), flagsTypeName, + QLatin1String("PyNumber_Check(pyIn)")); +} + +void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaClass *metaClass, + GeneratorContext &classContext) +{ + s << "// Type conversion functions." << endl << endl; + + AbstractMetaEnumList classEnums = metaClass->enums(); + const AbstractMetaClassList &innerClasses = metaClass->innerClasses(); + for (AbstractMetaClass *innerClass : innerClasses) + lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass); + if (!classEnums.isEmpty()) + s << "// Python to C++ enum conversion." << endl; + for (const AbstractMetaEnum *metaEnum : qAsConst(classEnums)) + writeEnumConverterFunctions(s, metaEnum); + + if (metaClass->isNamespace()) + return; + + QString typeName; + if (!classContext.forSmartPointer()) + typeName = getFullTypeName(metaClass); + else + typeName = getFullTypeName(classContext.preciseType()); + + QString cpythonType = cpythonTypeName(metaClass); + + // Returns the C++ pointer of the Python wrapper. + s << "// Python to C++ pointer conversion - returns the C++ object of the Python wrapper (keeps object identity)." << endl; + + QString sourceTypeName = metaClass->name(); + QString targetTypeName = metaClass->name() + QLatin1String("_PTR"); + QString code; + QTextStream c(&code); + c << INDENT << "Shiboken::Conversions::pythonToCppPointer(&" << cpythonType << ", pyIn, cppOut);"; + writePythonToCppFunction(s, code, sourceTypeName, targetTypeName); + + // "Is convertible" function for the Python object to C++ pointer conversion. + QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, (PyTypeObject*)&%1)").arg(cpythonType); + writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck, QString(), true); + s << endl; + + // C++ pointer to a Python wrapper, keeping identity. + s << "// C++ to Python pointer conversion - tries to find the Python wrapper for the C++ object (keeps object identity)." << endl; + code.clear(); + if (usePySideExtensions() && metaClass->isQObject()) + { + c << INDENT << "return PySide::getWrapperForQObject((" << typeName << "*)cppIn, &" << cpythonType << ");" << endl; + } else { + c << INDENT << "PyObject* pyOut = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(cppIn);" << endl; + c << INDENT << "if (pyOut) {" << endl; + { + Indentation indent(INDENT); + c << INDENT << "Py_INCREF(pyOut);" << endl; + c << INDENT << "return pyOut;" << endl; + } + c << INDENT << '}' << endl; + c << INDENT << "const char* typeName = typeid(*((" << typeName << "*)cppIn)).name();" << endl; + c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType; + c << ", const_cast(cppIn), false, false, typeName);"; + } + std::swap(targetTypeName, sourceTypeName); + writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); + + // The conversions for an Object Type end here. + if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer()) { + s << endl; + return; + } + + // Always copies C++ value (not pointer, and not reference) to a new Python wrapper. + s << endl << "// C++ to Python copy conversion." << endl; + if (!classContext.forSmartPointer()) + targetTypeName = metaClass->name(); + else + targetTypeName = classContext.preciseType()->name(); + + sourceTypeName = targetTypeName + QLatin1String("_COPY"); + + code.clear(); + + QString computedWrapperName; + if (!classContext.forSmartPointer()) + computedWrapperName = wrapperName(metaClass); + else + computedWrapperName = wrapperName(classContext.preciseType()); + + c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << computedWrapperName; + c << "(*((" << typeName << "*)cppIn)), true, true);"; + writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); + s << endl; + + // Python to C++ copy conversion. + s << "// Python to C++ copy conversion." << endl; + if (!classContext.forSmartPointer()) + sourceTypeName = metaClass->name(); + else + sourceTypeName = classContext.preciseType()->name(); + + targetTypeName = QStringLiteral("%1_COPY").arg(sourceTypeName); + code.clear(); + + QString pyInVariable = QLatin1String("pyIn"); + QString wrappedCPtrExpression; + if (!classContext.forSmartPointer()) + wrappedCPtrExpression = cpythonWrapperCPtr(metaClass->typeEntry(), pyInVariable); + else + wrappedCPtrExpression = cpythonWrapperCPtr(classContext.preciseType(), pyInVariable); + + c << INDENT << "*((" << typeName << "*)cppOut) = *" + << wrappedCPtrExpression << ';'; + writePythonToCppFunction(s, code, sourceTypeName, targetTypeName); + + // "Is convertible" function for the Python object to C++ value copy conversion. + writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck); + s << endl; + + // User provided implicit conversions. + CustomConversion* customConversion = metaClass->typeEntry()->customConversion(); + + // Implicit conversions. + AbstractMetaFunctionList implicitConvs; + if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) { + const AbstractMetaFunctionList &allImplicitConvs = implicitConversions(metaClass->typeEntry()); + for (AbstractMetaFunction *func : allImplicitConvs) { + if (!func->isUserAdded()) + implicitConvs << func; + } + } + + if (!implicitConvs.isEmpty()) + s << "// Implicit conversions." << endl; + + AbstractMetaType* targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass); + for (const AbstractMetaFunction* conv : qAsConst(implicitConvs)) { + if (conv->isModifiedRemoved()) + continue; + + QString typeCheck; + QString toCppConv; + QString toCppPreConv; + if (conv->isConversionOperator()) { + const AbstractMetaClass* sourceClass = conv->ownerClass(); + typeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, %1)").arg(cpythonTypeNameExt(sourceClass->typeEntry())); + toCppConv = QLatin1Char('*') + cpythonWrapperCPtr(sourceClass->typeEntry(), QLatin1String("pyIn")); + } else { + // Constructor that does implicit conversion. + if (!conv->typeReplaced(1).isEmpty()) + continue; + const AbstractMetaType* sourceType = conv->arguments().first()->type(); + typeCheck = cpythonCheckFunction(sourceType); + bool isUserPrimitiveWithoutTargetLangName = isUserPrimitive(sourceType) + && sourceType->typeEntry()->targetLangApiName() == sourceType->typeEntry()->name(); + if (!isWrapperType(sourceType) + && !isUserPrimitiveWithoutTargetLangName + && !sourceType->typeEntry()->isEnum() + && !sourceType->typeEntry()->isFlags() + && !sourceType->typeEntry()->isContainer()) { + typeCheck += QLatin1Char('('); + } + if (isWrapperType(sourceType)) { + typeCheck += QLatin1String("pyIn)"); + toCppConv = (sourceType->referenceType() == LValueReference || !isPointerToWrapperType(sourceType)) + ? QLatin1String("*") : QString(); + toCppConv += cpythonWrapperCPtr(sourceType->typeEntry(), QLatin1String("pyIn")); + } else if (typeCheck.contains(QLatin1String("%in"))) { + typeCheck.replace(QLatin1String("%in"), QLatin1String("pyIn")); + typeCheck.append(QLatin1Char(')')); + } else { + typeCheck += QLatin1String("pyIn)"); + } + + if (isUserPrimitive(sourceType) + || isCppPrimitive(sourceType) + || sourceType->typeEntry()->isContainer() + || sourceType->typeEntry()->isEnum() + || sourceType->typeEntry()->isFlags()) { + QTextStream pc(&toCppPreConv); + pc << INDENT << getFullTypeNameWithoutModifiers(sourceType) << " cppIn"; + writeMinimalConstructorExpression(pc, sourceType); + pc << ';' << endl; + writeToCppConversion(pc, sourceType, 0, QLatin1String("pyIn"), QLatin1String("cppIn")); + pc << ';'; + toCppConv.append(QLatin1String("cppIn")); + } else if (!isWrapperType(sourceType)) { + QTextStream tcc(&toCppConv); + writeToCppConversion(tcc, sourceType, metaClass, QLatin1String("pyIn"), QLatin1String("/*BOZO-1061*/")); + } + + + } + const AbstractMetaType* sourceType = conv->isConversionOperator() + ? buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass()) + : conv->arguments().first()->type(); + writePythonToCppConversionFunctions(s, sourceType, targetType, typeCheck, toCppConv, toCppPreConv); + } + + writeCustomConverterFunctions(s, customConversion); +} + +void CppGenerator::writeCustomConverterFunctions(QTextStream& s, const CustomConversion* customConversion) +{ + if (!customConversion) + return; + const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions(); + if (toCppConversions.isEmpty()) + return; + s << "// Python to C++ conversions for type '" << customConversion->ownerType()->qualifiedCppName() << "'." << endl; + for (CustomConversion::TargetToNativeConversion *toNative : toCppConversions) + writePythonToCppConversionFunctions(s, toNative, customConversion->ownerType()); + s << endl; +} + +void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClass *metaClass, + GeneratorContext &classContext) +{ + if (metaClass->isNamespace()) + return; + s << INDENT << "// Register Converter" << endl; + s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(&"; + s << cpythonTypeName(metaClass) << ',' << endl; + { + Indentation indent(INDENT); + QString sourceTypeName = metaClass->name(); + QString targetTypeName = sourceTypeName + QLatin1String("_PTR"); + s << INDENT << pythonToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl; + s << INDENT << convertibleToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl; + std::swap(targetTypeName, sourceTypeName); + s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName); + if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) { + s << ',' << endl; + sourceTypeName = metaClass->name() + QLatin1String("_COPY"); + s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName); + } + } + s << ");" << endl; + + s << endl; + + QStringList cppSignature; + if (!classContext.forSmartPointer()) { + cppSignature = metaClass->qualifiedCppName().split(QLatin1String("::"), + QString::SkipEmptyParts); + } else { + cppSignature = classContext.preciseType()->cppSignature().split(QLatin1String("::"), + QString::SkipEmptyParts); + } + while (!cppSignature.isEmpty()) { + QString signature = cppSignature.join(QLatin1String("::")); + s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "\");" << endl; + s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "*\");" << endl; + s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "&\");" << endl; + cppSignature.removeFirst(); + } + + s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::"; + QString qualifiedCppNameInvocation; + if (!classContext.forSmartPointer()) + qualifiedCppNameInvocation = metaClass->qualifiedCppName(); + else + qualifiedCppNameInvocation = classContext.preciseType()->cppSignature(); + + s << qualifiedCppNameInvocation << ").name());" << endl; + + if (shouldGenerateCppWrapper(metaClass)) { + s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::"; + s << wrapperName(metaClass) << ").name());" << endl; + } + + s << endl; + + if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer()) + return; + + // Python to C++ copy (value, not pointer neither reference) conversion. + s << INDENT << "// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter." << endl; + QString sourceTypeName = metaClass->name(); + QString targetTypeName = sourceTypeName + QLatin1String("_COPY"); + QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName); + QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName); + writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv); + + // User provided implicit conversions. + CustomConversion* customConversion = metaClass->typeEntry()->customConversion(); + + // Add implicit conversions. + AbstractMetaFunctionList implicitConvs; + if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) { + const AbstractMetaFunctionList &allImplicitConvs = implicitConversions(metaClass->typeEntry()); + for (AbstractMetaFunction *func : allImplicitConvs) { + if (!func->isUserAdded()) + implicitConvs << func; + } + } + + if (!implicitConvs.isEmpty()) + s << INDENT << "// Add implicit conversions to type converter." << endl; + + AbstractMetaType* targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass); + for (const AbstractMetaFunction *conv : qAsConst(implicitConvs)) { + if (conv->isModifiedRemoved()) + continue; + const AbstractMetaType* sourceType; + if (conv->isConversionOperator()) { + sourceType = buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass()); + } else { + // Constructor that does implicit conversion. + if (!conv->typeReplaced(1).isEmpty()) + continue; + sourceType = conv->arguments().first()->type(); + } + QString toCpp = pythonToCppFunctionName(sourceType, targetType); + QString isConv = convertibleToCppFunctionName(sourceType, targetType); + writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv); + } + + writeCustomConverterRegister(s, customConversion, QLatin1String("converter")); +} + +void CppGenerator::writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar) +{ + if (!customConversion) + return; + const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions(); + if (toCppConversions.isEmpty()) + return; + s << INDENT << "// Add user defined implicit conversions to type converter." << endl; + for (CustomConversion::TargetToNativeConversion *toNative : toCppConversions) { + QString toCpp = pythonToCppFunctionName(toNative, customConversion->ownerType()); + QString isConv = convertibleToCppFunctionName(toNative, customConversion->ownerType()); + writeAddPythonToCppConversion(s, converterVar, toCpp, isConv); + } +} + +void CppGenerator::writeContainerConverterRegister(QTextStream& s, const AbstractMetaType* container, const QString& converterVar) +{ + s << INDENT << "// Add user defined container conversion to type converter." << endl; + QString typeName = fixedCppTypeName(container); + QString toCpp = pythonToCppFunctionName(typeName, typeName); + QString isConv = convertibleToCppFunctionName(typeName, typeName); + writeAddPythonToCppConversion(s, converterVar, toCpp, isConv); +} + +void CppGenerator::writeContainerConverterFunctions(QTextStream& s, const AbstractMetaType* containerType) +{ + writeCppToPythonFunction(s, containerType); + writePythonToCppConversionFunctions(s, containerType); +} + +void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData, + GeneratorContext &context) +{ + const AbstractMetaFunction* rfunc = overloadData.referenceFunction(); + const AbstractMetaClass* ownerClass = rfunc->ownerClass(); + int minArgs = overloadData.minArgs(); + int maxArgs = overloadData.maxArgs(); + bool initPythonArguments; + bool usesNamedArguments; + + // If method is a constructor... + if (rfunc->isConstructor()) { + // 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< ::"; + QString qualifiedCppName; + if (!context.forSmartPointer()) + qualifiedCppName = ownerClass->qualifiedCppName(); + else + qualifiedCppName = context.preciseType()->cppSignature(); + + s << qualifiedCppName << " >()))" << endl; + Indentation indent(INDENT); + s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl; + } + // Declare pointer for the underlying C++ object. + s << INDENT << "::"; + if (!context.forSmartPointer()) { + s << (shouldGenerateCppWrapper(ownerClass) ? wrapperName(ownerClass) + : ownerClass->qualifiedCppName()); + } else { + s << context.preciseType()->cppSignature(); + } + s << "* cptr = 0;" << endl; + + initPythonArguments = maxArgs > 0; + usesNamedArguments = !ownerClass->isQObject() && overloadData.hasArgumentWithDefaultValue(); + + } else { + if (rfunc->implementingClass() && + (!rfunc->implementingClass()->isNamespace() && overloadData.hasInstanceFunction())) { + writeCppSelfDefinition(s, rfunc, context, overloadData.hasStaticFunction()); + } + if (!rfunc->isInplaceOperator() && overloadData.hasNonVoidReturnType()) + s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl; + + initPythonArguments = minArgs != maxArgs || maxArgs > 1; + usesNamedArguments = rfunc->isCallOperator() || overloadData.hasArgumentWithDefaultValue(); + } + + if (maxArgs > 0) { + s << INDENT << "int overloadId = -1;" << endl; + s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR; + if (pythonFunctionWrapperUsesListOfArguments(overloadData)) + s << "[] = { 0" << QString::fromLatin1(", 0").repeated(maxArgs-1) << " }"; + s << ';' << endl; + writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR)); + } + + if (usesNamedArguments && !rfunc->isCallOperator()) + s << INDENT << "int numNamedArgs = (kwds ? PyDict_Size(kwds) : 0);" << endl; + + if (initPythonArguments) { + s << INDENT << "int numArgs = "; + if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor() && !pythonFunctionWrapperUsesListOfArguments(overloadData)) + s << "(" PYTHON_ARG " == 0 ? 0 : 1);" << endl; + else + writeArgumentsInitializer(s, overloadData); + } +} + +void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, + GeneratorContext &classContext) +{ + ErrorCode errorCode(-1); + OverloadData overloadData(overloads, this); + + const AbstractMetaFunction* rfunc = overloadData.referenceFunction(); + const AbstractMetaClass* metaClass = rfunc->ownerClass(); + + s << "static int" << endl; + s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* args, PyObject* kwds)" << endl; + s << '{' << endl; + + QSet argNamesSet; + if (usePySideExtensions() && metaClass->isQObject()) { + // Write argNames variable with all known argument names. + const OverloadData::MetaFunctionList &overloads = overloadData.overloads(); + for (const AbstractMetaFunction *func : overloads) { + const AbstractMetaArgumentList &arguments = func->arguments(); + for (const AbstractMetaArgument *arg : arguments) { + if (arg->defaultValueExpression().isEmpty() || func->argumentRemoved(arg->argumentIndex() + 1)) + continue; + argNamesSet << arg->name(); + } + } + QStringList argNamesList = argNamesSet.toList(); + qSort(argNamesList.begin(), argNamesList.end()); + if (argNamesList.isEmpty()) { + s << INDENT << "const char** argNames = 0;" << endl; + } else { + s << INDENT << "const char* argNames[] = {\"" + << argNamesList.join(QLatin1String("\", \"")) << "\"};" << endl; + } + s << INDENT << "const QMetaObject* metaObject;" << endl; + } + + s << INDENT << "SbkObject* sbkSelf = reinterpret_cast(" PYTHON_SELF_VAR ");" << endl; + + if (metaClass->isAbstract() || metaClass->baseClassNames().size() > 1) { + s << INDENT << "SbkObjectType* type = reinterpret_cast(" PYTHON_SELF_VAR "->ob_type);" << endl; + s << INDENT << "SbkObjectType* myType = reinterpret_cast(" << cpythonTypeNameExt(metaClass->typeEntry()) << ");" << endl; + } + + if (metaClass->isAbstract()) { + s << INDENT << "if (type == myType) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyErr_SetString(PyExc_NotImplementedError," << endl; + { + Indentation indentation(INDENT); + s << INDENT << "\"'" << metaClass->qualifiedCppName(); + } + s << "' represents a C++ abstract class and cannot be instantiated\");" << endl; + s << INDENT << "return " << m_currentErrorCode << ';' << endl; + } + s << INDENT << '}' << endl << endl; + } + + if (metaClass->baseClassNames().size() > 1) { + if (!metaClass->isAbstract()) { + s << INDENT << "if (type != myType) {" << endl; + } + { + Indentation indentation(INDENT); + s << INDENT << "Shiboken::ObjectType::copyMultimpleheritance(type, myType);" << endl; + } + if (!metaClass->isAbstract()) + s << INDENT << '}' << endl << endl; + } + + writeMethodWrapperPreamble(s, overloadData, classContext); + + s << endl; + + if (overloadData.maxArgs() > 0) + writeOverloadedFunctionDecisor(s, overloadData); + + writeFunctionCalls(s, overloadData, classContext); + s << endl; + + s << INDENT << "if (PyErr_Occurred() || !Shiboken::Object::setCppPointer(sbkSelf, Shiboken::SbkType< ::" << metaClass->qualifiedCppName() << " >(), cptr)) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "delete cptr;" << endl; + s << INDENT << "return " << m_currentErrorCode << ';' << endl; + } + s << INDENT << '}' << endl; + if (overloadData.maxArgs() > 0) { + s << INDENT << "if (!cptr) goto " << cpythonFunctionName(rfunc) << "_TypeError;" << endl; + s << endl; + } + + s << INDENT << "Shiboken::Object::setValidCpp(sbkSelf, true);" << endl; + // If the created C++ object has a C++ wrapper the ownership is assigned to Python + // (first "1") and the flag indicating that the Python wrapper holds an C++ wrapper + // is marked as true (the second "1"). Otherwise the default values apply: + // Python owns it and C++ wrapper is false. + if (shouldGenerateCppWrapper(overloads.first()->ownerClass())) + s << INDENT << "Shiboken::Object::setHasCppWrapper(sbkSelf, true);" << endl; + // Need to check if a wrapper for same pointer is already registered + // Caused by bug PYSIDE-217, where deleted objects' wrappers are not released + s << INDENT << "if (Shiboken::BindingManager::instance().hasWrapper(cptr)) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "Shiboken::BindingManager::instance().releaseWrapper(Shiboken::BindingManager::instance().retrieveWrapper(cptr));" << endl; + } + s << INDENT << "}" << endl; + s << INDENT << "Shiboken::BindingManager::instance().registerWrapper(sbkSelf, cptr);" << endl; + + // 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 << "metaObject = cptr->metaObject(); // <- init python qt properties" << endl; + s << INDENT << "if (kwds && !PySide::fillQtProperties(" PYTHON_SELF_VAR ", metaObject, kwds, argNames, " << argNamesSet.count() << "))" << endl; + { + Indentation indentation(INDENT); + s << INDENT << "return " << m_currentErrorCode << ';' << endl; + } + } + + // Constructor code injections, position=end + bool hasCodeInjectionsAtEnd = false; + for (AbstractMetaFunction *func : overloads) { + const CodeSnipList &injectedCodeSnips = func->injectedCodeSnips(); + for (const CodeSnip &cs : injectedCodeSnips) { + if (cs.position == TypeSystem::CodeSnipPositionEnd) { + hasCodeInjectionsAtEnd = true; + break; + } + } + } + if (hasCodeInjectionsAtEnd) { + // FIXME: C++ arguments are not available in code injection on constructor when position = end. + s << INDENT << "switch(overloadId) {" << endl; + for (AbstractMetaFunction *func : overloads) { + Indentation indent(INDENT); + const CodeSnipList &injectedCodeSnips = func->injectedCodeSnips(); + for (const CodeSnip &cs : injectedCodeSnips) { + if (cs.position == TypeSystem::CodeSnipPositionEnd) { + s << INDENT << "case " << metaClass->functions().indexOf(func) << ':' << endl; + s << INDENT << '{' << endl; + { + Indentation indent(INDENT); + writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func); + } + s << INDENT << '}' << endl; + break; + } + } + } + s << '}' << endl; + } + + s << endl; + s << endl << INDENT << "return 1;" << endl; + if (overloadData.maxArgs() > 0) + writeErrorSection(s, overloadData); + s << '}' << endl << endl; +} + +void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, + GeneratorContext &classContext) +{ + OverloadData overloadData(overloads, this); + const AbstractMetaFunction* rfunc = overloadData.referenceFunction(); + + int maxArgs = overloadData.maxArgs(); + + s << "static PyObject* "; + s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR; + if (maxArgs > 0) { + s << ", PyObject* " << (pythonFunctionWrapperUsesListOfArguments(overloadData) ? "args" : PYTHON_ARG); + if (overloadData.hasArgumentWithDefaultValue() || rfunc->isCallOperator()) + s << ", PyObject* kwds"; + } + s << ')' << endl << '{' << endl; + + writeMethodWrapperPreamble(s, overloadData, classContext); + + s << endl; + + /* + * Make sure reverse <> operators defined in other classes (specially from other modules) + * are called. A proper and generic solution would require an reengineering in the operator + * system like the extended converters. + * + * Solves #119 - QDataStream <> operators not working for QPixmap + * http://bugs.openbossa.org/show_bug.cgi?id=119 + */ + bool hasReturnValue = overloadData.hasNonVoidReturnType(); + bool callExtendedReverseOperator = hasReturnValue + && !rfunc->isInplaceOperator() + && !rfunc->isCallOperator() + && rfunc->isOperatorOverload(); + if (callExtendedReverseOperator) { + QString revOpName = ShibokenGenerator::pythonOperatorFunctionName(rfunc).insert(2, QLatin1Char('r')); + if (rfunc->isBinaryOperator()) { + 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(\"" << 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(\"" << revOpName << "\"));" << endl; + s << INDENT << "if (revOpMethod && PyCallable_Check(revOpMethod)) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << PYTHON_RETURN_VAR " = PyObject_CallFunction(revOpMethod, const_cast(\"O\"), " PYTHON_SELF_VAR ");" << 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 << '}' << endl; + } + s << INDENT << "}" << endl; + s << INDENT << "Py_XDECREF(revOpMethod);" << endl << endl; + } + 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; + } + + if (maxArgs > 0) + writeOverloadedFunctionDecisor(s, overloadData); + + writeFunctionCalls(s, overloadData, classContext); + + if (callExtendedReverseOperator) + s << endl << INDENT << "} // End of \"if (!" PYTHON_RETURN_VAR ")\"" << endl; + + s << endl; + + writeFunctionReturnErrorCheckSection(s, hasReturnValue && !rfunc->isInplaceOperator()); + + if (hasReturnValue) { + if (rfunc->isInplaceOperator()) { + s << INDENT << "Py_INCREF(" PYTHON_SELF_VAR ");\n"; + s << INDENT << "return " PYTHON_SELF_VAR ";\n"; + } else { + s << INDENT << "return " PYTHON_RETURN_VAR ";\n"; + } + } else { + s << INDENT << "Py_RETURN_NONE;" << endl; + } + + if (maxArgs > 0) + writeErrorSection(s, overloadData); + + s << '}' << endl << endl; +} + +void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overloadData) +{ + const AbstractMetaFunction* rfunc = overloadData.referenceFunction(); + s << "PyTuple_GET_SIZE(args);" << endl; + + int minArgs = overloadData.minArgs(); + int maxArgs = overloadData.maxArgs(); + + s << INDENT << "PyObject* "; + s << PYTHON_ARGS "[] = {" + << QString(maxArgs, QLatin1Char('0')).split(QLatin1String(""), QString::SkipEmptyParts).join(QLatin1String(", ")) + << "};" << endl; + s << endl; + + if (overloadData.hasVarargs()) { + maxArgs--; + if (minArgs > maxArgs) + minArgs = maxArgs; + + 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 << endl; + } + + bool usesNamedArguments = overloadData.hasArgumentWithDefaultValue(); + + s << INDENT << "// invalid argument lengths" << endl; + bool ownerClassIsQObject = rfunc->ownerClass() && rfunc->ownerClass()->isQObject() && rfunc->isConstructor(); + if (usesNamedArguments) { + if (!ownerClassIsQObject) { + s << INDENT << "if (numArgs" << (overloadData.hasArgumentWithDefaultValue() ? " + numNamedArgs" : "") << " > " << maxArgs << ") {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): too many arguments\");" << endl; + s << INDENT << "return " << m_currentErrorCode << ';' << endl; + } + s << INDENT << '}'; + } + if (minArgs > 0) { + if (ownerClassIsQObject) + s << INDENT; + else + s << " else "; + s << "if (numArgs < " << minArgs << ") {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): not enough arguments\");" << endl; + s << INDENT << "return " << m_currentErrorCode << ';' << endl; + } + s << INDENT << '}'; + } + } + const QVector invalidArgsLength = overloadData.invalidArgumentLengths(); + if (!invalidArgsLength.isEmpty()) { + QStringList invArgsLen; + for (int i : qAsConst(invalidArgsLength)) + invArgsLen << QStringLiteral("numArgs == %1").arg(i); + if (usesNamedArguments && (!ownerClassIsQObject || minArgs > 0)) + s << " else "; + else + s << INDENT; + s << "if (" << invArgsLen.join(QLatin1String(" || ")) << ")" << endl; + Indentation indent(INDENT); + s << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;"; + } + s << endl << endl; + + QString funcName; + if (rfunc->isOperatorOverload()) + funcName = ShibokenGenerator::pythonOperatorFunctionName(rfunc); + else + funcName = rfunc->name(); + + QString argsVar = overloadData.hasVarargs() ? QLatin1String("nonvarargs") : QLatin1String("args"); + s << INDENT << "if (!"; + if (usesNamedArguments) + 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; + { + Indentation indent(INDENT); + s << INDENT << "return " << m_currentErrorCode << ';' << endl; + } + s << endl; +} + +void CppGenerator::writeCppSelfDefinition(QTextStream &s, + GeneratorContext &context, + bool hasStaticOverload, + bool cppSelfAsReference) +{ + const AbstractMetaClass *metaClass = context.metaClass(); + bool useWrapperClass = avoidProtectedHack() && metaClass->hasProtectedMembers(); + QString className; + if (!context.forSmartPointer()) { + className = useWrapperClass + ? wrapperName(metaClass) + : (QLatin1String("::") + metaClass->qualifiedCppName()); + } else { + className = context.preciseType()->cppSignature(); + } + + QString cppSelfAttribution; + QString pythonSelfVar = QLatin1String(PYTHON_SELF_VAR); + QString cpythonWrapperCPtrResult; + if (!context.forSmartPointer()) + cpythonWrapperCPtrResult = cpythonWrapperCPtr(metaClass, pythonSelfVar); + else + cpythonWrapperCPtrResult = cpythonWrapperCPtr(context.preciseType(), pythonSelfVar); + + if (cppSelfAsReference) { + QString cast = useWrapperClass ? QString::fromLatin1("(%1*)").arg(className) : QString(); + cppSelfAttribution = QString::fromLatin1("%1& %2 = *(%3%4)") + .arg(className, QLatin1String(CPP_SELF_VAR), cast, + cpythonWrapperCPtrResult); + } else { + s << INDENT << className << "* " CPP_SELF_VAR " = 0;" << endl; + writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR)); + cppSelfAttribution = QString::fromLatin1("%1 = %2%3") + .arg(QLatin1String(CPP_SELF_VAR), + (useWrapperClass ? QString::fromLatin1("(%1*)").arg(className) : QString()), + cpythonWrapperCPtrResult); + } + + // Checks if the underlying C++ object is valid. + if (hasStaticOverload && !cppSelfAsReference) { + s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl; + { + Indentation indent(INDENT); + writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR)); + s << INDENT << cppSelfAttribution << ';' << endl; + } + s << INDENT << '}' << endl; + return; + } + + writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR)); + s << INDENT << cppSelfAttribution << ';' << endl; +} + +void CppGenerator::writeCppSelfDefinition(QTextStream &s, + const AbstractMetaFunction *func, + GeneratorContext &context, + bool hasStaticOverload) +{ + if (!func->ownerClass() || func->isConstructor()) + return; + + if (func->isOperatorOverload() && func->isBinaryOperator()) { + QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry()); + 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 << "if (isReverse)" << endl; + Indentation indent(INDENT); + s << INDENT << "std::swap(" PYTHON_SELF_VAR ", " PYTHON_ARG ");" << endl; + } + + writeCppSelfDefinition(s, context, hasStaticOverload); +} + +void CppGenerator::writeErrorSection(QTextStream& s, OverloadData& overloadData) +{ + const AbstractMetaFunction* rfunc = overloadData.referenceFunction(); + s << endl << INDENT << cpythonFunctionName(rfunc) << "_TypeError:" << endl; + Indentation indentation(INDENT); + QString funcName = fullPythonFunctionName(rfunc); + + QString argsVar = pythonFunctionWrapperUsesListOfArguments(overloadData) + ? QLatin1String("args") : QLatin1String(PYTHON_ARG); + if (verboseErrorMessagesDisabled()) { + s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\", 0);" << endl; + } else { + QStringList overloadSignatures; + const OverloadData::MetaFunctionList &overloads = overloadData.overloads(); + for (const AbstractMetaFunction *f : overloads) { + QStringList args; + const AbstractMetaArgumentList &arguments = f->arguments(); + for (AbstractMetaArgument *arg : arguments) { + QString strArg; + AbstractMetaType* argType = arg->type(); + if (isCString(argType)) { + strArg = QLatin1String("\" SBK_STR_NAME \""); + } else if (argType->isPrimitive()) { + const PrimitiveTypeEntry* ptp = reinterpret_cast(argType->typeEntry()); + while (ptp->referencedTypeEntry()) + ptp = ptp->referencedTypeEntry(); + strArg = ptp->name(); + if (strArg == QLatin1String("QString")) { + strArg = QLatin1String("unicode"); + } else if (strArg == QLatin1String("QChar")) { + strArg = QLatin1String("1-unicode"); + } else { + strArg = ptp->name(); + static const QRegularExpression regex(QStringLiteral("^signed\\s+")); + Q_ASSERT(regex.isValid()); + strArg.remove(regex); + if (strArg == QLatin1String("double")) + strArg = QLatin1String("float"); + } + } else if (argType->typeEntry()->isContainer()) { + strArg = argType->fullName(); + if (strArg == QLatin1String("QList") || strArg == QLatin1String("QVector") + || strArg == QLatin1String("QLinkedList") || strArg == QLatin1String("QStack") + || strArg == QLatin1String("QQueue")) { + strArg = QLatin1String("list"); + } else if (strArg == QLatin1String("QMap") || strArg == QLatin1String("QHash") + || strArg == QLatin1String("QMultiMap") || strArg == QLatin1String("QMultiHash")) { + strArg = QLatin1String("dict"); + } else if (strArg == QLatin1String("QPair")) { + strArg = QLatin1String("2-tuple"); + } + } else { + strArg = argType->fullName(); + if (strArg == QLatin1String("PyUnicode")) + strArg = QLatin1String("unicode"); + else if (strArg == QLatin1String("PyString")) + strArg = QLatin1String("str"); + else if (strArg == QLatin1String("PyBytes")) + strArg = QLatin1String("\" SBK_STR_NAME \""); + else if (strArg == QLatin1String("PySequece")) + strArg = QLatin1String("list"); + else if (strArg == QLatin1String("PyTuple")) + strArg = QLatin1String("tuple"); + else if (strArg == QLatin1String("PyDict")) + strArg = QLatin1String("dict"); + else if (strArg == QLatin1String("PyObject")) + strArg = QLatin1String("object"); + else if (strArg == QLatin1String("PyCallable")) + strArg = QLatin1String("callable"); + else if (strArg == QLatin1String("uchar")) + strArg = QLatin1String("buffer"); // This depends on an inject code to be true, but if it's not true + // the function wont work at all, so it must be true. + } + if (!arg->defaultValueExpression().isEmpty()) { + strArg += QLatin1String(" = "); + if ((isCString(argType) || isPointerToWrapperType(argType)) + && arg->defaultValueExpression() == QLatin1String("0")) { + strArg += QLatin1String("None"); + } else { + QString e = arg->defaultValueExpression(); + e.replace(QLatin1String("::"), QLatin1String(".")); + e.replace(QLatin1String("\""), QLatin1String("\\\"")); + strArg += e; + } + } + args << strArg; + } + overloadSignatures << QLatin1Char('"') + args.join(QLatin1String(", ")) + QLatin1Char('"'); + } + s << INDENT << "const char* overloads[] = {" << overloadSignatures.join(QLatin1String(", ")) + << ", 0};" << endl; + s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\", overloads);" << endl; + } + s << INDENT << "return " << m_currentErrorCode << ';' << endl; +} + +void CppGenerator::writeFunctionReturnErrorCheckSection(QTextStream& s, bool hasReturnValue) +{ + s << INDENT << "if (PyErr_Occurred()" << (hasReturnValue ? " || !" PYTHON_RETURN_VAR : "") << ") {" << endl; + { + Indentation indent(INDENT); + if (hasReturnValue) + s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl; + s << INDENT << "return " << m_currentErrorCode << ';' << endl; + } + s << INDENT << '}' << endl; +} + +void CppGenerator::writeInvalidPyObjectCheck(QTextStream& s, const QString& pyObj) +{ + s << INDENT << "if (!Shiboken::Object::isValid(" << pyObj << "))" << endl; + Indentation indent(INDENT); + s << INDENT << "return " << m_currentErrorCode << ';' << endl; +} + +static QString pythonToCppConverterForArgumentName(const QString& argumentName) +{ + static const QRegularExpression pyArgsRegex(QLatin1String(PYTHON_ARGS"(\\[\\d+[-]?\\d*\\])")); + Q_ASSERT(pyArgsRegex.isValid()); + const QRegularExpressionMatch match = pyArgsRegex.match(argumentName); + QString result = QLatin1String(PYTHON_TO_CPP_VAR); + if (match.hasMatch()) + result += match.captured(1); + return result; +} + +void CppGenerator::writeTypeCheck(QTextStream& s, const AbstractMetaType* argType, QString argumentName, bool isNumber, QString customType, bool rejectNull) +{ + QString customCheck; + if (!customType.isEmpty()) { + AbstractMetaType* metaType; + customCheck = guessCPythonCheckFunction(customType, &metaType); + if (metaType) + argType = metaType; + } + + // TODO-CONVERTER: merge this with the code below. + QString typeCheck; + if (customCheck.isEmpty()) + typeCheck = cpythonIsConvertibleFunction(argType, argType->isEnum() ? false : isNumber); + else + typeCheck = customCheck; + typeCheck.append(QString::fromLatin1("(%1)").arg(argumentName)); + + // TODO-CONVERTER ----------------------------------------------------------------------- + if (customCheck.isEmpty() && !argType->typeEntry()->isCustom()) { + typeCheck = QString::fromLatin1("(%1 = %2))").arg(pythonToCppConverterForArgumentName(argumentName), typeCheck); + if (!isNumber && argType->typeEntry()->isCppPrimitive()) + typeCheck.prepend(QString::fromLatin1("%1(%2) && ").arg(cpythonCheckFunction(argType), argumentName)); + } + // TODO-CONVERTER ----------------------------------------------------------------------- + + if (rejectNull) + typeCheck = QString::fromLatin1("(%1 != Py_None && %2)").arg(argumentName, typeCheck); + + s << typeCheck; +} + +static void checkTypeViability(const AbstractMetaFunction* func, const AbstractMetaType* type, int argIdx) +{ + if (!type + || !type->typeEntry()->isPrimitive() + || type->indirections() == 0 + || ShibokenGenerator::isCString(type) + || func->argumentRemoved(argIdx) + || !func->typeReplaced(argIdx).isEmpty() + || !func->conversionRule(TypeSystem::All, argIdx).isEmpty() + || func->hasInjectedCode()) + return; + QString prefix; + if (func->ownerClass()) + prefix = func->ownerClass()->qualifiedCppName() + QLatin1String("::"); + qCWarning(lcShiboken).noquote().nospace() + << QString::fromLatin1("There's no user provided way (conversion rule, argument removal, custom code, etc) " + "to handle the primitive %1 type '%2' in function '%3%4'.") + .arg(argIdx == 0 ? QStringLiteral("return") : QStringLiteral("argument"), + type->cppSignature(), prefix, func->signature()); +} + +static void checkTypeViability(const AbstractMetaFunction* func) +{ + if (func->isUserAdded()) + return; + const AbstractMetaType* type = func->type(); + checkTypeViability(func, type, 0); + for (int i = 0; i < func->arguments().count(); ++i) + checkTypeViability(func, func->arguments().at(i)->type(), i + 1); +} + +void CppGenerator::writeTypeCheck(QTextStream& s, const OverloadData* overloadData, QString argumentName) +{ + QSet numericTypes; + const OverloadDataList &overloads = overloadData->previousOverloadData()->nextOverloadData(); + for (OverloadData *od : overloads) { + const OverloadData::MetaFunctionList &odOverloads = od->overloads(); + for (const AbstractMetaFunction *func : odOverloads) { + checkTypeViability(func); + const AbstractMetaType* argType = od->argument(func)->type(); + if (!argType->isPrimitive()) + continue; + if (ShibokenGenerator::isNumber(argType->typeEntry())) + numericTypes << argType->typeEntry(); + } + } + + // This condition trusts that the OverloadData object will arrange for + // PyInt type to come after the more precise numeric types (e.g. float and bool) + const AbstractMetaType* argType = overloadData->argType(); + bool numberType = numericTypes.count() == 1 || ShibokenGenerator::isPyInt(argType); + QString customType = (overloadData->hasArgumentTypeReplace() ? overloadData->argumentTypeReplaced() : QString()); + bool rejectNull = shouldRejectNullPointerArgument(overloadData->referenceFunction(), overloadData->argPos()); + writeTypeCheck(s, argType, argumentName, numberType, customType, rejectNull); +} + +void CppGenerator::writeArgumentConversion(QTextStream& s, + const AbstractMetaType* argType, + const QString& argName, const QString& pyArgName, + const AbstractMetaClass* context, + const QString& defaultValue, + bool castArgumentAsUnused) +{ + if (argType->typeEntry()->isCustom() || argType->typeEntry()->isVarargs()) + return; + if (isWrapperType(argType)) + writeInvalidPyObjectCheck(s, pyArgName); + writePythonToCppTypeConversion(s, argType, pyArgName, argName, context, defaultValue); + if (castArgumentAsUnused) + writeUnusedVariableCast(s, argName); +} + +const AbstractMetaType* CppGenerator::getArgumentType(const AbstractMetaFunction* func, int argPos) +{ + if (argPos < 0 || argPos > func->arguments().size()) { + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("Argument index for function '%1' out of range.").arg(func->signature()); + return 0; + } + + const AbstractMetaType* argType = 0; + QString typeReplaced = func->typeReplaced(argPos); + if (typeReplaced.isEmpty()) + argType = (argPos == 0) ? func->type() : func->arguments().at(argPos-1)->type(); + else + argType = buildAbstractMetaTypeFromString(typeReplaced); + if (!argType && !m_knownPythonTypes.contains(typeReplaced)) { + qCWarning(lcShiboken).noquote().nospace() + << QString::fromLatin1("Unknown type '%1' used as argument type replacement "\ + "in function '%2', the generated code may be broken.") + .arg(typeReplaced, func->signature()); + } + return argType; +} + +void CppGenerator::writePythonToCppTypeConversion(QTextStream& s, + const AbstractMetaType* type, + const QString& pyIn, + const QString& cppOut, + const AbstractMetaClass* /* context */, + const QString& defaultValue) +{ + const TypeEntry* typeEntry = type->typeEntry(); + if (typeEntry->isCustom() || typeEntry->isVarargs()) + return; + + QString cppOutAux = cppOut + QLatin1String("_local"); + + bool treatAsPointer = isValueTypeWithCopyConstructorOnly(type); + bool isPointerOrObjectType = (isObjectType(type) || isPointer(type)) && !isUserPrimitive(type) && !isCppPrimitive(type); + bool isNotContainerEnumOrFlags = !typeEntry->isContainer() && !typeEntry->isEnum() && !typeEntry->isFlags(); + bool mayHaveImplicitConversion = type->referenceType() == LValueReference + && !isUserPrimitive(type) + && !isCppPrimitive(type) + && isNotContainerEnumOrFlags + && !(treatAsPointer || isPointerOrObjectType); + QString typeName = getFullTypeNameWithoutModifiers(type); + + bool isProtectedEnum = false; + + if (mayHaveImplicitConversion) { + s << INDENT << typeName << ' ' << cppOutAux; + writeMinimalConstructorExpression(s, type, defaultValue); + s << ';' << endl; + } else if (avoidProtectedHack() && type->typeEntry()->isEnum()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(type); + if (metaEnum && metaEnum->isProtected()) { + typeName = QLatin1String("long"); + isProtectedEnum = true; + } + } + + s << INDENT << typeName; + if (treatAsPointer || isPointerOrObjectType) { + s << "* " << cppOut; + if (!defaultValue.isEmpty()) + s << " = " << defaultValue; + } else if (type->referenceType() == LValueReference && !typeEntry->isPrimitive() && isNotContainerEnumOrFlags) { + s << "* " << cppOut << " = &" << cppOutAux; + } else { + s << ' ' << cppOut; + if (isProtectedEnum && avoidProtectedHack()) { + s << " = "; + if (defaultValue.isEmpty()) + s << "0"; + else + s << "(long)" << defaultValue; + } else if (isUserPrimitive(type) || typeEntry->isEnum() || typeEntry->isFlags()) { + writeMinimalConstructorExpression(s, typeEntry, defaultValue); + } else if (!type->isContainer() && !type->isSmartPointer()) { + writeMinimalConstructorExpression(s, type, defaultValue); + } + } + s << ';' << endl; + + QString pythonToCppFunc = pythonToCppConverterForArgumentName(pyIn); + + s << INDENT; + if (!defaultValue.isEmpty()) + s << "if (" << pythonToCppFunc << ") "; + + QString pythonToCppCall = QString::fromLatin1("%1(%2, &%3)").arg(pythonToCppFunc, pyIn, cppOut); + if (!mayHaveImplicitConversion) { + s << pythonToCppCall << ';' << endl; + return; + } + + if (!defaultValue.isEmpty()) + s << '{' << endl << INDENT; + + s << "if (Shiboken::Conversions::isImplicitConversion(reinterpret_cast(" + << cpythonTypeNameExt(type) << "), " << pythonToCppFunc << "))" << endl; + { + Indentation indent(INDENT); + s << INDENT << pythonToCppFunc << '(' << pyIn << ", &" << cppOutAux << ");" << endl; + } + s << INDENT << "else" << endl; + { + Indentation indent(INDENT); + s << INDENT << pythonToCppCall << ';' << endl; + } + + if (!defaultValue.isEmpty()) + s << INDENT << '}'; + s << endl; +} + +static void addConversionRuleCodeSnippet(CodeSnipList& snippetList, QString& rule, + TypeSystem::Language /* conversionLanguage */, + TypeSystem::Language snippetLanguage, + QString outputName = QString(), + QString inputName = QString()) +{ + if (rule.isEmpty()) + return; + if (snippetLanguage == TypeSystem::TargetLangCode) { + rule.replace(QLatin1String("%in"), inputName); + rule.replace(QLatin1String("%out"), outputName + QLatin1String("_out")); + } else { + rule.replace(QLatin1String("%out"), outputName); + } + CodeSnip snip(0, snippetLanguage); + snip.position = (snippetLanguage == TypeSystem::NativeCode) ? TypeSystem::CodeSnipPositionAny : TypeSystem::CodeSnipPositionBeginning; + snip.addCode(rule); + snippetList << snip; +} + +void CppGenerator::writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language) +{ + CodeSnipList snippets; + const AbstractMetaArgumentList &arguments = func->arguments(); + for (AbstractMetaArgument *arg : arguments) { + QString rule = func->conversionRule(language, arg->argumentIndex() + 1); + addConversionRuleCodeSnippet(snippets, rule, language, TypeSystem::TargetLangCode, + arg->name(), arg->name()); + } + writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func); +} + +void CppGenerator::writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language, const QString& outputVar) +{ + CodeSnipList snippets; + QString rule = func->conversionRule(language, 0); + addConversionRuleCodeSnippet(snippets, rule, language, language, outputVar); + writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionAny, language, func); +} + +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 << "Py_INCREF(Py_None);" << endl; + } +} + +void CppGenerator::writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData) +{ + s << INDENT << "// Overloaded function decisor" << endl; + const AbstractMetaFunction* rfunc = overloadData.referenceFunction(); + const OverloadData::MetaFunctionList &functionOverloads = overloadData.overloadsWithoutRepetition(); + for (int i = 0; i < functionOverloads.count(); i++) + s << INDENT << "// " << i << ": " << functionOverloads.at(i)->minimalSignature() << endl; + writeOverloadedFunctionDecisorEngine(s, &overloadData); + s << endl; + + // Ensure that the direct overload that called this reverse + // is called. + if (rfunc->isOperatorOverload() && !rfunc->isCallOperator()) { + s << INDENT << "if (isReverse && overloadId == -1) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"reverse operator not implemented.\");" << endl; + s << INDENT << "return 0;" << endl; + } + s << INDENT << "}" << endl << endl; + } + + s << INDENT << "// Function signature not found." << endl; + s << INDENT << "if (overloadId == -1) goto " << cpythonFunctionName(overloadData.referenceFunction()) << "_TypeError;" << endl; + s << endl; +} + +void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const OverloadData* parentOverloadData) +{ + bool hasDefaultCall = parentOverloadData->nextArgumentHasDefaultValue(); + const AbstractMetaFunction* referenceFunction = parentOverloadData->referenceFunction(); + + // If the next argument has not an argument with a default value, it is still possible + // that one of the overloads for the current overload data has its final occurrence here. + // If found, the final occurrence of a method is attributed to the referenceFunction + // variable to be used further on this method on the conditional that identifies default + // method calls. + if (!hasDefaultCall) { + const OverloadData::MetaFunctionList &overloads = parentOverloadData->overloads(); + for (const AbstractMetaFunction *func : overloads) { + if (parentOverloadData->isFinalOccurrence(func)) { + referenceFunction = func; + hasDefaultCall = true; + break; + } + } + } + + int maxArgs = parentOverloadData->maxArgs(); + // Python constructors always receive multiple arguments. + bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(*parentOverloadData); + + // Functions without arguments are identified right away. + if (maxArgs == 0) { + s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(referenceFunction); + s << "; // " << referenceFunction->minimalSignature() << endl; + return; + + // To decide if a method call is possible at this point the current overload + // data object cannot be the head, since it is just an entry point, or a root, + // for the tree of arguments and it does not represent a valid method call. + } else if (!parentOverloadData->isHeadOverloadData()) { + bool isLastArgument = parentOverloadData->nextOverloadData().isEmpty(); + bool signatureFound = parentOverloadData->overloads().size() == 1; + + // The current overload data describes the last argument of a signature, + // so the method can be identified right now. + if (isLastArgument || (signatureFound && !hasDefaultCall)) { + const AbstractMetaFunction* func = parentOverloadData->referenceFunction(); + s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func); + s << "; // " << func->minimalSignature() << endl; + return; + } + } + + bool isFirst = true; + + // If the next argument has a default value the decisor can perform a method call; + // it just need to check if the number of arguments received from Python are equal + // to the number of parameters preceding the argument with the default value. + const OverloadDataList &overloads = parentOverloadData->nextOverloadData(); + if (hasDefaultCall) { + isFirst = false; + int numArgs = parentOverloadData->argPos() + 1; + s << INDENT << "if (numArgs == " << numArgs << ") {" << endl; + { + Indentation indent(INDENT); + const AbstractMetaFunction* func = referenceFunction; + for (OverloadData *overloadData : overloads) { + const AbstractMetaFunction* defValFunc = overloadData->getFunctionWithDefaultValue(); + if (defValFunc) { + func = defValFunc; + break; + } + } + s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func); + s << "; // " << func->minimalSignature() << endl; + } + s << INDENT << '}'; + } + + for (OverloadData *overloadData : overloads) { + bool signatureFound = overloadData->overloads().size() == 1 + && !overloadData->getFunctionWithDefaultValue() + && !overloadData->findNextArgWithDefault(); + + const AbstractMetaFunction* refFunc = overloadData->referenceFunction(); + + QStringList typeChecks; + QString pyArgName = (usePyArgs && maxArgs > 1) + ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(overloadData->argPos()) + : QLatin1String(PYTHON_ARG); + OverloadData* od = overloadData; + int startArg = od->argPos(); + int sequenceArgCount = 0; + while (od && !od->argType()->isVarargs()) { + bool typeReplacedByPyObject = od->argumentTypeReplaced() == QLatin1String("PyObject"); + if (!typeReplacedByPyObject) { + if (usePyArgs) + pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(od->argPos()); + QString typeCheck; + QTextStream tck(&typeCheck); + const AbstractMetaFunction* func = od->referenceFunction(); + + if (func->isConstructor() && func->arguments().count() == 1) { + const AbstractMetaClass* ownerClass = func->ownerClass(); + const ComplexTypeEntry* baseContainerType = ownerClass->typeEntry()->baseContainerType(); + if (baseContainerType && baseContainerType == func->arguments().first()->type()->typeEntry() && isCopyable(ownerClass)) { + tck << '!' << cpythonCheckFunction(ownerClass->typeEntry()) << pyArgName << ')' << endl; + Indentation indent(INDENT); + tck << INDENT << "&& "; + } + } + writeTypeCheck(tck, od, pyArgName); + typeChecks << typeCheck; + } + + sequenceArgCount++; + + if (od->nextOverloadData().isEmpty() + || od->nextArgumentHasDefaultValue() + || od->nextOverloadData().size() != 1 + || od->overloads().size() != od->nextOverloadData().first()->overloads().size()) { + overloadData = od; + od = 0; + } else { + od = od->nextOverloadData().first(); + } + } + + if (usePyArgs && signatureFound) { + AbstractMetaArgumentList args = refFunc->arguments(); + int lastArgIsVarargs = (int) (args.size() > 1 && args.last()->type()->isVarargs()); + int numArgs = args.size() - OverloadData::numberOfRemovedArguments(refFunc) - lastArgIsVarargs; + typeChecks.prepend(QString::fromLatin1("numArgs %1 %2").arg(lastArgIsVarargs ? QLatin1String(">=") : QLatin1String("==")).arg(numArgs)); + } else if (sequenceArgCount > 1) { + typeChecks.prepend(QString::fromLatin1("numArgs >= %1").arg(startArg + sequenceArgCount)); + } else if (refFunc->isOperatorOverload() && !refFunc->isCallOperator()) { + typeChecks.prepend(QString::fromLatin1("%1isReverse").arg(refFunc->isReverseOperator() ? QString() : QLatin1String("!"))); + } + + if (isFirst) { + isFirst = false; + s << INDENT; + } else { + s << " else "; + } + s << "if ("; + if (typeChecks.isEmpty()) { + s << "true"; + } else { + Indentation indent(INDENT); + QString separator; + QTextStream sep(&separator); + sep << endl << INDENT << "&& "; + s << typeChecks.join(separator); + } + s << ") {" << endl; + { + Indentation indent(INDENT); + writeOverloadedFunctionDecisorEngine(s, overloadData); + } + s << INDENT << "}"; + } + s << endl; +} + +void CppGenerator::writeFunctionCalls(QTextStream &s, const OverloadData &overloadData, + GeneratorContext &context) +{ + const OverloadData::MetaFunctionList &overloads = overloadData.overloadsWithoutRepetition(); + s << INDENT << "// Call function/method" << endl; + s << INDENT << (overloads.count() > 1 ? "switch (overloadId) " : "") << '{' << endl; + { + Indentation indent(INDENT); + if (overloads.count() == 1) { + writeSingleFunctionCall(s, overloadData, overloads.first(), context); + } else { + for (int i = 0; i < overloads.count(); i++) { + const AbstractMetaFunction* func = overloads.at(i); + s << INDENT << "case " << i << ": // " << func->signature() << endl; + s << INDENT << '{' << endl; + { + Indentation indent(INDENT); + writeSingleFunctionCall(s, overloadData, func, context); + s << INDENT << "break;" << endl; + } + s << INDENT << '}' << endl; + } + } + } + s << INDENT << '}' << endl; +} + +void CppGenerator::writeSingleFunctionCall(QTextStream &s, + const OverloadData &overloadData, + const AbstractMetaFunction *func, + GeneratorContext &context) +{ + if (func->isDeprecated()) { + s << INDENT << "Shiboken::warning(PyExc_DeprecationWarning, 1, \"Function: '" + << func->signature().replace(QLatin1String("::"), QLatin1String(".")) + << "' is marked as deprecated, please check the documentation for more information.\");" << endl; + } + + if (func->functionType() == AbstractMetaFunction::EmptyFunction) { + s << INDENT << "PyErr_Format(PyExc_TypeError, \"%s is a private method.\", \"" + << func->signature().replace(QLatin1String("::"), QLatin1String(".")) + << "\");" << endl; + s << INDENT << "return " << m_currentErrorCode << ';' << endl; + return; + } + + bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData); + + // Handle named arguments. + writeNamedArgumentResolution(s, func, usePyArgs); + + bool injectCodeCallsFunc = injectedCodeCallsCppFunction(func); + bool mayHaveUnunsedArguments = !func->isUserAdded() && func->hasInjectedCode() && injectCodeCallsFunc; + int removedArgs = 0; + for (int argIdx = 0; argIdx < func->arguments().count(); ++argIdx) { + bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, argIdx + 1).isEmpty(); + 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); + s << INDENT << getFullTypeName(arg->type()) << ' ' << cppArgRemoved; + s << " = " << guessScopeForDefaultValue(func, arg) << ';' << endl; + writeUnusedVariableCast(s, cppArgRemoved); + } else if (!injectCodeCallsFunc && !func->isUserAdded() && !hasConversionRule) { + // When an argument is removed from a method signature and no other means of calling + // the method are provided (as with code injection) the generator must abort. + qFatal(qPrintable(QString::fromLatin1("No way to call '%1::%2' with the modifications described in the type system.") + .arg(func->ownerClass()->name(), func->signature())), NULL); + } + removedArgs++; + continue; + } + if (hasConversionRule) + continue; + const AbstractMetaType* argType = getArgumentType(func, argIdx + 1); + 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 defaultValue = guessScopeForDefaultValue(func, arg); + writeArgumentConversion(s, argType, argName, pyArgName, func->implementingClass(), defaultValue, func->isUserAdded()); + } + + s << endl; + + int numRemovedArgs = OverloadData::numberOfRemovedArguments(func); + + s << INDENT << "if (!PyErr_Occurred()) {" << endl; + { + Indentation indentation(INDENT); + writeMethodCall(s, func, context, func->arguments().size() - numRemovedArgs); + if (!func->isConstructor()) + writeNoneReturn(s, func, overloadData.hasNonVoidReturnType()); + } + s << INDENT << '}' << endl; +} + +QString CppGenerator::cppToPythonFunctionName(const QString& sourceTypeName, QString targetTypeName) +{ + if (targetTypeName.isEmpty()) + targetTypeName = sourceTypeName; + return QString::fromLatin1("%1_CppToPython_%2").arg(sourceTypeName, targetTypeName); +} + +QString CppGenerator::pythonToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName) +{ + return QString::fromLatin1("%1_PythonToCpp_%2").arg(sourceTypeName, targetTypeName); +} +QString CppGenerator::pythonToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType) +{ + return pythonToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType)); +} +QString CppGenerator::pythonToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative, + const TypeEntry* targetType) +{ + return pythonToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType)); +} + +QString CppGenerator::convertibleToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName) +{ + return QString::fromLatin1("is_%1_PythonToCpp_%2_Convertible").arg(sourceTypeName, targetTypeName); +} +QString CppGenerator::convertibleToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType) +{ + return convertibleToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType)); +} +QString CppGenerator::convertibleToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative, + const TypeEntry* targetType) +{ + return convertibleToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType)); +} + +void CppGenerator::writeCppToPythonFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, QString targetTypeName) +{ + QString prettyCode; + QTextStream c(&prettyCode); + formatCode(c, code, INDENT); + processCodeSnip(prettyCode); + + s << "static PyObject* " << cppToPythonFunctionName(sourceTypeName, targetTypeName); + s << "(const void* cppIn) {" << endl; + s << prettyCode; + s << '}' << endl; +} + +static void replaceCppToPythonVariables(QString& code, const QString& typeName) +{ + code.prepend(QString::fromLatin1("%1& cppInRef = *((%1*)cppIn);\n").arg(typeName)); + code.replace(QLatin1String("%INTYPE"), typeName); + code.replace(QLatin1String("%OUTTYPE"), QLatin1String("PyObject*")); + code.replace(QLatin1String("%in"), QLatin1String("cppInRef")); + code.replace(QLatin1String("%out"), QLatin1String("pyOut")); +} +void CppGenerator::writeCppToPythonFunction(QTextStream& s, const CustomConversion* customConversion) +{ + QString code = customConversion->nativeToTargetConversion(); + replaceCppToPythonVariables(code, getFullTypeName(customConversion->ownerType())); + writeCppToPythonFunction(s, code, fixedCppTypeName(customConversion->ownerType())); +} +void CppGenerator::writeCppToPythonFunction(QTextStream& s, const AbstractMetaType* containerType) +{ + const CustomConversion* customConversion = containerType->typeEntry()->customConversion(); + if (!customConversion) { + qFatal(qPrintable(QString::fromLatin1("Can't write the C++ to Python conversion function for container type '%1' - "\ + "no conversion rule was defined for it in the type system.") + .arg(containerType->typeEntry()->qualifiedCppName())), NULL); + } + if (!containerType->typeEntry()->isContainer()) { + writeCppToPythonFunction(s, customConversion); + return; + } + QString code = customConversion->nativeToTargetConversion(); + for (int i = 0; i < containerType->instantiations().count(); ++i) { + AbstractMetaType* type = containerType->instantiations().at(i); + QString typeName = getFullTypeName(type); + if (type->isConstant()) + typeName = QLatin1String("const ") + typeName; + code.replace(QString::fromLatin1("%INTYPE_%1").arg(i), typeName); + } + replaceCppToPythonVariables(code, getFullTypeNameWithoutModifiers(containerType)); + processCodeSnip(code); + writeCppToPythonFunction(s, code, fixedCppTypeName(containerType)); +} + +void CppGenerator::writePythonToCppFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, const QString& targetTypeName) +{ + QString prettyCode; + QTextStream c(&prettyCode); + formatCode(c, code, INDENT); + processCodeSnip(prettyCode); + s << "static void " << pythonToCppFunctionName(sourceTypeName, targetTypeName); + s << "(PyObject* pyIn, void* cppOut) {" << endl; + s << prettyCode; + s << '}' << endl; +} + +void CppGenerator::writeIsPythonConvertibleToCppFunction(QTextStream& s, + const QString& sourceTypeName, + const QString& targetTypeName, + const QString& condition, + QString pythonToCppFuncName, + bool acceptNoneAsCppNull) +{ + if (pythonToCppFuncName.isEmpty()) + pythonToCppFuncName = pythonToCppFunctionName(sourceTypeName, targetTypeName); + + s << "static PythonToCppFunc " << convertibleToCppFunctionName(sourceTypeName, targetTypeName); + s << "(PyObject* pyIn) {" << endl; + if (acceptNoneAsCppNull) { + s << INDENT << "if (pyIn == Py_None)" << endl; + Indentation indent(INDENT); + s << INDENT << "return Shiboken::Conversions::nonePythonToCppNullPtr;" << endl; + } + s << INDENT << "if (" << condition << ')' << endl; + { + Indentation indent(INDENT); + s << INDENT << "return " << pythonToCppFuncName << ';' << endl; + } + s << INDENT << "return 0;" << endl; + s << '}' << endl; +} + +void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, + const AbstractMetaType* sourceType, + const AbstractMetaType* targetType, + QString typeCheck, + QString conversion, + QString preConversion) +{ + QString sourcePyType = cpythonTypeNameExt(sourceType); + + // Python to C++ conversion function. + QString code; + QTextStream c(&code); + if (conversion.isEmpty()) + conversion = QLatin1Char('*') + cpythonWrapperCPtr(sourceType->typeEntry(), QLatin1String("pyIn")); + if (!preConversion.isEmpty()) + c << INDENT << preConversion << endl; + c << INDENT << QString::fromLatin1("*((%1*)cppOut) = %1(%2);") + .arg(getFullTypeName(targetType->typeEntry()), conversion); + QString sourceTypeName = fixedCppTypeName(sourceType); + QString targetTypeName = fixedCppTypeName(targetType); + writePythonToCppFunction(s, code, sourceTypeName, targetTypeName); + + // Python to C++ convertible check function. + if (typeCheck.isEmpty()) + typeCheck = QString::fromLatin1("PyObject_TypeCheck(pyIn, %1)").arg(sourcePyType); + writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck); + s << endl; +} + +void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, + const CustomConversion::TargetToNativeConversion* toNative, + const TypeEntry* targetType) +{ + // Python to C++ conversion function. + QString code = toNative->conversion(); + QString inType; + if (toNative->sourceType()) + inType = cpythonTypeNameExt(toNative->sourceType()); + else + inType = QString::fromLatin1("(&%1_Type)").arg(toNative->sourceTypeName()); + code.replace(QLatin1String("%INTYPE"), inType); + code.replace(QLatin1String("%OUTTYPE"), targetType->qualifiedCppName()); + code.replace(QLatin1String("%in"), QLatin1String("pyIn")); + code.replace(QLatin1String("%out"), QString::fromLatin1("*((%1*)cppOut)").arg(getFullTypeName(targetType))); + + QString sourceTypeName = fixedCppTypeName(toNative); + QString targetTypeName = fixedCppTypeName(targetType); + writePythonToCppFunction(s, code, sourceTypeName, targetTypeName); + + // Python to C++ convertible check function. + QString typeCheck = toNative->sourceTypeCheck(); + if (typeCheck.isEmpty()) { + QString pyTypeName = toNative->sourceTypeName(); + if (pyTypeName == QLatin1String("Py_None") || pyTypeName == QLatin1String("PyNone")) + typeCheck = QLatin1String("%in == Py_None"); + else if (pyTypeName == QLatin1String("SbkEnumType")) + typeCheck = QLatin1String("Shiboken::isShibokenEnum(%in)"); + else if (pyTypeName == QLatin1String("SbkObject")) + typeCheck = QLatin1String("Shiboken::Object::checkType(%in)"); + else if (pyTypeName == QLatin1String("PyTypeObject")) + typeCheck = QLatin1String("PyType_Check(%in)"); + else if (pyTypeName == QLatin1String("PyObject")) + typeCheck = QLatin1String("PyObject_TypeCheck(%in, &PyBaseObject_Type)"); + else if (pyTypeName.startsWith(QLatin1String("Py"))) + typeCheck = pyTypeName + QLatin1String("_Check(%in)"); + } + if (typeCheck.isEmpty()) { + if (!toNative->sourceType() || toNative->sourceType()->isPrimitive()) { + qFatal(qPrintable(QString::fromLatin1("User added implicit conversion for C++ type '%1' must provide either an input "\ + "type check function or a non primitive type entry.") + .arg(targetType->qualifiedCppName())), NULL); + + } + typeCheck = QString::fromLatin1("PyObject_TypeCheck(%in, %1)").arg(cpythonTypeNameExt(toNative->sourceType())); + } + typeCheck.replace(QLatin1String("%in"), QLatin1String("pyIn")); + processCodeSnip(typeCheck); + writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck); +} + +void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, const AbstractMetaType* containerType) +{ + const CustomConversion* customConversion = containerType->typeEntry()->customConversion(); + if (!customConversion) { + //qFatal + return; + } + const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions(); + if (toCppConversions.isEmpty()) { + //qFatal + return; + } + // Python to C++ conversion function. + QString cppTypeName = getFullTypeNameWithoutModifiers(containerType); + QString code; + QTextStream c(&code); + c << INDENT << QString::fromLatin1("%1& cppOutRef = *((%1*)cppOut);").arg(cppTypeName) << endl; + code.append(toCppConversions.first()->conversion()); + for (int i = 0; i < containerType->instantiations().count(); ++i) { + 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); + if (!match.hasMatch()) + break; + pos = match.capturedEnd(); + const QString varName = match.captured(1); + QString rightCode = code.mid(pos); + rightCode.replace(varName, QLatin1Char('*') + varName); + code.replace(pos, code.size() - pos, rightCode); + } + typeName.append(QLatin1Char('*')); + } + code.replace(QString::fromLatin1("%OUTTYPE_%1").arg(i), typeName); + } + code.replace(QLatin1String("%OUTTYPE"), cppTypeName); + code.replace(QLatin1String("%in"), QLatin1String("pyIn")); + code.replace(QLatin1String("%out"), QLatin1String("cppOutRef")); + QString typeName = fixedCppTypeName(containerType); + writePythonToCppFunction(s, code, typeName, typeName); + + // Python to C++ convertible check function. + QString typeCheck = cpythonCheckFunction(containerType); + if (typeCheck.isEmpty()) + typeCheck = QLatin1String("false"); + else + typeCheck = QString::fromLatin1("%1pyIn)").arg(typeCheck); + writeIsPythonConvertibleToCppFunction(s, typeName, typeName, typeCheck); + s << endl; +} + +void CppGenerator::writeAddPythonToCppConversion(QTextStream& s, const QString& converterVar, const QString& pythonToCppFunc, const QString& isConvertibleFunc) +{ + s << INDENT << "Shiboken::Conversions::addPythonToCppValueConversion(" << converterVar << ',' << endl; + { + Indentation indent(INDENT); + s << INDENT << pythonToCppFunc << ',' << endl; + s << INDENT << isConvertibleFunc; + } + s << ");" << endl; +} + +void CppGenerator::writeNamedArgumentResolution(QTextStream& s, const AbstractMetaFunction* func, bool usePyArgs) +{ + const AbstractMetaArgumentList &args = OverloadData::getArgumentsWithDefaultValues(func); + if (args.isEmpty()) + return; + + QString pyErrString(QLatin1String("PyErr_SetString(PyExc_TypeError, \"") + fullPythonFunctionName(func) + + QLatin1String("(): got multiple values for keyword argument '%1'.\");")); + + s << INDENT << "if (kwds) {" << endl; + { + Indentation indent(INDENT); + 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); + 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 << "} else if (value) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << pyArgName << " = value;" << endl; + s << INDENT << "if (!"; + writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()), func->typeReplaced(arg->argumentIndex() + 1)); + s << ')' << endl; + { + Indentation indent(INDENT); + s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;" << endl; + } + } + s << INDENT << '}' << endl; + if (arg != args.last()) + s << INDENT; + } + } + s << INDENT << '}' << endl; +} + +QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass) +{ + *wrappedClass = 0; + QString pyArgName; + if (argIndex == -1) { + pyArgName = QLatin1String(PYTHON_SELF_VAR); + *wrappedClass = func->implementingClass(); + } else if (argIndex == 0) { + AbstractMetaType *funcType = func->type(); + AbstractMetaType *returnType = getTypeWithoutContainer(funcType); + if (returnType) { + pyArgName = QLatin1String(PYTHON_RETURN_VAR); + *wrappedClass = AbstractMetaClass::findClass(classes(), returnType->typeEntry()->name()); + } else { + QString message = QLatin1String("Invalid Argument index (0, return value) on function modification: ") + + (funcType ? funcType->name() : QLatin1String("void")) + QLatin1Char(' '); + if (const AbstractMetaClass *declaringClass = func->declaringClass()) + message += declaringClass->name() + QLatin1String("::"); + message += func->name() + QLatin1String("()"); + qCWarning(lcShiboken).noquote().nospace() << message; + } + } else { + int realIndex = argIndex - 1 - OverloadData::numberOfRemovedArguments(func, argIndex - 1); + AbstractMetaType* argType = getTypeWithoutContainer(func->arguments().at(realIndex)->type()); + + if (argType) { + *wrappedClass = AbstractMetaClass::findClass(classes(), argType->typeEntry()->name()); + if (argIndex == 1 + && !func->isConstructor() + && OverloadData::isSingleArgument(getFunctionGroups(func->implementingClass())[func->name()])) + pyArgName = QLatin1String(PYTHON_ARG); + else + pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argIndex - 1); + } + } + return pyArgName; +} + +void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *func, + GeneratorContext &context, int maxArgs) +{ + s << INDENT << "// " << func->minimalSignature() << (func->isReverseOperator() ? " [reverse operator]": "") << endl; + if (func->isConstructor()) { + const CodeSnipList &snips = func->injectedCodeSnips(); + for (const CodeSnip &cs : snips) { + if (cs.position == TypeSystem::CodeSnipPositionEnd) { + s << INDENT << "overloadId = " << func->ownerClass()->functions().indexOf(const_cast(func)) << ';' << endl; + break; + } + } + } + + if (func->isAbstract()) { + s << INDENT << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast(" PYTHON_SELF_VAR "))) {\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 << "}\n"; + } + + // Used to provide contextual information to custom code writer function. + const AbstractMetaArgument* lastArg = 0; + + CodeSnipList snips; + if (func->hasInjectedCode()) { + snips = func->injectedCodeSnips(); + + // Find the last argument available in the method call to provide + // the injected code writer with information to avoid invalid replacements + // on the %# variable. + if (maxArgs > 0 && maxArgs < func->arguments().size() - OverloadData::numberOfRemovedArguments(func)) { + int removedArgs = 0; + for (int i = 0; i < maxArgs + removedArgs; i++) { + lastArg = func->arguments().at(i); + if (func->argumentRemoved(i + 1)) + removedArgs++; + } + } else if (maxArgs != 0 && !func->arguments().isEmpty()) { + lastArg = func->arguments().last(); + } + + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func, lastArg); + s << endl; + } + + writeConversionRule(s, func, TypeSystem::NativeCode); + + if (!func->isUserAdded()) { + QStringList userArgs; + if (func->functionType() != AbstractMetaFunction::CopyConstructorFunction) { + int removedArgs = 0; + for (int i = 0; i < maxArgs + removedArgs; i++) { + const AbstractMetaArgument* arg = func->arguments().at(i); + bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty(); + if (func->argumentRemoved(i + 1)) { + // If some argument with default value is removed from a + // method signature, the said value must be explicitly + // added to the method call. + removedArgs++; + + // If have conversion rules I will use this for removed args + if (hasConversionRule) + userArgs << arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX); + else if (!arg->defaultValueExpression().isEmpty()) + userArgs << QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(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 any argument's default value was modified the method must be called + // with this new value whenever the user doesn't pass an explicit value to it. + // Also, any unmodified default value coming after the last user specified + // argument and before the modified argument must be explicitly stated. + QStringList otherArgs; + bool otherArgsModified = false; + bool argsClear = true; + for (int i = func->arguments().size() - 1; i >= maxArgs + removedArgs; i--) { + const AbstractMetaArgument* arg = func->arguments().at(i); + bool defValModified = arg->defaultValueExpression() != arg->originalDefaultValueExpression(); + bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty(); + if (argsClear && !defValModified && !hasConversionRule) + continue; + else + 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)); + } + if (otherArgsModified) + userArgs << otherArgs; + } + + bool isCtor = false; + QString methodCall; + QTextStream mc(&methodCall); + 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 secondArg = QLatin1String(CPP_ARG0); + if (!func->isUnaryOperator() && shouldDereferenceArgumentPointer(func->arguments().first())) { + secondArg.prepend(QLatin1String("(*")); + secondArg.append(QLatin1Char(')')); + } + + if (func->isUnaryOperator()) + std::swap(firstArg, secondArg); + + QString op = func->originalName(); + op = op.right(op.size() - (sizeof("operator")/sizeof(char)-1)); + + if (func->isBinaryOperator()) { + if (func->isReverseOperator()) + std::swap(firstArg, secondArg); + + if (((op == QLatin1String("++")) || (op == QLatin1String("--"))) && !func->isReverseOperator()) { + s << endl << INDENT << "for(int i=0; i < " << secondArg << "; i++, " << firstArg << op << ");" << endl; + mc << firstArg; + } else { + mc << firstArg << ' ' << op << ' ' << secondArg; + } + } else { + mc << op << ' ' << secondArg; + } + } else if (!injectedCodeCallsCppFunction(func)) { + if (func->isConstructor()) { + isCtor = true; + QString className = wrapperName(func->ownerClass()); + + if (func->functionType() == AbstractMetaFunction::CopyConstructorFunction && maxArgs == 1) { + mc << "new ::" << className << "(*" << CPP_ARG0 << ')'; + } else { + QString ctorCall = className + QLatin1Char('(') + userArgs.join(QLatin1String(", ")) + QLatin1Char(')'); + if (usePySideExtensions() && func->ownerClass()->isQObject()) { + s << INDENT << "void* addr = PySide::nextQObjectMemoryAddr();" << endl; + uva << "if (addr) {" << endl; + { + Indentation indent(INDENT); + + uva << INDENT << "cptr = " << "new (addr) ::" + << ctorCall << ';' << endl + << INDENT + << "PySide::setNextQObjectMemoryAddr(0);" + << endl; + } + uva << INDENT << "} else {" << endl; + { + Indentation indent(INDENT); + + uva << INDENT << "cptr = " << "new ::" + << ctorCall << ';' << endl; + } + uva << INDENT << "}" << endl; + } else { + mc << "new ::" << ctorCall; + } + } + } else { + QString methodCallClassName; + if (context.forSmartPointer()) + methodCallClassName = context.preciseType()->cppSignature(); + else if (func->ownerClass()) + methodCallClassName = func->ownerClass()->qualifiedCppName(); + + if (func->ownerClass()) { + if (!avoidProtectedHack() || !func->isProtected()) { + if (func->isStatic()) { + mc << "::" << methodCallClassName << "::"; + } else { + const QString selfVarCast = func->ownerClass() == func->implementingClass() + ? QLatin1String(CPP_SELF_VAR) + : QLatin1String("reinterpret_cast<") + methodCallClassName + QLatin1String(" *>(" CPP_SELF_VAR ")"); + if (func->isConstant()) { + if (avoidProtectedHack()) { + mc << "const_castownerClass()->hasProtectedMembers()) { + // 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 ")"); + mc << wrapperName(func->ownerClass()); + mc << "*>(" << selfWrapCast << ")->"; + } + else { + mc << methodCallClassName; + mc << "*>(" << selfVarCast << ")->"; + } + } else { + mc << "const_cast(" << selfVarCast << ")->"; + } + } else { + mc << selfVarCast << "->"; + } + } + + if (!func->isAbstract() && func->isVirtual()) + mc << "::%CLASS_NAME::"; + + mc << func->originalName(); + } else { + if (!func->isStatic()) + mc << "((::" << wrapperName(func->ownerClass()) << "*) " << CPP_SELF_VAR << ")->"; + + if (!func->isAbstract()) + mc << (func->isProtected() ? wrapperName(func->ownerClass()) : + QLatin1String("::") + + methodCallClassName) << "::"; + mc << func->originalName() << "_protected"; + } + } else { + mc << func->originalName(); + } + mc << '(' << userArgs.join(QLatin1String(", ")) << ')'; + if (!func->isAbstract() && func->isVirtual()) { + mc.flush(); + if (!avoidProtectedHack() || !func->isProtected()) { + QString virtualCall(methodCall); + QString normalCall(methodCall); + virtualCall = virtualCall.replace(QLatin1String("%CLASS_NAME"), + methodCallClassName); + normalCall.remove(QLatin1String("::%CLASS_NAME::")); + methodCall.clear(); + mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast(" PYTHON_SELF_VAR ")) ? "; + mc << virtualCall << " : " << normalCall; + } + } + } + } + + if (!injectedCodeCallsCppFunction(func)) { + s << INDENT << BEGIN_ALLOW_THREADS << endl << INDENT; + if (isCtor) { + s << (useVAddr.isEmpty() ? + QString::fromLatin1("cptr = %1;").arg(methodCall) : useVAddr) << endl; + } else if (func->type() && !func->isInplaceOperator()) { + bool writeReturnType = true; + if (avoidProtectedHack()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type()); + if (metaEnum) { + QString enumName; + if (metaEnum->isProtected()) + enumName = protectedEnumSurrogateName(metaEnum); + else + enumName = func->type()->cppSignature(); + methodCall.prepend(enumName + QLatin1Char('(')); + methodCall.append(QLatin1Char(')')); + s << enumName; + writeReturnType = false; + } + } + if (writeReturnType) { + s << func->type()->cppSignature(); + if (isObjectTypeUsedAsValueType(func->type())) { + s << '*'; + methodCall.prepend(QString::fromLatin1("new %1(").arg(func->type()->typeEntry()->qualifiedCppName())); + methodCall.append(QLatin1Char(')')); + } + } + s << " " CPP_RETURN_VAR " = "; + s << methodCall << ';' << endl; + } else { + s << methodCall << ';' << endl; + } + s << INDENT << END_ALLOW_THREADS << endl; + + 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 " = "; + if (isObjectTypeUsedAsValueType(func->type())) { + s << "Shiboken::Object::newObject(reinterpret_cast(" << cpythonTypeNameExt(func->type()->typeEntry()) + << "), " << CPP_RETURN_VAR << ", true, true)"; + } else { + writeToPythonConversion(s, func->type(), func->ownerClass(), QLatin1String(CPP_RETURN_VAR)); + } + s << ';' << endl; + } + } + } + + if (func->hasInjectedCode() && !func->isConstructor()) { + s << endl; + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func, lastArg); + } + + bool hasReturnPolicy = false; + + // Ownership transference between C++ and Python. + QVector ownership_mods; + // Python object reference management. + QVector refcount_mods; + const FunctionModificationList &funcMods = func->modifications(); + for (const FunctionModification &func_mod : funcMods) { + for (const ArgumentModification &arg_mod : func_mod.argument_mods) { + if (!arg_mod.ownerships.isEmpty() && arg_mod.ownerships.contains(TypeSystem::TargetLangCode)) + ownership_mods.append(arg_mod); + else if (!arg_mod.referenceCounts.isEmpty()) + refcount_mods.append(arg_mod); + } + } + + // If there's already a setParent(return, me), don't use the return heuristic! + if (func->argumentOwner(func->ownerClass(), -1).index == 0) + hasReturnPolicy = true; + + if (!ownership_mods.isEmpty()) { + s << endl << INDENT << "// Ownership transferences." << endl; + for (const ArgumentModification &arg_mod : qAsConst(ownership_mods)) { + const AbstractMetaClass* wrappedClass = 0; + QString pyArgName = argumentNameFromIndex(func, arg_mod.index, &wrappedClass); + if (!wrappedClass) { + s << "#error Invalid ownership modification for argument " << arg_mod.index << '(' << pyArgName << ')' << endl << endl; + break; + } + + if (arg_mod.index == 0 || arg_mod.owner.index == 0) + hasReturnPolicy = true; + + // The default ownership does nothing. This is useful to avoid automatic heuristically + // based generation of code defining parenting. + if (arg_mod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::DefaultOwnership) + continue; + + s << INDENT << "Shiboken::Object::"; + if (arg_mod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::TargetLangOwnership) { + s << "getOwnership(" << pyArgName << ");"; + } else if (wrappedClass->hasVirtualDestructor()) { + if (arg_mod.index == 0) + s << "releaseOwnership(" PYTHON_RETURN_VAR ");"; + else + s << "releaseOwnership(" << pyArgName << ");"; + } else { + s << "invalidate(" << pyArgName << ");"; + } + s << endl; + } + + } else if (!refcount_mods.isEmpty()) { + for (const ArgumentModification &arg_mod : qAsConst(refcount_mods)) { + ReferenceCount refCount = arg_mod.referenceCounts.first(); + if (refCount.action != ReferenceCount::Set + && refCount.action != ReferenceCount::Remove + && refCount.action != ReferenceCount::Add) { + qCWarning(lcShiboken) << "\"set\", \"add\" and \"remove\" are the only values supported by Shiboken for action attribute of reference-count tag."; + continue; + } + const AbstractMetaClass* wrappedClass = 0; + + QString pyArgName; + if (refCount.action == ReferenceCount::Remove) { + pyArgName = QLatin1String("Py_None"); + } else { + pyArgName = argumentNameFromIndex(func, arg_mod.index, &wrappedClass); + if (pyArgName.isEmpty()) { + s << "#error Invalid reference count modification for argument " << arg_mod.index << endl << endl; + break; + } + } + + if (refCount.action == ReferenceCount::Add || refCount.action == ReferenceCount::Set) + s << INDENT << "Shiboken::Object::keepReference("; + else + s << INDENT << "Shiboken::Object::removeReference("; + + s << "reinterpret_cast(" PYTHON_SELF_VAR "), \""; + QString varName = arg_mod.referenceCounts.first().varName; + if (varName.isEmpty()) + varName = func->minimalSignature() + QString().number(arg_mod.index); + + s << varName << "\", " << pyArgName + << (refCount.action == ReferenceCount::Add ? ", true" : "") + << ");" << endl; + + if (arg_mod.index == 0) + hasReturnPolicy = true; + } + } + writeParentChildManagement(s, func, !hasReturnPolicy); +} + +QStringList CppGenerator::getAncestorMultipleInheritance(const AbstractMetaClass* metaClass) +{ + QStringList result; + const AbstractMetaClassList &baseClases = getBaseClasses(metaClass); + if (!baseClases.isEmpty()) { + for (const AbstractMetaClass *baseClass : baseClases) { + result.append(QString::fromLatin1("((size_t) static_cast(class_ptr)) - base") + .arg(baseClass->qualifiedCppName())); + result.append(QString::fromLatin1("((size_t) static_cast((%2*)((void*)class_ptr))) - base") + .arg(baseClass->qualifiedCppName(), metaClass->qualifiedCppName())); + } + for (const AbstractMetaClass *baseClass : baseClases) + result.append(getAncestorMultipleInheritance(baseClass)); + } + return result; +} + +void CppGenerator::writeMultipleInheritanceInitializerFunction(QTextStream& s, const AbstractMetaClass* metaClass) +{ + QString className = metaClass->qualifiedCppName(); + const QStringList ancestors = getAncestorMultipleInheritance(metaClass); + s << "static int mi_offsets[] = { "; + for (int i = 0; i < ancestors.size(); i++) + s << "-1, "; + s << "-1 };" << endl; + s << "int*" << endl; + s << multipleInheritanceInitializerFunctionName(metaClass) << "(const void* cptr)" << endl; + s << '{' << endl; + s << INDENT << "if (mi_offsets[0] == -1) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "std::set offsets;" << endl; + s << INDENT << "std::set::iterator it;" << endl; + s << INDENT << "const " << className << "* class_ptr = reinterpret_cast(cptr);" << endl; + s << INDENT << "size_t base = (size_t) class_ptr;" << endl; + + for (const QString &ancestor : ancestors) + s << INDENT << "offsets.insert(" << ancestor << ");" << endl; + + s << endl; + s << INDENT << "offsets.erase(0);" << endl; + s << endl; + + s << INDENT << "int i = 0;" << endl; + s << INDENT << "for (it = offsets.begin(); it != offsets.end(); it++) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "mi_offsets[i] = *it;" << endl; + s << INDENT << "i++;" << endl; + } + s << INDENT << '}' << endl; + } + s << INDENT << '}' << endl; + s << INDENT << "return mi_offsets;" << endl; + s << '}' << endl; +} + +void CppGenerator::writeSpecialCastFunction(QTextStream& s, const AbstractMetaClass* metaClass) +{ + QString className = metaClass->qualifiedCppName(); + s << "static void* " << cpythonSpecialCastFunctionName(metaClass) << "(void* obj, SbkObjectType* desiredType)\n"; + s << "{\n"; + s << INDENT << className << "* me = reinterpret_cast< ::" << className << "*>(obj);\n"; + bool firstClass = true; + const AbstractMetaClassList &allAncestors = getAllAncestors(metaClass); + for (const AbstractMetaClass *baseClass : allAncestors) { + s << INDENT << (!firstClass ? "else " : "") << "if (desiredType == reinterpret_cast(" << cpythonTypeNameExt(baseClass->typeEntry()) << "))\n"; + Indentation indent(INDENT); + s << INDENT << "return static_cast< ::" << baseClass->qualifiedCppName() << "*>(me);\n"; + firstClass = false; + } + s << INDENT << "return me;\n"; + s << "}\n\n"; +} + +void CppGenerator::writePrimitiveConverterInitialization(QTextStream& s, const CustomConversion* customConversion) +{ + const TypeEntry* type = customConversion->ownerType(); + QString converter = converterObject(type); + s << INDENT << "// Register converter for type '" << type->qualifiedTargetLangName() << "'." << endl; + s << INDENT << converter << " = Shiboken::Conversions::createConverter("; + if (type->targetLangApiName() == type->name()) + s << '0'; + else if (type->targetLangApiName() == QLatin1String("PyObject")) + s << "&PyBaseObject_Type"; + else + s << '&' << type->targetLangApiName() << "_Type"; + QString typeName = fixedCppTypeName(type); + s << ", " << cppToPythonFunctionName(typeName, typeName) << ");" << endl; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << type->qualifiedCppName() << "\");" << endl; + writeCustomConverterRegister(s, customConversion, converter); +} + +void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum) +{ + if (metaEnum->isPrivate() || metaEnum->isAnonymous()) + return; + writeEnumConverterInitialization(s, metaEnum->typeEntry()); +} + +void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEntry* enumType) +{ + if (!enumType) + return; + QString enumFlagName = enumType->isFlags() ? QLatin1String("flag") : QLatin1String("enum"); + QString enumPythonType = cpythonTypeNameExt(enumType); + + const FlagsTypeEntry* flags = 0; + if (enumType->isFlags()) + flags = reinterpret_cast(enumType); + + s << INDENT << "// Register converter for " << enumFlagName << " '" << enumType->qualifiedCppName() << "'." << endl; + s << INDENT << '{' << endl; + { + Indentation indent(INDENT); + QString typeName = fixedCppTypeName(enumType); + s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(" << enumPythonType << ',' << endl; + { + Indentation indent(INDENT); + s << INDENT << cppToPythonFunctionName(typeName, typeName) << ");" << endl; + } + + if (flags) { + QString enumTypeName = fixedCppTypeName(flags->originator()); + QString toCpp = pythonToCppFunctionName(enumTypeName, typeName); + QString isConv = convertibleToCppFunctionName(enumTypeName, typeName); + writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv); + } + + QString toCpp = pythonToCppFunctionName(typeName, typeName); + QString isConv = convertibleToCppFunctionName(typeName, typeName); + writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv); + + if (flags) { + QString toCpp = pythonToCppFunctionName(QLatin1String("number"), typeName); + QString isConv = convertibleToCppFunctionName(QLatin1String("number"), typeName); + writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv); + } + + s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl; + s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl; + QStringList cppSignature = enumType->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts); + while (!cppSignature.isEmpty()) { + QString signature = cppSignature.join(QLatin1String("::")); + s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \""; + if (flags) + s << "QFlags<"; + s << signature << "\");" << endl; + cppSignature.removeFirst(); + } + } + s << INDENT << '}' << endl; + + if (!flags) + writeEnumConverterInitialization(s, reinterpret_cast(enumType)->flags()); +} + +void CppGenerator::writeContainerConverterInitialization(QTextStream& s, const AbstractMetaType* type) +{ + QByteArray cppSignature = QMetaObject::normalizedSignature(type->cppSignature().toUtf8()); + s << INDENT << "// Register converter for type '" << cppSignature << "'." << endl; + QString converter = converterObject(type); + s << INDENT << converter << " = Shiboken::Conversions::createConverter("; + if (type->typeEntry()->targetLangApiName() == QLatin1String("PyObject")) { + s << "&PyBaseObject_Type"; + } else { + QString baseName = cpythonBaseName(type->typeEntry()); + if (baseName == QLatin1String("PySequence")) + baseName = QLatin1String("PyList"); + s << '&' << baseName << "_Type"; + } + QString typeName = fixedCppTypeName(type); + s << ", " << cppToPythonFunctionName(typeName, typeName) << ");" << endl; + QString toCpp = pythonToCppFunctionName(typeName, typeName); + QString isConv = convertibleToCppFunctionName(typeName, typeName); + s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << cppSignature << "\");" << endl; + if (usePySideExtensions() && cppSignature.startsWith("const ") && cppSignature.endsWith("&")) { + cppSignature.chop(1); + cppSignature.remove(0, sizeof("const ") / sizeof(char) - 1); + s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << cppSignature << "\");" << endl; + } + writeAddPythonToCppConversion(s, converterObject(type), toCpp, isConv); +} + +void CppGenerator::writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType, + const QVector& conversions) +{ + s << INDENT << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << endl; + for (const AbstractMetaClass *sourceClass : conversions) { + const QString converterVar = QLatin1String("reinterpret_cast(") + + cppApiVariableName(externalType->targetLangPackage()) + QLatin1Char('[') + + getTypeIndexVariableName(externalType) + QLatin1String("])"); + QString sourceTypeName = fixedCppTypeName(sourceClass->typeEntry()); + QString targetTypeName = fixedCppTypeName(externalType); + QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName); + QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName); + writeAddPythonToCppConversion(s, converterVar, toCpp, isConv); + } +} + +QString CppGenerator::multipleInheritanceInitializerFunctionName(const AbstractMetaClass* metaClass) +{ + if (!hasMultipleInheritanceInAncestry(metaClass)) + return QString(); + return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("_mi_init"); +} + +typedef QHash >::const_iterator ProtocolIt; + +bool CppGenerator::supportsMappingProtocol(const AbstractMetaClass* metaClass) +{ + for (ProtocolIt it = m_mappingProtocol.cbegin(), end = m_mappingProtocol.cend(); it != end; ++it) { + if (metaClass->hasFunction(it.key())) + return true; + } + + return false; +} + +bool CppGenerator::supportsNumberProtocol(const AbstractMetaClass* metaClass) +{ + return metaClass->hasArithmeticOperatorOverload() + || metaClass->hasLogicalOperatorOverload() + || metaClass->hasBitwiseOperatorOverload() + || hasBoolCast(metaClass); +} + +bool CppGenerator::supportsSequenceProtocol(const AbstractMetaClass* metaClass) +{ + for (ProtocolIt it = m_sequenceProtocol.cbegin(), end = m_sequenceProtocol.cend(); it != end; ++it) { + if (metaClass->hasFunction(it.key())) + return true; + } + + const ComplexTypeEntry* baseType = metaClass->typeEntry()->baseContainerType(); + if (baseType && baseType->isContainer()) + return true; + + return false; +} + +bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass* metaClass) +{ + const AbstractMetaFieldList &fields = metaClass->fields(); + for (const AbstractMetaField *f : fields) { + if (!f->isStatic()) + return true; + } + return false; +} + +void CppGenerator::writeClassDefinition(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &classContext) +{ + QString tp_flags; + QString tp_init; + QString tp_new; + QString tp_dealloc; + QString tp_hash(QLatin1Char('0')); + QString tp_call = tp_hash; + QString cppClassName = metaClass->qualifiedCppName(); + const QString className = chopType(cpythonTypeName(metaClass)); + QString baseClassName(QLatin1Char('0')); + AbstractMetaFunctionList ctors; + const AbstractMetaFunctionList &allCtors = metaClass->queryFunctions(AbstractMetaClass::Constructors); + for (AbstractMetaFunction *f : allCtors) { + if (!f->isPrivate() && !f->isModifiedRemoved() && !classContext.forSmartPointer()) + ctors.append(f); + } + + if (!metaClass->baseClass()) + baseClassName = QLatin1String("reinterpret_cast(&SbkObject_Type)"); + + bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor(); + + if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) { + tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC"); + tp_dealloc = metaClass->hasPrivateDestructor() ? + QLatin1String("SbkDeallocWrapperWithPrivateDtor") : QLatin1String("0"); + tp_init = QLatin1String("0"); + } else { + if (onlyPrivCtor) + tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC"); + else + tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC"); + + QString deallocClassName; + if (shouldGenerateCppWrapper(metaClass)) + deallocClassName = wrapperName(metaClass); + else + deallocClassName = cppClassName; + tp_dealloc = QLatin1String("&SbkDeallocWrapper"); + // avoid constFirst to stay Qt 5.5 compatible + tp_init = (onlyPrivCtor || ctors.isEmpty()) ? QLatin1String("0") : cpythonFunctionName(ctors.first()); + } + + QString tp_getattro(QLatin1Char('0')); + QString tp_setattro = tp_getattro; + if (usePySideExtensions() && (metaClass->qualifiedCppName() == QLatin1String("QObject"))) { + tp_getattro = cpythonGetattroFunctionName(metaClass); + tp_setattro = cpythonSetattroFunctionName(metaClass); + } else { + if (classNeedsGetattroFunction(metaClass)) + tp_getattro = cpythonGetattroFunctionName(metaClass); + if (classNeedsSetattroFunction(metaClass)) + tp_setattro = cpythonSetattroFunctionName(metaClass); + } + + if (metaClass->hasPrivateDestructor() || onlyPrivCtor) + tp_new = QLatin1String("0"); + else + tp_new = QLatin1String("SbkObjectTpNew"); + + QString tp_richcompare = QString(QLatin1Char('0')); + if (metaClass->hasComparisonOperatorOverload()) + tp_richcompare = cpythonBaseName(metaClass) + QLatin1String("_richcompare"); + + QString tp_getset = QString(QLatin1Char('0')); + if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer()) + tp_getset = cpythonGettersSettersDefinitionName(metaClass); + + // search for special functions + ShibokenGenerator::clearTpFuncs(); + const AbstractMetaFunctionList &funcs = metaClass->functions(); + for (AbstractMetaFunction *func : funcs) { + if (m_tpFuncs.contains(func->name())) + m_tpFuncs[func->name()] = cpythonFunctionName(func); + } + if (m_tpFuncs[QLatin1String("__repr__")] == QLatin1String("0") + && !metaClass->isQObject() + && metaClass->hasToStringCapability()) { + m_tpFuncs[QLatin1String("__repr__")] = writeReprFunction(s, classContext); + } + + // class or some ancestor has multiple inheritance + const AbstractMetaClass* miClass = getMultipleInheritingClass(metaClass); + if (miClass) { + if (metaClass == miClass) + writeMultipleInheritanceInitializerFunction(s, metaClass); + writeSpecialCastFunction(s, metaClass); + s << endl; + } + + if (!metaClass->typeEntry()->hashFunction().isEmpty()) + tp_hash = QLatin1Char('&') + cpythonBaseName(metaClass) + QLatin1String("_HashFunc"); + + const AbstractMetaFunction* callOp = metaClass->findFunction(QLatin1String("operator()")); + if (callOp && !callOp->isModifiedRemoved()) + tp_call = QLatin1Char('&') + cpythonFunctionName(callOp); + + s << "// Class Definition -----------------------------------------------" << endl; + s << "extern \"C\" {" << endl; + + if (supportsNumberProtocol(metaClass)) { + s << "static PyNumberMethods " << className + QLatin1String("_TypeAsNumber") << ";" << endl; + s << endl; + } + + if (supportsSequenceProtocol(metaClass)) { + s << "static PySequenceMethods " << className + QLatin1String("_TypeAsSequence") << ";" << endl; + s << endl; + } + + if (supportsMappingProtocol(metaClass)) { + s << "static PyMappingMethods " << className + QLatin1String("_TypeAsMapping") << ";" << endl; + s << endl; + } + + s << "static SbkObjectType " << className + QLatin1String("_Type") << " = { { {" << endl; + s << INDENT << "PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0)" << endl; + QString computedClassTargetFullName; + if (!classContext.forSmartPointer()) + computedClassTargetFullName = getClassTargetFullName(metaClass); + else + computedClassTargetFullName = getClassTargetFullName(classContext.preciseType()); + + s << INDENT << "/*tp_name*/ \"" << computedClassTargetFullName << "\"," << endl; + s << INDENT << "/*tp_basicsize*/ sizeof(SbkObject)," << endl; + s << INDENT << "/*tp_itemsize*/ 0," << endl; + s << INDENT << "/*tp_dealloc*/ " << tp_dealloc << ',' << endl; + s << INDENT << "/*tp_print*/ 0," << endl; + s << INDENT << "/*tp_getattr*/ 0," << endl; + s << INDENT << "/*tp_setattr*/ 0," << endl; + s << INDENT << "/*tp_compare*/ 0," << endl; + s << INDENT << "/*tp_repr*/ " << m_tpFuncs[QLatin1String("__repr__")] << "," << endl; + s << INDENT << "/*tp_as_number*/ 0," << endl; + s << INDENT << "/*tp_as_sequence*/ 0," << endl; + s << INDENT << "/*tp_as_mapping*/ 0," << endl; + s << INDENT << "/*tp_hash*/ " << tp_hash << ',' << endl; + s << INDENT << "/*tp_call*/ " << tp_call << ',' << endl; + s << INDENT << "/*tp_str*/ " << m_tpFuncs[QLatin1String("__str__")] << ',' << endl; + s << INDENT << "/*tp_getattro*/ " << tp_getattro << ',' << endl; + s << INDENT << "/*tp_setattro*/ " << tp_setattro << ',' << endl; + s << INDENT << "/*tp_as_buffer*/ 0," << endl; + s << INDENT << "/*tp_flags*/ " << tp_flags << ',' << endl; + s << INDENT << "/*tp_doc*/ 0," << endl; + s << INDENT << "/*tp_traverse*/ " << className << "_traverse," << endl; + s << INDENT << "/*tp_clear*/ " << className << "_clear," << endl; + s << INDENT << "/*tp_richcompare*/ " << tp_richcompare << ',' << endl; + s << INDENT << "/*tp_weaklistoffset*/ 0," << endl; + s << INDENT << "/*tp_iter*/ " << m_tpFuncs[QLatin1String("__iter__")] << ',' << endl; + s << INDENT << "/*tp_iternext*/ " << m_tpFuncs[QLatin1String("__next__")] << ',' << endl; + s << INDENT << "/*tp_methods*/ " << className << "_methods," << endl; + s << INDENT << "/*tp_members*/ 0," << endl; + s << INDENT << "/*tp_getset*/ " << tp_getset << ',' << endl; + s << INDENT << "/*tp_base*/ " << baseClassName << ',' << endl; + s << INDENT << "/*tp_dict*/ 0," << endl; + s << INDENT << "/*tp_descr_get*/ 0," << endl; + s << INDENT << "/*tp_descr_set*/ 0," << endl; + s << INDENT << "/*tp_dictoffset*/ 0," << endl; + s << INDENT << "/*tp_init*/ " << tp_init << ',' << endl; + s << INDENT << "/*tp_alloc*/ 0," << endl; + s << INDENT << "/*tp_new*/ " << tp_new << ',' << endl; + s << INDENT << "/*tp_free*/ 0," << endl; + s << INDENT << "/*tp_is_gc*/ 0," << endl; + s << INDENT << "/*tp_bases*/ 0," << endl; + s << INDENT << "/*tp_mro*/ 0," << endl; + s << INDENT << "/*tp_cache*/ 0," << endl; + s << INDENT << "/*tp_subclasses*/ 0," << endl; + s << INDENT << "/*tp_weaklist*/ 0" << endl; + s << "}, }," << endl; + s << INDENT << "/*priv_data*/ 0" << endl; + s << "};" << endl; + QString suffix; + if (isObjectType(metaClass)) + suffix = QLatin1String("*"); + s << "} //extern" << endl; +} + +void CppGenerator::writeMappingMethods(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &context) +{ + + QMap funcs; + + QHash< QString, QPair< QString, QString > >::const_iterator it = m_mappingProtocol.begin(); + for (; it != m_mappingProtocol.end(); ++it) { + const AbstractMetaFunction* func = metaClass->findFunction(it.key()); + if (!func) + continue; + QString funcName = cpythonFunctionName(func); + QString funcArgs = it.value().first; + QString funcRetVal = it.value().second; + + CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode); + s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl; + writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR)); + + writeCppSelfDefinition(s, func, context); + + const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg); + s << '}' << endl << endl; + } +} + +void CppGenerator::writeSequenceMethods(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &context) +{ + + QMap funcs; + bool injectedCode = false; + + QHash< QString, QPair< QString, QString > >::const_iterator it = m_sequenceProtocol.begin(); + for (; it != m_sequenceProtocol.end(); ++it) { + const AbstractMetaFunction* func = metaClass->findFunction(it.key()); + if (!func) + continue; + injectedCode = true; + QString funcName = cpythonFunctionName(func); + QString funcArgs = it.value().first; + QString funcRetVal = it.value().second; + + CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode); + s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl; + writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR)); + + writeCppSelfDefinition(s, func, context); + + const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); + writeCodeSnips(s, snips,TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg); + s << '}' << endl << endl; + } + + if (!injectedCode) + writeStdListWrapperMethods(s, context); +} + +void CppGenerator::writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass) +{ + bool hasFunctions = false; + QMap funcs; + for (ProtocolIt it = m_sequenceProtocol.cbegin(), end = m_sequenceProtocol.cend(); it != end; ++it) { + const QString &funcName = it.key(); + const AbstractMetaFunction* func = metaClass->findFunction(funcName); + funcs[funcName] = func ? cpythonFunctionName(func).prepend(QLatin1Char('&')) : QString(); + if (!hasFunctions && func) + hasFunctions = true; + } + + QString baseName = cpythonBaseName(metaClass); + + //use default implementation + if (!hasFunctions) { + funcs[QLatin1String("__len__")] = baseName + QLatin1String("__len__"); + funcs[QLatin1String("__getitem__")] = baseName + QLatin1String("__getitem__"); + funcs[QLatin1String("__setitem__")] = baseName + QLatin1String("__setitem__"); + } + + s << INDENT << "memset(&" << baseName << "_TypeAsSequence, 0, sizeof(PySequenceMethods));" << endl; + for (QHash::const_iterator it = m_sqFuncs.cbegin(), end = m_sqFuncs.cend(); it != end; ++it) { + const QString& sqName = it.key(); + if (funcs[sqName].isEmpty()) + continue; + if (it.value() == QLatin1String("sq_slice")) + s << "#ifndef IS_PY3K" << endl; + s << INDENT << baseName << "_TypeAsSequence." << it.value() << " = " << funcs[sqName] << ';' << endl; + if (it.value() == QLatin1String("sq_slice")) + s << "#endif" << endl; + } +} + +void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMetaClass* metaClass) +{ + bool hasFunctions = false; + QMap funcs; + for (ProtocolIt it = m_mappingProtocol.cbegin(), end = m_mappingProtocol.cend(); it != end; ++it) { + const QString &funcName = it.key(); + const AbstractMetaFunction* func = metaClass->findFunction(funcName); + funcs[funcName] = func ? cpythonFunctionName(func).prepend(QLatin1Char('&')) : QLatin1String("0"); + if (!hasFunctions && func) + hasFunctions = true; + } + + //use default implementation + if (!hasFunctions) { + funcs.insert(QLatin1String("__mlen__"), QString()); + funcs.insert(QLatin1String("__mgetitem__"), QString()); + funcs.insert(QLatin1String("__msetitem__"), QString()); + } + + QString baseName = cpythonBaseName(metaClass); + s << INDENT << "memset(&" << baseName << "_TypeAsMapping, 0, sizeof(PyMappingMethods));" << endl; + for (QHash::const_iterator it = m_mpFuncs.cbegin(), end = m_mpFuncs.end(); it != end; ++it) { + const QString &mpName = it.key(); + if (funcs[mpName].isEmpty()) + continue; + s << INDENT << baseName << "_TypeAsMapping." << it.value() << " = " << funcs[mpName] << ';' << endl; + } +} + +void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass) +{ + QMap nb; + + nb.insert(QLatin1String("__add__"), QString()); + nb.insert(QLatin1String("__sub__"), QString()); + nb.insert(QLatin1String("__mul__"), QString()); + nb.insert(QLatin1String("__div__"), QString()); + nb.insert(QLatin1String("__mod__"), QString()); + nb.insert(QLatin1String("__neg__"), QString()); + nb.insert(QLatin1String("__pos__"), QString()); + nb.insert(QLatin1String("__invert__"), QString()); + nb.insert(QLatin1String("__lshift__"), QString()); + nb.insert(QLatin1String("__rshift__"), QString()); + nb.insert(QLatin1String("__and__"), QString()); + nb.insert(QLatin1String("__xor__"), QString()); + nb.insert(QLatin1String("__or__"), QString()); + nb.insert(QLatin1String("__iadd__"), QString()); + nb.insert(QLatin1String("__isub__"), QString()); + nb.insert(QLatin1String("__imul__"), QString()); + nb.insert(QLatin1String("__idiv__"), QString()); + nb.insert(QLatin1String("__imod__"), QString()); + nb.insert(QLatin1String("__ilshift__"), QString()); + nb.insert(QLatin1String("__irshift__"), QString()); + nb.insert(QLatin1String("__iand__"), QString()); + nb.insert(QLatin1String("__ixor__"), QString()); + nb.insert(QLatin1String("__ior__"), QString()); + + const QVector opOverloads = + filterGroupedOperatorFunctions(metaClass, + AbstractMetaClass::ArithmeticOp + | AbstractMetaClass::LogicalOp + | AbstractMetaClass::BitwiseOp); + + for (const AbstractMetaFunctionList &opOverload : opOverloads) { + const AbstractMetaFunction* rfunc = opOverload[0]; + QString opName = ShibokenGenerator::pythonOperatorFunctionName(rfunc); + nb[opName] = cpythonFunctionName(rfunc); + } + + QString baseName = cpythonBaseName(metaClass); + + nb[QLatin1String("bool")] = hasBoolCast(metaClass) ? baseName + QLatin1String("___nb_bool") : QString(); + + s << INDENT << "memset(&" << baseName << "_TypeAsNumber, 0, sizeof(PyNumberMethods));" << endl; + for (QHash::const_iterator it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) { + const QString &nbName = it.key(); + if (nb[nbName].isEmpty()) + continue; + + // bool is special because the field name differs on Python 2 and 3 (nb_nonzero vs nb_bool) + // so a shiboken macro is used. + if (nbName == QLatin1String("bool")) { + s << INDENT << "SBK_NB_BOOL(" << baseName << "_TypeAsNumber) = " << nb[nbName] << ';' << endl; + } else { + bool excludeFromPy3K = nbName == QLatin1String("__div__") || nbName == QLatin1String("__idiv__"); + if (excludeFromPy3K) { + s << "#ifdef IS_PY3K" << endl; + s << INDENT << "SBK_UNUSED(&" << nb[nbName] << ");" << endl; + s << "#else" << endl; + } + s << INDENT << baseName << "_TypeAsNumber." << it.value() << " = " << nb[nbName] << ';' << endl; + if (excludeFromPy3K) + s << "#endif" << endl; + } + } + if (!nb[QLatin1String("__div__")].isEmpty()) + s << INDENT << baseName << "_TypeAsNumber.nb_true_divide = " << nb[QLatin1String("__div__")] << ';' << endl; +} + +void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass) +{ + QString baseName = cpythonBaseName(metaClass); + s << "static int "; + s << baseName << "_traverse(PyObject* " PYTHON_SELF_VAR ", visitproc visit, void* arg)" << endl; + s << '{' << endl; + s << INDENT << "return reinterpret_cast(&SbkObject_Type)->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl; + s << '}' << endl; +} + +void CppGenerator::writeTpClearFunction(QTextStream& s, const AbstractMetaClass* metaClass) +{ + QString baseName = cpythonBaseName(metaClass); + s << "static int "; + s << baseName << "_clear(PyObject* " PYTHON_SELF_VAR ")" << endl; + s << '{' << endl; + s << INDENT << "return reinterpret_cast(&SbkObject_Type)->tp_clear(" PYTHON_SELF_VAR ");" << endl; + s << '}' << endl; +} + +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 << "{" << endl; + writeCppSelfDefinition(s, context, false, true); + QString conversionCode; + if (!context.forSmartPointer()) + conversionCode = cpythonToPythonConversionFunction(metaClass); + else + conversionCode = cpythonToPythonConversionFunction(context.preciseType()); + + s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = " << conversionCode; + s << CPP_SELF_VAR ");" << endl; + writeFunctionReturnErrorCheckSection(s); + s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl; + s << "}" << endl; + s << endl; +} + +void CppGenerator::writeGetterFunction(QTextStream &s, + const AbstractMetaField *metaField, + GeneratorContext &context) +{ + ErrorCode errorCode(0); + s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", void*)" << endl; + s << '{' << endl; + + writeCppSelfDefinition(s, context); + + AbstractMetaType* fieldType = metaField->type(); + // Force use of pointer to return internal variable memory + bool newWrapperSameObject = !fieldType->isConstant() && isWrapperType(fieldType) && !isPointer(fieldType); + + QString cppField; + if (avoidProtectedHack() && metaField->isProtected()) { + cppField = QString::fromLatin1("((%1*)%2)->%3()") + .arg(wrapperName(metaField->enclosingClass()), QLatin1String(CPP_SELF_VAR), + protectedFieldGetterName(metaField)); + } else { + cppField = QLatin1String(CPP_SELF_VAR) + QLatin1String("->") + metaField->name(); + if (newWrapperSameObject) { + cppField.prepend(QLatin1String("&(")); + cppField.append(QLatin1Char(')')); + } + } + if (isCppIntegralPrimitive(fieldType) || fieldType->isEnum()) { + s << INDENT << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ';' << endl; + cppField = QLatin1String("cppOut_local"); + } else if (avoidProtectedHack() && metaField->isProtected()) { + s << INDENT << getFullTypeNameWithoutModifiers(fieldType); + if (fieldType->isContainer() || fieldType->isFlags() || fieldType->isSmartPointer()) { + s << '&'; + cppField.prepend(QLatin1Char('*')); + } else if ((!fieldType->isConstant() && !fieldType->isEnum() && !fieldType->isPrimitive()) || fieldType->indirections() == 1) { + s << '*'; + } + s << " fieldValue = " << cppField << ';' << endl; + cppField = QLatin1String("fieldValue"); + } + + s << INDENT << "PyObject* pyOut = 0;\n"; + if (newWrapperSameObject) { + // Special case colocated field with same address (first field in a struct) + s << INDENT << "if (reinterpret_cast(" + << cppField + << ") == reinterpret_cast(" + << CPP_SELF_VAR << ")) {\n"; + { + Indentation indent(INDENT); + s << INDENT << "pyOut = reinterpret_cast(Shiboken::Object::findColocatedChild(" + << "reinterpret_cast(self), reinterpret_cast(" + << cpythonTypeNameExt(fieldType) + << ")));\n"; + s << INDENT << "if (pyOut) {Py_IncRef(pyOut); return pyOut;}\n"; + } + s << INDENT << "}\n"; + // Check if field wrapper has already been created. + s << INDENT << "else if (Shiboken::BindingManager::instance().hasWrapper(" << cppField << ")) {" << "\n"; + { + Indentation indent(INDENT); + s << INDENT << "pyOut = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(" << cppField << ");" << "\n"; + s << INDENT << "Py_IncRef(pyOut);" << "\n"; + s << INDENT << "return pyOut;" << "\n"; + } + s << INDENT << "}\n"; + // Create and register new wrapper + s << INDENT << "pyOut = "; + s << "Shiboken::Object::newObject(reinterpret_cast(" << cpythonTypeNameExt(fieldType) + << "), " << cppField << ", false, true);" << endl; + s << INDENT << "Shiboken::Object::setParent(" PYTHON_SELF_VAR ", pyOut)"; + } else { + s << INDENT << "pyOut = "; + writeToPythonConversion(s, fieldType, metaField->enclosingClass(), cppField); + } + s << ';' << endl; + + s << INDENT << "return pyOut;" << endl; + s << '}' << endl; +} + +void CppGenerator::writeSetterFunction(QTextStream &s, + const AbstractMetaField *metaField, + GeneratorContext &context) +{ + ErrorCode errorCode(0); + s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* pyIn, void*)" << endl; + s << '{' << endl; + + writeCppSelfDefinition(s, context); + + s << INDENT << "if (pyIn == 0) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyErr_SetString(PyExc_TypeError, \"'"; + s << metaField->name() << "' may not be deleted\");" << endl; + s << INDENT << "return -1;" << endl; + } + s << INDENT << '}' << endl; + + AbstractMetaType* fieldType = metaField->type(); + + s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl; + s << INDENT << "if (!"; + writeTypeCheck(s, fieldType, QLatin1String("pyIn"), isNumber(fieldType->typeEntry())); + s << ") {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyErr_SetString(PyExc_TypeError, \"wrong type attributed to '"; + s << metaField->name() << "', '" << fieldType->name() << "' or convertible type expected\");" << endl; + s << INDENT << "return -1;" << endl; + } + s << INDENT << '}' << endl << endl; + + QString cppField = QString::fromLatin1("%1->%2").arg(QLatin1String(CPP_SELF_VAR), metaField->name()); + s << INDENT; + if (avoidProtectedHack() && metaField->isProtected()) { + s << getFullTypeNameWithoutModifiers(fieldType); + s << (fieldType->indirections() == 1 ? "*" : "") << " cppOut;" << endl; + s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut);" << endl; + s << INDENT << QString::fromLatin1("((%1*)%2)->%3(cppOut)") + .arg(wrapperName(metaField->enclosingClass()), + QLatin1String(CPP_SELF_VAR), protectedFieldSetterName(metaField)); + } else if (isCppIntegralPrimitive(fieldType) || fieldType->typeEntry()->isEnum() || fieldType->typeEntry()->isFlags()) { + s << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ';' << endl; + s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_local);" << endl; + s << INDENT << cppField << " = cppOut_local"; + } else { + s << getFullTypeNameWithoutModifiers(fieldType); + s << QString::fromLatin1("*").repeated(fieldType->indirections()) << "& cppOut_ptr = "; + s << cppField << ';' << endl; + s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_ptr)"; + } + s << ';' << endl << endl; + + if (isPointerToWrapperType(fieldType)) { + s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast(" PYTHON_SELF_VAR "), \""; + s << metaField->name() << "\", pyIn);" << endl; + } + + s << INDENT << "return 0;" << endl; + s << '}' << endl; +} + +void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &context) +{ + const AbstractMetaClass *metaClass = context.metaClass(); + QString baseName = cpythonBaseName(metaClass); + s << "static PyObject* "; + s << baseName << "_richcompare(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ", int op)" << endl; + s << '{' << endl; + writeCppSelfDefinition(s, 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; + writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR)); + s << endl; + + s << INDENT << "switch (op) {" << endl; + { + Indentation indent(INDENT); + const QVector &groupedFuncs = filterGroupedOperatorFunctions(metaClass, AbstractMetaClass::ComparisonOp); + for (const AbstractMetaFunctionList &overloads : groupedFuncs) { + const AbstractMetaFunction* rfunc = overloads[0]; + + QString operatorId = ShibokenGenerator::pythonRichCompareOperatorId(rfunc); + s << INDENT << "case " << operatorId << ':' << endl; + + Indentation indent(INDENT); + + QString op = rfunc->originalName(); + op = op.right(op.size() - QLatin1String("operator").size()); + + int alternativeNumericTypes = 0; + for (const AbstractMetaFunction *func : overloads) { + if (!func->isStatic() && + ShibokenGenerator::isNumber(func->arguments()[0]->type()->typeEntry())) + alternativeNumericTypes++; + } + + bool first = true; + OverloadData overloadData(overloads, this); + const OverloadDataList &nextOverloads = overloadData.nextOverloadData(); + for (OverloadData *od : nextOverloads) { + const AbstractMetaFunction* func = od->referenceFunction(); + if (func->isStatic()) + continue; + const AbstractMetaType* argType = getArgumentType(func, 1); + if (!argType) + continue; + if (!first) { + s << " else "; + } else { + first = false; + s << INDENT; + } + s << "if ("; + writeTypeCheck(s, argType, QLatin1String(PYTHON_ARG), alternativeNumericTypes == 1 || isPyInt(argType)); + s << ") {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "// " << func->signature() << endl; + writeArgumentConversion(s, argType, QLatin1String(CPP_ARG0), + QLatin1String(PYTHON_ARG), metaClass, + QString(), func->isUserAdded()); + + // If the function is user added, use the inject code + if (func->isUserAdded()) { + CodeSnipList snips = func->injectedCodeSnips(); + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, func->arguments().last()); + } 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 " = "; + if (func->type()) + writeToPythonConversion(s, func->type(), metaClass, QLatin1String(CPP_RETURN_VAR)); + else + s << "Py_None;" << endl << INDENT << "Py_INCREF(Py_None)"; + s << ';' << endl; + } + } + s << INDENT << '}'; + } + + s << " else {" << endl; + if (operatorId == QLatin1String("Py_EQ") || operatorId == QLatin1String("Py_NE")) { + Indentation indent(INDENT); + s << INDENT << PYTHON_RETURN_VAR " = " + << (operatorId == QLatin1String("Py_EQ") ? "Py_False" : "Py_True") << ';' << endl; + s << INDENT << "Py_INCREF(" PYTHON_RETURN_VAR ");" << endl; + } else { + Indentation indent(INDENT); + s << INDENT << "goto " << baseName << "_RichComparison_TypeError;" << endl; + } + s << INDENT << '}' << endl << endl; + + s << INDENT << "break;" << endl; + } + s << INDENT << "default:" << endl; + { + Indentation indent(INDENT); + s << INDENT << "goto " << baseName << "_RichComparison_TypeError;" << endl; + } + } + s << INDENT << '}' << endl << endl; + + s << INDENT << "if (" PYTHON_RETURN_VAR " && !PyErr_Occurred())" << endl; + { + Indentation indent(INDENT); + 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 << '}' << endl << endl; +} + +void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads) +{ + Q_ASSERT(!overloads.isEmpty()); + OverloadData overloadData(overloads, this); + bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData); + const AbstractMetaFunction* func = overloadData.referenceFunction(); + int min = overloadData.minArgs(); + int max = overloadData.maxArgs(); + + s << '"' << func->name() << "\", (PyCFunction)" << cpythonFunctionName(func) << ", "; + if ((min == max) && (max < 2) && !usePyArgs) { + if (max == 0) + s << "METH_NOARGS"; + else + s << "METH_O"; + } else { + s << "METH_VARARGS"; + if (overloadData.hasArgumentWithDefaultValue()) + s << "|METH_KEYWORDS"; + } + if (func->ownerClass() && overloadData.hasStaticFunction()) + s << "|METH_STATIC"; +} + +void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads) +{ + Q_ASSERT(!overloads.isEmpty()); + const AbstractMetaFunction* func = overloads.first(); + if (m_tpFuncs.contains(func->name())) + return; + + s << INDENT; + if (OverloadData::hasStaticAndInstanceFunctions(overloads)) { + s << cpythonMethodDefinitionName(func); + } else { + s << '{'; + writeMethodDefinitionEntry(s, overloads); + s << '}'; + } + s << ',' << endl; +} + +void CppGenerator::writeEnumsInitialization(QTextStream& s, AbstractMetaEnumList& enums) +{ + if (enums.isEmpty()) + return; + s << INDENT << "// Initialization of enums." << endl << endl; + for (const AbstractMetaEnum *cppEnum : qAsConst(enums)) { + if (cppEnum->isPrivate()) + continue; + writeEnumInitialization(s, cppEnum); + } +} + +void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* cppEnum) +{ + const AbstractMetaClass* enclosingClass = getProperEnclosingClassForEnum(cppEnum); + const AbstractMetaClass* upper = enclosingClass ? enclosingClass->enclosingClass() : 0; + bool hasUpperEnclosingClass = upper && upper->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass; + QString enclosingObjectVariable; + if (enclosingClass) + enclosingObjectVariable = QLatin1Char('&') + cpythonTypeName(enclosingClass); + else if (hasUpperEnclosingClass) + enclosingObjectVariable = QLatin1String("enclosingClass"); + else + enclosingObjectVariable = QLatin1String("module"); + + s << INDENT << "// Initialization of "; + s << (cppEnum->isAnonymous() ? "anonymous enum identified by enum value" : "enum"); + s << " '" << cppEnum->name() << "'." << endl; + + if (!cppEnum->isAnonymous()) { + FlagsTypeEntry* flags = cppEnum->typeEntry()->flags(); + if (flags) { + s << INDENT << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\"" << flags->flagsName() << "\", &" + << cpythonEnumName(cppEnum) << "_as_number);" << endl; + } + + s << INDENT << cpythonTypeNameExt(cppEnum->typeEntry()) << " = Shiboken::Enum::"; + s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnum" : "createGlobalEnum"); + s << '(' << enclosingObjectVariable << ',' << endl; + { + Indentation indent(INDENT); + s << INDENT << '"' << cppEnum->name() << "\"," << endl; + s << INDENT << '"' << getClassTargetFullName(cppEnum) << "\"," << endl; + s << INDENT << '"' << (cppEnum->enclosingClass() ? (cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::")) : QString()); + s << cppEnum->name() << '"'; + if (flags) + s << ',' << endl << INDENT << cpythonTypeNameExt(flags); + s << ");" << endl; + } + s << INDENT << "if (!" << cpythonTypeNameExt(cppEnum->typeEntry()) << ')' << endl; + { + Indentation indent(INDENT); + s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl; + } + } + + const AbstractMetaEnumValueList &enumValues = cppEnum->values(); + for (const AbstractMetaEnumValue *enumValue : enumValues) { + if (cppEnum->typeEntry()->isEnumValueRejected(enumValue->name())) + continue; + + QString enumValueText; + if (!avoidProtectedHack() || !cppEnum->isProtected()) { + enumValueText = QLatin1String("(long) "); + if (cppEnum->enclosingClass()) + enumValueText += cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::"); + enumValueText += enumValue->name(); + } else { + enumValueText += QString::number(enumValue->value()); + } + + if (cppEnum->isAnonymous()) { + if (enclosingClass || hasUpperEnclosingClass) { + s << INDENT << '{' << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyObject* anonEnumItem = PyInt_FromLong(" << enumValueText << ");" << endl; + s << INDENT << "if (PyDict_SetItemString(reinterpret_cast(" << enclosingObjectVariable + << ")->super.ht_type.tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl; + { + Indentation indent(INDENT); + s << INDENT << "return " << m_currentErrorCode << ';' << endl; + } + s << INDENT << "Py_DECREF(anonEnumItem);" << endl; + } + s << INDENT << '}' << endl; + } else { + s << INDENT << "if (PyModule_AddIntConstant(module, \"" << enumValue->name() << "\", "; + s << enumValueText << ") < 0)" << endl; + { + Indentation indent(INDENT); + s << INDENT << "return " << m_currentErrorCode << ';' << endl; + } + } + } else { + s << INDENT << "if (!Shiboken::Enum::"; + s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnumItem" : "createGlobalEnumItem"); + s << '(' << cpythonTypeNameExt(cppEnum->typeEntry()) << ',' << endl; + Indentation indent(INDENT); + s << INDENT << enclosingObjectVariable << ", \"" << enumValue->name() << "\", "; + s << enumValueText << "))" << endl; + s << INDENT << "return " << m_currentErrorCode << ';' << endl; + } + } + + writeEnumConverterInitialization(s, cppEnum); + + s << INDENT << "// End of '" << cppEnum->name() << "' enum"; + if (cppEnum->typeEntry()->flags()) + s << "/flags"; + s << '.' << endl << endl; +} + +void CppGenerator::writeSignalInitialization(QTextStream& s, const AbstractMetaClass* metaClass) +{ + // Try to check something and print some warnings + const AbstractMetaFunctionList &signalFuncs = metaClass->cppSignalFunctions(); + for (const AbstractMetaFunction *cppSignal : signalFuncs) { + if (cppSignal->declaringClass() != metaClass) + continue; + const AbstractMetaArgumentList &arguments = cppSignal->arguments(); + for (AbstractMetaArgument *arg : arguments) { + AbstractMetaType* metaType = arg->type(); + const QByteArray origType = + QMetaObject::normalizedType(qPrintable(metaType->originalTypeDescription())); + const QByteArray cppSig = + QMetaObject::normalizedType(qPrintable(metaType->cppSignature())); + if ((origType != cppSig) && (!metaType->isFlags())) { + qCWarning(lcShiboken).noquote().nospace() + << "Typedef used on signal " << metaClass->qualifiedCppName() << "::" + << cppSignal->signature(); + } + } + } + + s << INDENT << "PySide::Signal::registerSignals(&" << cpythonTypeName(metaClass) << ", &::" + << metaClass->qualifiedCppName() << "::staticMetaObject);" << endl; +} + +void CppGenerator::writeFlagsToLong(QTextStream& s, const AbstractMetaEnum* cppEnum) +{ + FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags(); + if (!flagsEntry) + return; + s << "static PyObject* " << cpythonEnumName(cppEnum) << "_long(PyObject* " PYTHON_SELF_VAR ")" << endl; + s << "{" << endl; + s << INDENT << "int val;" << endl; + AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry); + s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl; + s << INDENT << "return Shiboken::Conversions::copyToPython(Shiboken::Conversions::PrimitiveTypeConverter(), &val);" << endl; + s << "}" << endl; +} + +void CppGenerator::writeFlagsNonZero(QTextStream& s, const AbstractMetaEnum* cppEnum) +{ + FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags(); + if (!flagsEntry) + return; + s << "static int " << cpythonEnumName(cppEnum) << "__nonzero(PyObject* " PYTHON_SELF_VAR ")" << endl; + s << "{" << endl; + + s << INDENT << "int val;" << endl; + AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry); + s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl; + s << INDENT << "return val != 0;" << endl; + s << "}" << endl; +} + +void CppGenerator::writeFlagsMethods(QTextStream& s, const AbstractMetaEnum* cppEnum) +{ + writeFlagsBinaryOperator(s, cppEnum, QLatin1String("and"), QLatin1String("&")); + writeFlagsBinaryOperator(s, cppEnum, QLatin1String("or"), QLatin1String("|")); + writeFlagsBinaryOperator(s, cppEnum, QLatin1String("xor"), QLatin1String("^")); + + writeFlagsUnaryOperator(s, cppEnum, QLatin1String("invert"), QLatin1String("~")); + writeFlagsToLong(s, cppEnum); + writeFlagsNonZero(s, cppEnum); + + s << endl; +} + +void CppGenerator::writeFlagsNumberMethodsDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum) +{ + QString cpythonName = cpythonEnumName(cppEnum); + + s << "static PyNumberMethods " << cpythonName << "_as_number = {" << endl; + s << INDENT << "/*nb_add*/ 0," << endl; + s << INDENT << "/*nb_subtract*/ 0," << endl; + s << INDENT << "/*nb_multiply*/ 0," << endl; + s << INDENT << "#ifndef IS_PY3K" << endl; + s << INDENT << "/* nb_divide */ 0," << endl; + s << INDENT << "#endif" << endl; + s << INDENT << "/*nb_remainder*/ 0," << endl; + s << INDENT << "/*nb_divmod*/ 0," << endl; + s << INDENT << "/*nb_power*/ 0," << endl; + s << INDENT << "/*nb_negative*/ 0," << endl; + s << INDENT << "/*nb_positive*/ 0," << endl; + s << INDENT << "/*nb_absolute*/ 0," << endl; + s << INDENT << "/*nb_nonzero*/ " << cpythonName << "__nonzero," << endl; + s << INDENT << "/*nb_invert*/ (unaryfunc)" << cpythonName << "___invert__," << endl; + s << INDENT << "/*nb_lshift*/ 0," << endl; + s << INDENT << "/*nb_rshift*/ 0," << endl; + s << INDENT << "/*nb_and*/ (binaryfunc)" << cpythonName << "___and__," << endl; + s << INDENT << "/*nb_xor*/ (binaryfunc)" << cpythonName << "___xor__," << endl; + s << INDENT << "/*nb_or*/ (binaryfunc)" << cpythonName << "___or__," << endl; + s << INDENT << "#ifndef IS_PY3K" << endl; + s << INDENT << "/* nb_coerce */ 0," << endl; + s << INDENT << "#endif" << endl; + s << INDENT << "/*nb_int*/ " << cpythonName << "_long," << endl; + s << INDENT << "#ifdef IS_PY3K" << endl; + s << INDENT << "/*nb_reserved*/ 0," << endl; + s << INDENT << "/*nb_float*/ 0," << endl; + s << INDENT << "#else" << endl; + s << INDENT << "/*nb_long*/ " << cpythonName << "_long," << endl; + s << INDENT << "/*nb_float*/ 0," << endl; + s << INDENT << "/*nb_oct*/ 0," << endl; + s << INDENT << "/*nb_hex*/ 0," << endl; + s << INDENT << "#endif" << endl; + s << INDENT << "/*nb_inplace_add*/ 0," << endl; + s << INDENT << "/*nb_inplace_subtract*/ 0," << endl; + s << INDENT << "/*nb_inplace_multiply*/ 0," << endl; + s << INDENT << "#ifndef IS_PY3K" << endl; + s << INDENT << "/*nb_inplace_divide*/ 0," << endl; + s << INDENT << "#endif" << endl; + s << INDENT << "/*nb_inplace_remainder*/ 0," << endl; + s << INDENT << "/*nb_inplace_power*/ 0," << endl; + s << INDENT << "/*nb_inplace_lshift*/ 0," << endl; + s << INDENT << "/*nb_inplace_rshift*/ 0," << endl; + s << INDENT << "/*nb_inplace_and*/ 0," << endl; + s << INDENT << "/*nb_inplace_xor*/ 0," << endl; + s << INDENT << "/*nb_inplace_or*/ 0," << endl; + s << INDENT << "/*nb_floor_divide*/ 0," << endl; + s << INDENT << "/*nb_true_divide*/ 0," << endl; + s << INDENT << "/*nb_inplace_floor_divide*/ 0," << endl; + s << INDENT << "/*nb_inplace_true_divide*/ 0," << endl; + s << INDENT << "/*nb_index*/ 0" << endl; + s << "};" << endl << endl; +} + +void CppGenerator::writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum, + QString pyOpName, QString cppOpName) +{ + FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags(); + Q_ASSERT(flagsEntry); + + s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ")" << endl; + s << '{' << endl; + + AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry); + 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 << "#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 << "#endif" << endl << endl; + s << INDENT << "cppResult = " CPP_SELF_VAR " " << cppOpName << " cppArg;" << endl; + s << INDENT << "return "; + writeToPythonConversion(s, flagsType, 0, QLatin1String("cppResult")); + s << ';' << endl; + s << '}' << endl << endl; +} + +void CppGenerator::writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum, + QString pyOpName, 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 << '{' << 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; + if (boolResult) + s << "bool"; + else + s << "::" << flagsEntry->originalName(); + s << " cppResult = " << cppOpName << CPP_SELF_VAR ";" << endl; + s << INDENT << "return "; + if (boolResult) + s << "PyBool_FromLong(cppResult)"; + else + writeToPythonConversion(s, flagsType, 0, QLatin1String("cppResult")); + s << ';' << endl; + s << '}' << endl << endl; +} + +QString CppGenerator::getInitFunctionName(GeneratorContext &context) const +{ + QString initFunctionName; + if (!context.forSmartPointer()) { + initFunctionName = context.metaClass()->qualifiedCppName(); + initFunctionName.replace(QLatin1String("::"), QLatin1String("_")); + } else { + initFunctionName = getFilteredCppSignatureString(context.preciseType()->cppSignature()); + } + return initFunctionName; +} + +void CppGenerator::writeClassRegister(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &classContext) +{ + const ComplexTypeEntry* classTypeEntry = metaClass->typeEntry(); + + const AbstractMetaClass* enc = metaClass->enclosingClass(); + bool hasEnclosingClass = enc && enc->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass; + QString enclosingObjectVariable = hasEnclosingClass ? QLatin1String("enclosingClass") : QLatin1String("module"); + + QString pyTypeName = cpythonTypeName(metaClass); + QString initFunctionName = getInitFunctionName(classContext); + s << "void init_" << initFunctionName; + s << "(PyObject* " << enclosingObjectVariable << ")" << endl; + s << '{' << endl; + + if (supportsNumberProtocol(metaClass)) { + s << INDENT << "// type has number operators" << endl; + writeTypeAsNumberDefinition(s, metaClass); + s << INDENT << pyTypeName << ".super.ht_type.tp_as_number = &" << pyTypeName << "AsNumber;" << endl; + s << endl; + } + + if (supportsSequenceProtocol(metaClass)) { + s << INDENT << "// type supports sequence protocol" << endl; + writeTypeAsSequenceDefinition(s, metaClass); + s << INDENT << pyTypeName << ".super.ht_type.tp_as_sequence = &" << pyTypeName << "AsSequence;" << endl; + s << endl; + } + + if (supportsMappingProtocol(metaClass)) { + s << INDENT << "// type supports mapping protocol" << endl; + writeTypeAsMappingDefinition(s, metaClass); + s << INDENT << pyTypeName << ".super.ht_type.tp_as_mapping = &" << pyTypeName << "AsMapping;" << endl; + s << endl; + } + + if (!classContext.forSmartPointer()) + s << INDENT << cpythonTypeNameExt(classTypeEntry); + else + s << INDENT << cpythonTypeNameExt(classContext.preciseType()); + + s << " = reinterpret_cast(&" << pyTypeName << ");" << endl; + s << endl; + + // Multiple inheritance + QString pyTypeBasesVariable = pyTypeName + QLatin1String("_bases"); + const AbstractMetaClassList baseClasses = getBaseClasses(metaClass); + if (metaClass->baseClassNames().size() > 1) { + s << INDENT << "PyObject* " << pyTypeBasesVariable << " = PyTuple_Pack(" << baseClasses.size() << ',' << endl; + QStringList bases; + for (const AbstractMetaClass *base : baseClasses) + bases << QLatin1String("(PyObject*)") + cpythonTypeNameExt(base->typeEntry()); + Indentation indent(INDENT); + QString separator; + QTextStream sep(&separator); + sep << "," << endl << INDENT; + s << INDENT << bases.join(separator) << ");" << endl << endl; + } + + // Create type and insert it in the module or enclosing class. + s << INDENT << "if (!Shiboken::ObjectType::introduceWrapperType(" << enclosingObjectVariable; + QString typeName; + if (!classContext.forSmartPointer()) + typeName = metaClass->name(); + else + typeName = classContext.preciseType()->cppSignature(); + + s << ", \"" << typeName << "\", \""; + + // Original name + if (!classContext.forSmartPointer()) + s << metaClass->qualifiedCppName() << (isObjectType(classTypeEntry) ? "*" : ""); + else + s << classContext.preciseType()->cppSignature(); + + s << "\"," << endl; + { + Indentation indent(INDENT); + s << INDENT << "&" << pyTypeName; + + // Set destructor function + if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) { + QString dtorClassName = metaClass->qualifiedCppName(); + if ((avoidProtectedHack() && metaClass->hasProtectedDestructor()) || classTypeEntry->isValue()) + dtorClassName = wrapperName(metaClass); + if (classContext.forSmartPointer()) + dtorClassName = wrapperName(classContext.preciseType()); + + s << ", &Shiboken::callCppDestructor< ::" << dtorClassName << " >"; + } else if (metaClass->baseClass() || hasEnclosingClass) { + s << ", 0"; + } + + // Base type + if (metaClass->baseClass()) { + s << ", reinterpret_cast(" << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()) << ')'; + // The other base types + if (metaClass->baseClassNames().size() > 1) + s << ", " << pyTypeBasesVariable; + else if (hasEnclosingClass) + s << ", 0"; + } else if (hasEnclosingClass) { + s << ", 0, 0"; + } + if (hasEnclosingClass) + s << ", true"; + s << ")) {" << endl; + s << INDENT << "return;" << endl; + } + s << INDENT << '}' << endl << endl; + + // Register conversions for the type. + writeConverterRegister(s, metaClass, classContext); + s << endl; + + // class inject-code target/beginning + if (!classTypeEntry->codeSnips().isEmpty()) { + writeCodeSnips(s, classTypeEntry->codeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, metaClass); + s << endl; + } + + // Fill multiple inheritance data, if needed. + const AbstractMetaClass* miClass = getMultipleInheritingClass(metaClass); + if (miClass) { + s << INDENT << "MultipleInheritanceInitFunction func = "; + if (miClass == metaClass) { + s << multipleInheritanceInitializerFunctionName(miClass) << ";" << endl; + } else { + s << "Shiboken::ObjectType::getMultipleIheritanceFunction(reinterpret_cast("; + s << cpythonTypeNameExt(miClass->typeEntry()) << "));" << endl; + } + s << INDENT << "Shiboken::ObjectType::setMultipleIheritanceFunction(&"; + s << cpythonTypeName(metaClass) << ", func);" << endl; + s << INDENT << "Shiboken::ObjectType::setCastFunction(&" << cpythonTypeName(metaClass); + s << ", &" << cpythonSpecialCastFunctionName(metaClass) << ");" << endl; + } + + // Set typediscovery struct or fill the struct of another one + if (metaClass->isPolymorphic() && metaClass->baseClass()) { + s << INDENT << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(&" << cpythonTypeName(metaClass); + s << ", &" << cpythonBaseName(metaClass) << "_typeDiscovery);" << endl << endl; + } + + AbstractMetaEnumList classEnums = metaClass->enums(); + const AbstractMetaClassList &innerClasses = metaClass->innerClasses(); + for (AbstractMetaClass *innerClass : innerClasses) + lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass); + + ErrorCode errorCode(QString::null); + writeEnumsInitialization(s, classEnums); + + if (metaClass->hasSignals()) + writeSignalInitialization(s, metaClass); + + // Write static fields + const AbstractMetaFieldList &fields = metaClass->fields(); + for (const AbstractMetaField *field : fields) { + if (!field->isStatic()) + continue; + s << INDENT << QLatin1String("PyDict_SetItemString(") + cpythonTypeName(metaClass) + QLatin1String(".super.ht_type.tp_dict, \""); + s << field->name() << "\", "; + writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + QLatin1String("::") + field->name()); + s << ");" << endl; + } + s << endl; + + // class inject-code target/end + if (!classTypeEntry->codeSnips().isEmpty()) { + s << endl; + writeCodeSnips(s, classTypeEntry->codeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, metaClass); + } + + if (usePySideExtensions()) { + if (avoidProtectedHack() && shouldGenerateCppWrapper(metaClass)) + s << INDENT << wrapperName(metaClass) << "::pysideInitQtMetaTypes();\n"; + else + writeInitQtMetaTypeFunctionBody(s, classContext); + } + + if (usePySideExtensions() && metaClass->isQObject()) { + s << INDENT << "Shiboken::ObjectType::setSubTypeInitHook(&" << pyTypeName << ", &PySide::initQObjectSubType);" << endl; + s << INDENT << "PySide::initDynamicMetaObject(&" << pyTypeName << ", &::" << metaClass->qualifiedCppName() + << "::staticMetaObject, sizeof(::" << metaClass->qualifiedCppName() << "));" << endl; + } + + s << '}' << endl; +} + +void CppGenerator::writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const +{ + const AbstractMetaClass* metaClass = context.metaClass(); + // Gets all class name variants used on different possible scopes + QStringList nameVariants; + if (!context.forSmartPointer()) + nameVariants << metaClass->name(); + else + nameVariants << context.preciseType()->cppSignature(); + + const AbstractMetaClass* enclosingClass = metaClass->enclosingClass(); + while (enclosingClass) { + if (enclosingClass->typeEntry()->generateCode()) + nameVariants << (enclosingClass->name() + QLatin1String("::") + nameVariants.last()); + enclosingClass = enclosingClass->enclosingClass(); + } + + QString className; + if (!context.forSmartPointer()) + className = metaClass->qualifiedCppName(); + else + className = context.preciseType()->cppSignature(); + + if (!metaClass->isNamespace() && !metaClass->isAbstract()) { + // Qt metatypes are registered only on their first use, so we do this now. + bool canBeValue = false; + if (!isObjectType(metaClass)) { + // check if there's a empty ctor + const AbstractMetaFunctionList &funcs = metaClass->functions(); + for (AbstractMetaFunction *func : funcs) { + if (func->isConstructor() && !func->arguments().count()) { + canBeValue = true; + break; + } + } + } + + if (canBeValue) { + for (const QString &name : qAsConst(nameVariants)) { + if (name == QLatin1String("iterator")) { + qCWarning(lcShiboken).noquote().nospace() + << QString::fromLatin1("%1:%2 FIXME:\n" + " The code tried to qRegisterMetaType the unqualified name " + "'iterator'. This is currently fixed by a hack(ct) and needs improvement!") + .arg(QFile::decodeName(__FILE__)).arg(__LINE__); + continue; + } + s << INDENT << "qRegisterMetaType< ::" << className << " >(\"" << name << "\");" << endl; + } + } + } + + const AbstractMetaEnumList &enums = metaClass->enums(); + for (AbstractMetaEnum *metaEnum : enums) { + if (!metaEnum->isPrivate() && !metaEnum->isAnonymous()) { + for (const QString &name : qAsConst(nameVariants)) + s << INDENT << "qRegisterMetaType< ::" << metaEnum->typeEntry()->qualifiedCppName() << " >(\"" << name << "::" << metaEnum->name() << "\");" << endl; + + if (metaEnum->typeEntry()->flags()) { + QString n = metaEnum->typeEntry()->flags()->originalName(); + s << INDENT << "qRegisterMetaType< ::" << n << " >(\"" << n << "\");" << endl; + } + } + } +} + +void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMetaClass* metaClass) +{ + QString polymorphicExpr = metaClass->typeEntry()->polymorphicIdValue(); + + s << "static void* " << cpythonBaseName(metaClass) << "_typeDiscovery(void* cptr, SbkObjectType* instanceType)\n{" << endl; + + if (!polymorphicExpr.isEmpty()) { + polymorphicExpr = polymorphicExpr.replace(QLatin1String("%1"), + QLatin1String(" reinterpret_cast< ::") + + metaClass->qualifiedCppName() + + QLatin1String("*>(cptr)")); + s << INDENT << " if (" << polymorphicExpr << ")" << endl; + { + Indentation indent(INDENT); + s << INDENT << "return cptr;" << endl; + } + } else if (metaClass->isPolymorphic()) { + const AbstractMetaClassList &ancestors = getAllAncestors(metaClass); + for (AbstractMetaClass *ancestor : ancestors) { + if (ancestor->baseClass()) + continue; + if (ancestor->isPolymorphic()) { + s << INDENT << "if (instanceType == reinterpret_cast(Shiboken::SbkType< ::" + << ancestor->qualifiedCppName() << " >()))" << endl; + Indentation indent(INDENT); + s << INDENT << "return dynamic_cast< ::" << metaClass->qualifiedCppName() + << "*>(reinterpret_cast< ::"<< ancestor->qualifiedCppName() << "*>(cptr));" << endl; + } else { + qCWarning(lcShiboken).noquote().nospace() + << metaClass->qualifiedCppName() << " inherits from a non polymorphic type (" + << ancestor->qualifiedCppName() << "), type discovery based on RTTI is " + "impossible, write a polymorphic-id-expression for this type."; + } + + } + } + s << INDENT << "return 0;" << endl; + s << "}\n\n"; +} + +QString CppGenerator::writeSmartPointerGetterCast() { + return QLatin1String("const_cast(" SMART_POINTER_GETTER ")"); +} + +void CppGenerator::writeSetattroFunction(QTextStream &s, GeneratorContext &context) +{ + const AbstractMetaClass* metaClass = context.metaClass(); + s << "static int " << cpythonSetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name, PyObject* value)" << endl; + s << '{' << endl; + if (usePySideExtensions()) { + s << INDENT << "Shiboken::AutoDecRef pp(reinterpret_cast(PySide::Property::getObject(" PYTHON_SELF_VAR ", name)));" << endl; + s << INDENT << "if (!pp.isNull())" << endl; + Indentation indent(INDENT); + s << INDENT << "return PySide::Property::setValue(reinterpret_cast(pp.object()), " PYTHON_SELF_VAR ", value);" << endl; + } + + if (context.forSmartPointer()) { + s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for the corresponding C++ object held by the smart pointer." << endl; + s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", " + << writeSmartPointerGetterCast() << ", 0);" << endl; + s << INDENT << "if (rawObj) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "int hasAttribute = PyObject_HasAttr(rawObj, name);" << endl; + s << INDENT << "if (hasAttribute) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "return PyObject_GenericSetAttr(rawObj, name, value);" << endl; + } + s << INDENT << '}' << endl; + s << INDENT << "Py_DECREF(rawObj);" << endl; + } + s << INDENT << '}' << endl; + + } + + s << INDENT << "return PyObject_GenericSetAttr(" PYTHON_SELF_VAR ", name, value);" << endl; + s << '}' << endl; +} + +static inline QString qObjectClassName() { return QStringLiteral("QObject"); } +static inline QString qMetaObjectClassName() { return QStringLiteral("QMetaObject"); } + +void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &context) +{ + const AbstractMetaClass* metaClass = context.metaClass(); + s << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name)" << endl; + s << '{' << endl; + + 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))); + } else { + getattrFunc = QLatin1String("PyObject_GenericGetAttr(" PYTHON_SELF_VAR ", name)"); + } + + if (classNeedsGetattroFunction(metaClass)) { + s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "// Search the method in the instance dict" << endl; + s << INDENT << "if (reinterpret_cast(" PYTHON_SELF_VAR ")->ob_dict) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyObject* meth = PyDict_GetItem(reinterpret_cast(" PYTHON_SELF_VAR ")->ob_dict, name);" << endl; + s << INDENT << "if (meth) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "Py_INCREF(meth);" << endl; + s << INDENT << "return meth;" << endl; + } + s << INDENT << '}' << endl; + } + s << INDENT << '}' << endl; + s << INDENT << "// Search the method in the type dict" << endl; + s << INDENT << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ")) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyObject* meth = PyDict_GetItem(" PYTHON_SELF_VAR "->ob_type->tp_dict, name);" << 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 << '}' << endl; + + const AbstractMetaFunctionList &funcs = getMethodsWithBothStaticAndNonStaticMethods(metaClass); + for (const AbstractMetaFunction *func : funcs) { + QString defName = cpythonMethodDefinitionName(func); + s << INDENT << "static PyMethodDef non_static_" << defName << " = {" << endl; + { + Indentation indent(INDENT); + s << INDENT << defName << ".ml_name," << endl; + s << INDENT << defName << ".ml_meth," << endl; + s << INDENT << defName << ".ml_flags & (~METH_STATIC)," << endl; + s << INDENT << defName << ".ml_doc," << endl; + } + 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 << '}' << endl; + } + + if (context.forSmartPointer()) { + s << INDENT << "PyObject *tmp = " << getattrFunc << ';' << endl; + s << INDENT << "if (tmp) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "return tmp;" << endl; + } + s << INDENT << "} else {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "if (!PyErr_ExceptionMatches(PyExc_AttributeError)) return NULL;" << endl; + s << INDENT << "PyErr_Clear();" << endl; + + s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for " + "the corresponding C++ object held by the smart pointer." << endl; + s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", " + << writeSmartPointerGetterCast() << ", 0);" << endl; + s << INDENT << "if (rawObj) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyObject *attribute = PyObject_GetAttr(rawObj, name);" << endl; + s << INDENT << "if (attribute) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "tmp = attribute;" << endl; + } + s << INDENT << '}' << endl; + s << INDENT << "Py_DECREF(rawObj);" << endl; + } + s << INDENT << '}' << endl; + s << INDENT << "if (!tmp) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyTypeObject *tp = Py_TYPE(self);" << endl; + s << INDENT << "PyErr_Format(PyExc_AttributeError," << endl; + s << INDENT << " \"'%.50s' object has no attribute '%.400s'\"," << endl; + s << INDENT << " tp->tp_name, PyBytes_AS_STRING(name));" << endl; + s << INDENT << "return NULL;" << endl; + } + s << INDENT << "} else {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "return tmp;" << endl; + } + s << INDENT << '}' << endl; + + } + s << INDENT << '}' << endl; + + } else { + s << INDENT << "return " << getattrFunc << ';' << endl; + } + s << '}' << endl; +} + +bool CppGenerator::finishGeneration() +{ + //Generate CPython wrapper file + QString classInitDecl; + QTextStream s_classInitDecl(&classInitDecl); + QString classPythonDefines; + QTextStream s_classPythonDefines(&classPythonDefines); + + QSet includes; + QString globalFunctionImpl; + QTextStream s_globalFunctionImpl(&globalFunctionImpl); + QString globalFunctionDecl; + QTextStream s_globalFunctionDef(&globalFunctionDecl); + + Indentation indent(INDENT); + + const FunctionGroupMap &functionGroups = getFunctionGroups(); + for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) { + AbstractMetaFunctionList overloads; + for (AbstractMetaFunction *func : it.value()) { + if (!func->isModifiedRemoved()) { + overloads.append(func); + if (func->typeEntry()) + includes << func->typeEntry()->include(); + } + } + + if (overloads.isEmpty()) + continue; + + // Dummy context to satisfy the API. + GeneratorContext classContext; + writeMethodWrapper(s_globalFunctionImpl, overloads, classContext); + writeMethodDefinition(s_globalFunctionDef, overloads); + } + + //this is a temporary solution before new type revison implementation + //We need move QMetaObject register before QObject + Dependencies additionalDependencies; + const AbstractMetaClassList &allClasses = classes(); + if (AbstractMetaClass::findClass(allClasses, qObjectClassName()) != Q_NULLPTR + && AbstractMetaClass::findClass(allClasses, qMetaObjectClassName()) != Q_NULLPTR) { + Dependency dependency; + dependency.parent = qMetaObjectClassName(); + dependency.child = qObjectClassName(); + additionalDependencies.append(dependency); + } + const AbstractMetaClassList lst = classesTopologicalSorted(additionalDependencies); + + for (const AbstractMetaClass *cls : lst){ + if (!shouldGenerate(cls)) + continue; + + s_classInitDecl << "void init_" << cls->qualifiedCppName().replace(QLatin1String("::"), QLatin1String("_")) << "(PyObject* module);" << endl; + + QString defineStr = QLatin1String("init_") + cls->qualifiedCppName().replace(QLatin1String("::"), QLatin1String("_")); + + if (cls->enclosingClass() && (cls->enclosingClass()->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass)) + defineStr += QLatin1Char('(') + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) + QLatin1String("->tp_dict);"); + else + defineStr += QLatin1String("(module);"); + s_classPythonDefines << INDENT << defineStr << endl; + } + + // Initialize smart pointer types. + const QVector &smartPtrs = instantiatedSmartPointers(); + for (const AbstractMetaType *metaType : smartPtrs) { + GeneratorContext context(0, metaType, true); + QString initFunctionName = getInitFunctionName(context); + s_classInitDecl << "void init_" << initFunctionName << "(PyObject* module);" << endl; + QString defineStr = QLatin1String("init_") + initFunctionName; + defineStr += QLatin1String("(module);"); + s_classPythonDefines << INDENT << defineStr << endl; + } + + QString moduleFileName(outputDirectory() + QLatin1Char('/') + subDirectoryForPackage(packageName())); + moduleFileName += QLatin1Char('/') + moduleName().toLower() + QLatin1String("_module_wrapper.cpp"); + + 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); + + // write license comment + s << licenseComment() << endl; + + s << "#include " << endl; + s << "#include " << endl; + s << "#include " << endl; + if (usePySideExtensions()) { + s << includeQDebug; + s << "#include " << endl; + } + + s << "#include \"" << getModuleHeaderFileName() << '"' << endl << endl; + for (const Include &include : qAsConst(includes)) + s << include; + s << endl; + + // Global enums + AbstractMetaEnumList globalEnums = this->globalEnums(); + const AbstractMetaClassList &classList = classes(); + for (const AbstractMetaClass *metaClass : classList) { + const AbstractMetaClass* encClass = metaClass->enclosingClass(); + if (encClass && encClass->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass) + continue; + lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass); + } + + TypeDatabase* typeDb = TypeDatabase::instance(); + TypeSystemTypeEntry* moduleEntry = reinterpret_cast(typeDb->findType(packageName())); + + //Extra includes + s << endl << "// Extra includes" << endl; + QVector extraIncludes; + if (moduleEntry) + extraIncludes = moduleEntry->extraIncludes(); + for (AbstractMetaEnum *cppEnum : qAsConst(globalEnums)) + extraIncludes.append(cppEnum->typeEntry()->extraIncludes()); + qSort(extraIncludes.begin(), extraIncludes.end()); + for (const Include &inc : qAsConst(extraIncludes)) + s << inc; + s << endl; + + s << "// Current module's type array." << endl; + s << "PyTypeObject** " << cppApiVariableName() << ';' << endl; + + s << "// Current module's converter array." << endl; + s << "SbkConverter** " << convertersVariableName() << ';' << endl; + + CodeSnipList snips; + if (moduleEntry) + snips = moduleEntry->codeSnips(); + + // module inject-code native/beginning + if (!snips.isEmpty()) { + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode); + s << endl; + } + + // cleanup staticMetaObject attribute + if (usePySideExtensions()) { + s << "void cleanTypesAttributes(void) {" << endl; + s << INDENT << "for (int i = 0, imax = SBK_" << moduleName() << "_IDX_COUNT; i < imax; i++) {" << endl; + { + Indentation indentation(INDENT); + s << INDENT << "PyObject *pyType = reinterpret_cast(" << cppApiVariableName() << "[i]);" << endl; + s << INDENT << "if (pyType && PyObject_HasAttrString(pyType, \"staticMetaObject\"))"<< endl; + { + Indentation indentation(INDENT); + s << INDENT << "PyObject_SetAttrString(pyType, \"staticMetaObject\", Py_None);" << endl; + } + } + s << INDENT << "}" << endl; + s << "}" << endl; + } + + s << "// Global functions "; + s << "------------------------------------------------------------" << endl; + s << globalFunctionImpl << endl; + + s << "static PyMethodDef " << moduleName() << "_methods[] = {" << endl; + s << globalFunctionDecl; + s << INDENT << "{0} // Sentinel" << endl << "};" << endl << endl; + + s << "// Classes initialization functions "; + s << "------------------------------------------------------------" << endl; + s << classInitDecl << endl; + + if (!globalEnums.isEmpty()) { + QString converterImpl; + QTextStream convImpl(&converterImpl); + + s << "// Enum definitions "; + s << "------------------------------------------------------------" << endl; + for (const AbstractMetaEnum *cppEnum : qAsConst(globalEnums)) { + if (cppEnum->isAnonymous() || cppEnum->isPrivate()) + continue; + writeEnumConverterFunctions(s, cppEnum); + s << endl; + } + + if (!converterImpl.isEmpty()) { + s << "// Enum converters "; + s << "------------------------------------------------------------" << endl; + s << "namespace Shiboken" << endl << '{' << endl; + s << converterImpl << endl; + s << "} // namespace Shiboken" << endl << endl; + } + } + + const QStringList &requiredModules = typeDb->requiredTargetImports(); + if (!requiredModules.isEmpty()) + s << "// Required modules' type and converter arrays." << endl; + for (const QString &requiredModule : requiredModules) { + s << "PyTypeObject** " << cppApiVariableName(requiredModule) << ';' << endl; + s << "SbkConverter** " << convertersVariableName(requiredModule) << ';' << endl; + } + s << endl; + + s << "// Module initialization "; + s << "------------------------------------------------------------" << endl; + ExtendedConverterData extendedConverters = getExtendedConverters(); + if (!extendedConverters.isEmpty()) { + s << endl << "// Extended Converters." << endl << endl; + for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) { + const TypeEntry *externalType = it.key(); + s << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << endl; + for (const AbstractMetaClass *sourceClass : it.value()) { + AbstractMetaType* sourceType = buildAbstractMetaTypeFromAbstractMetaClass(sourceClass); + AbstractMetaType* targetType = buildAbstractMetaTypeFromTypeEntry(externalType); + writePythonToCppConversionFunctions(s, sourceType, targetType); + } + } + } + + const QVector &typeConversions = getPrimitiveCustomConversions(); + if (!typeConversions.isEmpty()) { + s << endl << "// Primitive Type converters." << endl << endl; + for (const CustomConversion *conversion : typeConversions) { + s << "// C++ to Python conversion for type '" << conversion->ownerType()->qualifiedCppName() << "'." << endl; + writeCppToPythonFunction(s, conversion); + writeCustomConverterFunctions(s, conversion); + } + s << endl; + } + + const QVector &containers = instantiatedContainers(); + if (!containers.isEmpty()) { + s << "// Container Type converters." << endl << endl; + for (const AbstractMetaType *container : containers) { + s << "// C++ to Python conversion for type '" << container->cppSignature() << "'." << endl; + writeContainerConverterFunctions(s, container); + } + s << endl; + } + + s << "#if defined _WIN32 || defined __CYGWIN__" << endl; + s << " #define SBK_EXPORT_MODULE __declspec(dllexport)" << endl; + s << "#elif __GNUC__ >= 4" << endl; + s << " #define SBK_EXPORT_MODULE __attribute__ ((visibility(\"default\")))" << endl; + s << "#else" << endl; + s << " #define SBK_EXPORT_MODULE" << endl; + s << "#endif" << endl << endl; + + s << "#ifdef IS_PY3K" << endl; + s << "static struct PyModuleDef moduledef = {" << endl; + s << " /* m_base */ PyModuleDef_HEAD_INIT," << endl; + s << " /* m_name */ \"" << moduleName() << "\"," << endl; + s << " /* m_doc */ 0," << endl; + s << " /* m_size */ -1," << endl; + s << " /* m_methods */ " << moduleName() << "_methods," << endl; + s << " /* m_reload */ 0," << endl; + s << " /* m_traverse */ 0," << endl; + s << " /* m_clear */ 0," << endl; + s << " /* m_free */ 0" << endl; + s << "};" << endl << endl; + s << "#endif" << endl; + s << "SBK_MODULE_INIT_FUNCTION_BEGIN(" << moduleName() << ")" << endl; + + ErrorCode errorCode(QLatin1String("SBK_MODULE_INIT_ERROR")); + // module inject-code target/beginning + if (!snips.isEmpty()) { + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode); + s << endl; + } + + for (const QString& requiredModule : requiredModules) { + s << INDENT << "{" << endl; + { + Indentation indentation(INDENT); + s << INDENT << "Shiboken::AutoDecRef requiredModule(Shiboken::Module::import(\"" << requiredModule << "\"));" << endl; + s << INDENT << "if (requiredModule.isNull())" << endl; + { + Indentation indentation(INDENT); + s << INDENT << "return SBK_MODULE_INIT_ERROR;" << endl; + } + s << INDENT << cppApiVariableName(requiredModule) << " = Shiboken::Module::getTypes(requiredModule);" << endl; + s << INDENT << convertersVariableName(requiredModule) << " = Shiboken::Module::getTypeConverters(requiredModule);" << endl; + } + s << INDENT << "}" << endl << endl; + } + + int maxTypeIndex = getMaxTypeIndex() + instantiatedSmartPointers().size(); + if (maxTypeIndex) { + s << INDENT << "// Create an array of wrapper types for the current module." << endl; + s << INDENT << "static PyTypeObject* cppApi[SBK_" << moduleName() << "_IDX_COUNT];" << endl; + s << INDENT << cppApiVariableName() << " = cppApi;" << endl << endl; + } + + s << INDENT << "// Create an array of primitive type converters for the current module." << endl; + s << INDENT << "static SbkConverter* sbkConverters[SBK_" << moduleName() << "_CONVERTERS_IDX_COUNT" << "];" << endl; + s << INDENT << convertersVariableName() << " = sbkConverters;" << endl << endl; + + s << "#ifdef IS_PY3K" << endl; + s << INDENT << "PyObject* module = Shiboken::Module::create(\"" << moduleName() << "\", &moduledef);" << endl; + s << "#else" << endl; + s << INDENT << "PyObject* module = Shiboken::Module::create(\"" << moduleName() << "\", "; + s << moduleName() << "_methods);" << endl; + s << "#endif" << endl << endl; + + //s << INDENT << "// Initialize converters for primitive types." << endl; + //s << INDENT << "initConverters();" << endl << endl; + + s << INDENT << "// Initialize classes in the type system" << endl; + s << classPythonDefines; + + if (!typeConversions.isEmpty()) { + s << endl; + for (const CustomConversion *conversion : typeConversions) { + writePrimitiveConverterInitialization(s, conversion); + s << endl; + } + } + + if (!containers.isEmpty()) { + s << endl; + for (const AbstractMetaType *container : containers) { + writeContainerConverterInitialization(s, container); + s << endl; + } + } + + if (!extendedConverters.isEmpty()) { + s << endl; + for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) { + writeExtendedConverterInitialization(s, it.key(), it.value()); + s << endl; + } + } + + writeEnumsInitialization(s, globalEnums); + + s << INDENT << "// Register primitive types converters." << endl; + const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes(); + for (const PrimitiveTypeEntry *pte : primitiveTypeList) { + if (!pte->generateCode() || !pte->isCppPrimitive()) + continue; + const TypeEntry *referencedType = pte->basicReferencedTypeEntry(); + if (!referencedType) + continue; + QString converter = converterObject(referencedType); + QStringList cppSignature = pte->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts); + while (!cppSignature.isEmpty()) { + QString signature = cppSignature.join(QLatin1String("::")); + s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << signature << "\");" << endl; + cppSignature.removeFirst(); + } + } + // Register type resolver for all containers found in signals. + QSet typeResolvers; + + for (AbstractMetaClass *metaClass : classList) { + if (!metaClass->isQObject() || !metaClass->typeEntry()->generateCode()) + continue; + const AbstractMetaFunctionList &functions = metaClass->functions(); + for (AbstractMetaFunction *func : functions) { + if (func->isSignal()) { + const AbstractMetaArgumentList &arguments = func->arguments(); + for (AbstractMetaArgument *arg : arguments) { + if (arg->type()->isContainer()) { + QString value = translateType(arg->type(), metaClass, ExcludeConst | ExcludeReference); + if (value.startsWith(QLatin1String("::"))) + value.remove(0, 2); + typeResolvers << QMetaObject::normalizedType(value.toUtf8().constData()); + } + } + } + } + } + + s << endl; + if (maxTypeIndex) + s << INDENT << "Shiboken::Module::registerTypes(module, " << cppApiVariableName() << ");" << endl; + s << INDENT << "Shiboken::Module::registerTypeConverters(module, " << convertersVariableName() << ");" << endl; + + s << endl << INDENT << "if (PyErr_Occurred()) {" << endl; + { + Indentation indentation(INDENT); + s << INDENT << "PyErr_Print();" << endl; + s << INDENT << "Py_FatalError(\"can't initialize module " << moduleName() << "\");" << endl; + } + s << INDENT << '}' << endl; + + // module inject-code target/end + if (!snips.isEmpty()) { + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode); + s << endl; + } + + // module inject-code native/end + if (!snips.isEmpty()) { + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode); + s << endl; + } + + if (usePySideExtensions()) { + for (AbstractMetaEnum *metaEnum : qAsConst(globalEnums)) + if (!metaEnum->isAnonymous()) { + s << INDENT << "qRegisterMetaType< ::" << metaEnum->typeEntry()->qualifiedCppName() << " >(\"" << metaEnum->name() << "\");" << endl; + } + + // cleanup staticMetaObject attribute + s << INDENT << "PySide::registerCleanupFunction(cleanTypesAttributes);" << endl; + } + + s << "SBK_MODULE_INIT_FUNCTION_END" << endl; + + return true; +} + +static ArgumentOwner getArgumentOwner(const AbstractMetaFunction* func, int argIndex) +{ + ArgumentOwner argOwner = func->argumentOwner(func->ownerClass(), argIndex); + if (argOwner.index == ArgumentOwner::InvalidIndex) + argOwner = func->argumentOwner(func->declaringClass(), argIndex); + return argOwner; +} + +bool CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, int argIndex, bool useHeuristicPolicy) +{ + const int numArgs = func->arguments().count(); + bool ctorHeuristicEnabled = func->isConstructor() && useCtorHeuristic() && useHeuristicPolicy; + + bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(OverloadData(getFunctionGroups(func->implementingClass())[func->name()], this)); + + ArgumentOwner argOwner = getArgumentOwner(func, argIndex); + ArgumentOwner::Action action = argOwner.action; + int parentIndex = argOwner.index; + int childIndex = argIndex; + if (ctorHeuristicEnabled && argIndex > 0 && numArgs) { + AbstractMetaArgument* arg = func->arguments().at(argIndex-1); + if (arg->name() == QLatin1String("parent") && isObjectType(arg->type())) { + action = ArgumentOwner::Add; + parentIndex = argIndex; + childIndex = -1; + } + } + + QString parentVariable; + QString childVariable; + if (action != ArgumentOwner::Invalid) { + if (!usePyArgs && argIndex > 1) + qCWarning(lcShiboken).noquote().nospace() + << "Argument index for parent tag out of bounds: " << func->signature(); + + if (action == ArgumentOwner::Remove) { + parentVariable = QLatin1String("Py_None"); + } else { + if (parentIndex == 0) { + parentVariable = QLatin1String(PYTHON_RETURN_VAR); + } else if (parentIndex == -1) { + parentVariable = QLatin1String(PYTHON_SELF_VAR); + } else { + parentVariable = usePyArgs + ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(parentIndex - 1) + : QLatin1String(PYTHON_ARG); + } + } + + if (childIndex == 0) { + childVariable = QLatin1String(PYTHON_RETURN_VAR); + } else if (childIndex == -1) { + childVariable = QLatin1String(PYTHON_SELF_VAR); + } else { + childVariable = usePyArgs + ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(childIndex - 1) + : QLatin1String(PYTHON_ARG); + } + + s << INDENT << "Shiboken::Object::setParent(" << parentVariable << ", " << childVariable << ");\n"; + return true; + } + + return false; +} + +void CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool useHeuristicForReturn) +{ + const int numArgs = func->arguments().count(); + + // -1 = return value + // 0 = self + // 1..n = func. args. + for (int i = -1; i <= numArgs; ++i) + writeParentChildManagement(s, func, i, useHeuristicForReturn); + + if (useHeuristicForReturn) + writeReturnValueHeuristics(s, func); +} + +void CppGenerator::writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self) +{ + AbstractMetaType *type = func->type(); + if (!useReturnValueHeuristic() + || !func->ownerClass() + || !type + || func->isStatic() + || func->isConstructor() + || !func->typeReplaced(0).isEmpty()) { + return; + } + + 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; + } +} + +void CppGenerator::writeHashFunction(QTextStream &s, GeneratorContext &context) +{ + const AbstractMetaClass *metaClass = context.metaClass(); + s << "static Py_hash_t " << cpythonBaseName(metaClass) << "_HashFunc(PyObject* self) {" << endl; + writeCppSelfDefinition(s, context); + s << INDENT << "return " << metaClass->typeEntry()->hashFunction() << '('; + s << (isObjectType(metaClass) ? "" : "*") << CPP_SELF_VAR << ");" << endl; + s << '}' << endl << endl; +} + +void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &context) +{ + const AbstractMetaClass *metaClass = context.metaClass(); + ErrorCode errorCode(0); + + // __len__ + s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__(PyObject* " PYTHON_SELF_VAR ")" << endl; + s << '{' << endl; + writeCppSelfDefinition(s, context); + s << INDENT << "return " CPP_SELF_VAR "->size();" << endl; + s << '}' << endl; + + // __getitem__ + s << "PyObject* " << cpythonBaseName(metaClass->typeEntry()) << "__getitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i)" << endl; + s << '{' << endl; + writeCppSelfDefinition(s, context); + writeIndexError(s, QLatin1String("index out of bounds")); + + 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().first(); + + s << INDENT << "return "; + writeToPythonConversion(s, itemType, metaClass, QLatin1String("*_item")); + s << ';' << endl; + s << '}' << endl; + + // __setitem__ + ErrorCode errorCode2(-1); + s << "int " << cpythonBaseName(metaClass->typeEntry()) << "__setitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* pyArg)" << endl; + s << '{' << endl; + writeCppSelfDefinition(s, context); + writeIndexError(s, QLatin1String("list assignment index out of range")); + + s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl; + s << INDENT << "if (!"; + writeTypeCheck(s, itemType, QLatin1String("pyArg"), isNumber(itemType->typeEntry())); + s << ") {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyErr_SetString(PyExc_TypeError, \"attributed value with wrong type, '"; + s << itemType->name() << "' or other convertible type expected\");" << endl; + s << INDENT << "return -1;" << endl; + } + s << INDENT << '}' << endl; + writeArgumentConversion(s, itemType, QLatin1String("cppValue"), QLatin1String("pyArg"), metaClass); + + 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; + s << '}' << endl; +} +void CppGenerator::writeIndexError(QTextStream& s, const QString& errorMsg) +{ + 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 << '}' << endl; +} + +QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &context) +{ + const AbstractMetaClass *metaClass = context.metaClass(); + QString funcName = cpythonBaseName(metaClass) + QLatin1String("__repr__"); + s << "extern \"C\"" << endl; + s << '{' << endl; + s << "static PyObject* " << funcName << "(PyObject* self)" << endl; + s << '{' << endl; + writeCppSelfDefinition(s, context); + 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 << "buffer.close();" << endl; + s << INDENT << "QByteArray str = buffer.data();" << endl; + s << INDENT << "int idx = str.indexOf('(');" << endl; + s << INDENT << "if (idx >= 0)" << endl; + { + Indentation indent(INDENT); + s << INDENT << "str.replace(0, idx, Py_TYPE(self)->tp_name);" << endl; + } + s << INDENT << "PyObject* mod = PyDict_GetItemString(Py_TYPE(self)->tp_dict, \"__module__\");" << endl; + s << INDENT << "if (mod)" << endl; + { + Indentation indent(INDENT); + s << INDENT << "return Shiboken::String::fromFormat(\"<%s.%s at %p>\", Shiboken::String::toCString(mod), str.constData(), self);" << endl; + } + s << INDENT << "else" << endl; + { + Indentation indent(INDENT); + s << INDENT << "return Shiboken::String::fromFormat(\"<%s at %p>\", str.constData(), self);" << endl; + } + s << '}' << endl; + s << "} // extern C" << endl << endl;; + return funcName; +} diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h new file mode 100644 index 000000000..c3ca48307 --- /dev/null +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h @@ -0,0 +1,370 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 CPPGENERATOR_H +#define CPPGENERATOR_H + +#include "shibokengenerator.h" + +/** + * The CppGenerator generate the implementations of C++ bindings classes. + */ +class CppGenerator : public ShibokenGenerator +{ +public: + CppGenerator(); +protected: + QString fileNamePrefix() const override; + QString fileNameForContext(GeneratorContext &context) const override; + QVector filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass, + uint query); + void generateClass(QTextStream& s, GeneratorContext &classContext) override; + bool finishGeneration() override; + +private: + void writeConstructorNative(QTextStream& s, const AbstractMetaFunction* func); + void writeDestructorNative(QTextStream& s, const AbstractMetaClass* metaClass); + + QString getVirtualFunctionReturnTypeName(const AbstractMetaFunction* func); + void writeVirtualMethodNative(QTextStream& s, const AbstractMetaFunction* func); + + void writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass* metaClass); + void writeMetaCast(QTextStream& s, const AbstractMetaClass* metaClass); + + void writeEnumConverterFunctions(QTextStream& s, const TypeEntry* enumType); + void writeEnumConverterFunctions(QTextStream& s, const AbstractMetaEnum* metaEnum); + void writeConverterFunctions(QTextStream &s, const AbstractMetaClass *metaClass, + GeneratorContext &classContext); + void writeCustomConverterFunctions(QTextStream& s, const CustomConversion* customConversion); + void writeConverterRegister(QTextStream &s, const AbstractMetaClass *metaClass, + GeneratorContext &classContext); + void writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar); + void writeContainerConverterRegister(QTextStream& s, const AbstractMetaType* container, const QString& converterVar); + + void writeContainerConverterFunctions(QTextStream& s, const AbstractMetaType* containerType); + + void writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData, + GeneratorContext &context); + void writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, GeneratorContext &classContext); + void writeDestructorWrapper(QTextStream& s, const AbstractMetaClass* metaClass); + void writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, + GeneratorContext &classContext); + void writeArgumentsInitializer(QTextStream& s, OverloadData& overloadData); + void writeCppSelfDefinition(QTextStream &s, + const AbstractMetaFunction *func, + GeneratorContext &context, + bool hasStaticOverload = false); + void writeCppSelfDefinition(QTextStream &s, + GeneratorContext &context, + bool hasStaticOverload = false, + bool cppSelfAsReference = false); + + void writeErrorSection(QTextStream& s, OverloadData& overloadData); + void writeFunctionReturnErrorCheckSection(QTextStream& s, bool hasReturnValue = true); + + /// Writes the check section for the validity of wrapped C++ objects. + void writeInvalidPyObjectCheck(QTextStream& s, const QString& pyObj); + + void writeTypeCheck(QTextStream& s, const AbstractMetaType* argType, QString argumentName, bool isNumber = false, QString customType = QString(), bool rejectNull = false); + void writeTypeCheck(QTextStream& s, const OverloadData* overloadData, QString argumentName); + + void writeTypeDiscoveryFunction(QTextStream& s, const AbstractMetaClass* metaClass); + + void writeSetattroFunction(QTextStream &s, GeneratorContext &context); + void writeGetattroFunction(QTextStream &s, GeneratorContext &context); + QString writeSmartPointerGetterCast(); + + /** + * Writes Python to C++ conversions for arguments on Python wrappers. + * If implicit conversions, and thus new object allocation, are needed, + * code to deallocate a possible new instance is also generated. + * \param s text stream to write + * \param argType a pointer to the argument type to be converted + * \param argName C++ argument name + * \param pyArgName Python argument name + * \param context the current meta class + * \param defaultValue an optional default value to be used instead of the conversion result + * \param castArgumentAsUnused if true the converted argument is cast as unused to avoid compiler warnings + */ + void writeArgumentConversion(QTextStream& s, const AbstractMetaType* argType, + const QString& argName, const QString& pyArgName, + const AbstractMetaClass* context = 0, + const QString& defaultValue = QString(), + bool castArgumentAsUnused = false); + + /** + * Returns the AbstractMetaType for a function argument. + * If the argument type was modified in the type system, this method will + * try to build a new type based on the type name defined in the type system. + * \param func The function which owns the argument. + * \param argPos Argument position in the function signature. + * Note that the position 0 represents the return value, and the function + * parameters start counting on 1. + * \param newType It is set to true if the type returned is a new object that must be deallocated. + * \return The type of the argument indicated by \p argPos. + */ + const AbstractMetaType* getArgumentType(const AbstractMetaFunction* func, int argPos); + + void writePythonToCppTypeConversion(QTextStream& s, + const AbstractMetaType* type, + const QString& pyIn, + const QString& cppOut, + const AbstractMetaClass* context = 0, + const QString& defaultValue = QString()); + + /// Writes the conversion rule for arguments of regular and virtual methods. + void writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language); + /// Writes the conversion rule for the return value of a method. + void writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language, const QString& outputVar); + + /** + * Set the Python method wrapper return value variable to Py_None if + * there are return types different from void in any of the other overloads + * for the function passed as parameter. + * \param s text stream to write + * \param func a pointer to the function that will possibly return Py_None + * \param thereIsReturnValue indicates if the return type of any of the other overloads + * for this function is different from 'void' + */ + void writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue); + + /** + * Writes the Python function wrapper overload decisor that selects which C++ + * method/function to call with the received Python arguments. + * \param s text stream to write + * \param overloadData the overload data describing all the possible overloads for the function/method + */ + void writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData); + /// Recursive auxiliar method to the other writeOverloadedFunctionDecisor. + void writeOverloadedFunctionDecisorEngine(QTextStream& s, const OverloadData* parentOverloadData); + + /// Writes calls to all the possible method/function overloads. + void writeFunctionCalls(QTextStream &s, + const OverloadData &overloadData, + GeneratorContext &context); + + /// Writes the call to a single function usually from a collection of overloads. + void writeSingleFunctionCall(QTextStream &s, + const OverloadData &overloadData, + const AbstractMetaFunction *func, + GeneratorContext &context); + + /// Returns the name of a C++ to Python conversion function. + static QString cppToPythonFunctionName(const QString& sourceTypeName, QString targetTypeName = QString()); + + /// Returns the name of a Python to C++ conversion function. + static QString pythonToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName); + static QString pythonToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType); + static QString pythonToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative, const TypeEntry* targetType); + + /// Returns the name of a Python to C++ convertible check function. + static QString convertibleToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName); + static QString convertibleToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType); + static QString convertibleToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative, const TypeEntry* targetType); + + /// Writes a C++ to Python conversion function. + void writeCppToPythonFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, QString targetTypeName = QString()); + void writeCppToPythonFunction(QTextStream& s, const CustomConversion* customConversion); + void writeCppToPythonFunction(QTextStream& s, const AbstractMetaType* containerType); + + /// Writes a Python to C++ conversion function. + void writePythonToCppFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, const QString& targetTypeName); + + /// Writes a Python to C++ convertible check function. + void writeIsPythonConvertibleToCppFunction(QTextStream& s, + const QString& sourceTypeName, + const QString& targetTypeName, + const QString& condition, + QString pythonToCppFuncName = QString(), + bool acceptNoneAsCppNull = false); + + /// Writes a pair of Python to C++ conversion and check functions. + void writePythonToCppConversionFunctions(QTextStream& s, + const AbstractMetaType* sourceType, + const AbstractMetaType* targetType, + QString typeCheck = QString(), + QString conversion = QString(), + QString preConversion = QString()); + /// Writes a pair of Python to C++ conversion and check functions for implicit conversions. + void writePythonToCppConversionFunctions(QTextStream& s, + const CustomConversion::TargetToNativeConversion* toNative, + const TypeEntry* targetType); + + /// Writes a pair of Python to C++ conversion and check functions for instantiated container types. + void writePythonToCppConversionFunctions(QTextStream& s, const AbstractMetaType* containerType); + + void writeAddPythonToCppConversion(QTextStream& s, const QString& converterVar, const QString& pythonToCppFunc, const QString& isConvertibleFunc); + + void writeNamedArgumentResolution(QTextStream& s, const AbstractMetaFunction* func, bool usePyArgs); + + /// Returns a string containing the name of an argument for the given function and argument index. + QString argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass); + void writeMethodCall(QTextStream &s, const AbstractMetaFunction *func, + GeneratorContext &context, int maxArgs = 0); + + QString getInitFunctionName(GeneratorContext &context) const; + + void writeClassRegister(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &classContext); + void writeClassDefinition(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &classContext); + void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads); + void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads); + + /// Writes the implementation of all methods part of python sequence protocol + void writeSequenceMethods(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &context); + void writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass); + + /// Writes the PyMappingMethods structure for types that supports the python mapping protocol. + void writeTypeAsMappingDefinition(QTextStream& s, const AbstractMetaClass* metaClass); + void writeMappingMethods(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &context); + + void writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass); + + void writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass); + void writeTpClearFunction(QTextStream& s, const AbstractMetaClass* metaClass); + + void writeCopyFunction(QTextStream &s, GeneratorContext &context); + + void writeGetterFunction(QTextStream &s, + const AbstractMetaField *metaField, + GeneratorContext &context); + void writeSetterFunction(QTextStream &s, + const AbstractMetaField *metaField, + GeneratorContext &context); + + void writeRichCompareFunction(QTextStream &s, GeneratorContext &context); + void writeToPythonFunction(QTextStream& s, const AbstractMetaClass* metaClass); + + void writeEnumsInitialization(QTextStream& s, AbstractMetaEnumList& enums); + void writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum); + + void writeSignalInitialization(QTextStream& s, const AbstractMetaClass* metaClass); + + void writeFlagsMethods(QTextStream& s, const AbstractMetaEnum* cppEnum); + void writeFlagsToLong(QTextStream& s, const AbstractMetaEnum* cppEnum); + 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); + void writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum, + QString pyOpName, 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); + /// Writes the implementation of special cast functions, used when we need to cast a class with multiple inheritance. + void writeSpecialCastFunction(QTextStream& s, const AbstractMetaClass* metaClass); + + void writePrimitiveConverterInitialization(QTextStream& s, const CustomConversion* customConversion); + void writeEnumConverterInitialization(QTextStream& s, const TypeEntry* enumType); + void writeEnumConverterInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum); + void writeContainerConverterInitialization(QTextStream& s, const AbstractMetaType* type); + void writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType, const QVector& conversions); + + void writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool userHeuristicForReturn); + bool writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, int argIndex, bool userHeuristicPolicy); + void writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self = QLatin1String(PYTHON_SELF_VAR)); + void writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const; + + /** + * Returns the multiple inheritance initializer function for the given class. + * \param metaClass the class for whom the function name must be generated. + * \return name of the multiple inheritance information initializer function or + * an empty string if there is no multiple inheritance in its ancestry. + */ + QString multipleInheritanceInitializerFunctionName(const AbstractMetaClass* metaClass); + + /// Returns a list of all classes to which the given class could be cast. + QStringList getAncestorMultipleInheritance(const AbstractMetaClass* metaClass); + + /// Returns true if the given class supports the python number protocol + bool supportsNumberProtocol(const AbstractMetaClass* metaClass); + + /// Returns true if the given class supports the python sequence protocol + bool supportsSequenceProtocol(const AbstractMetaClass* metaClass); + + /// Returns true if the given class supports the python mapping protocol + bool supportsMappingProtocol(const AbstractMetaClass* metaClass); + + /// Returns true if generator should produce getters and setters for the given class. + bool shouldGenerateGetSetList(const AbstractMetaClass* metaClass); + + void writeHashFunction(QTextStream &s, GeneratorContext &context); + + /// Write default implementations for sequence protocol + void writeStdListWrapperMethods(QTextStream &s, GeneratorContext &context); + /// Helper function for writeStdListWrapperMethods. + void writeIndexError(QTextStream& s, const QString& errorMsg); + + QString writeReprFunction(QTextStream &s, GeneratorContext &context); + + bool hasBoolCast(const AbstractMetaClass* metaClass) const; + + // Number protocol structure members names. + static QHash m_nbFuncs; + + // Maps special function names to function parameters and return types + // used by CPython API in the sequence protocol. + QHash > m_sequenceProtocol; + // Sequence protocol structure members names. + static QHash m_sqFuncs; + + // Maps special function names to function parameters and return types + // used by CPython API in the mapping protocol. + QHash > m_mappingProtocol; + // Mapping protocol structure members names. + static QHash m_mpFuncs; + + static QString m_currentErrorCode; + + /// Helper class to set and restore the current error code. + class ErrorCode { + public: + explicit ErrorCode(QString errorCode) { + m_savedErrorCode = CppGenerator::m_currentErrorCode; + CppGenerator::m_currentErrorCode = errorCode; + } + explicit ErrorCode(int errorCode) { + m_savedErrorCode = CppGenerator::m_currentErrorCode; + CppGenerator::m_currentErrorCode = QString::number(errorCode); + } + ~ErrorCode() { + CppGenerator::m_currentErrorCode = m_savedErrorCode; + } + private: + QString m_savedErrorCode; + }; +}; + +#endif // CPPGENERATOR_H diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp new file mode 100644 index 000000000..6b8185dc9 --- /dev/null +++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp @@ -0,0 +1,569 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "headergenerator.h" +#include +#include +#include +#include + +#include +#include +#include +#include + +QString HeaderGenerator::fileNamePrefix() const +{ + return QLatin1String("_wrapper.h"); +} + +QString HeaderGenerator::fileNameForContext(GeneratorContext &context) const +{ + const AbstractMetaClass *metaClass = context.metaClass(); + if (!context.forSmartPointer()) { + QString fileNameBase = metaClass->qualifiedCppName().toLower(); + fileNameBase.replace(QLatin1String("::"), QLatin1String("_")); + return fileNameBase + fileNamePrefix(); + } else { + const AbstractMetaType *smartPointerType = context.preciseType(); + QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass); + return fileNameBase + fileNamePrefix(); + } +} + +void HeaderGenerator::writeCopyCtor(QTextStream& s, const AbstractMetaClass* metaClass) const +{ + s << INDENT << wrapperName(metaClass) << "(const " << metaClass->qualifiedCppName() << "& self)"; + s << " : " << metaClass->qualifiedCppName() << "(self)" << endl; + s << INDENT << "{" << endl; + s << INDENT << "}" << endl << endl; +} + +void HeaderGenerator::writeProtectedFieldAccessors(QTextStream& s, const AbstractMetaField* field) const +{ + AbstractMetaType *metaType = field->type(); + QString fieldType = metaType->cppSignature(); + QString fieldName = field->enclosingClass()->qualifiedCppName() + QLatin1String("::") + field->name(); + + // Force use of pointer to return internal variable memory + bool useReference = (!metaType->isConstant() && + !metaType->isEnum() && + !metaType->isPrimitive() && + metaType->indirections() == 0); + + + // Get function + s << INDENT << "inline " << fieldType + << (useReference ? '*' : ' ') + << ' ' << protectedFieldGetterName(field) << "()" + << " { return " + << (useReference ? '&' : ' ') << "this->" << fieldName << "; }" << endl; + + // Set function + s << INDENT << "inline void " << protectedFieldSetterName(field) << '(' << fieldType << " value)" + << " { " << fieldName << " = value; }" << endl; +} + +void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) +{ + AbstractMetaClass *metaClass = classContext.metaClass(); + if (ReportHandler::isDebug(ReportHandler::SparseDebug)) + qCDebug(lcShiboken) << "Generating header for " << metaClass->fullName(); + m_inheritedOverloads.clear(); + Indentation indent(INDENT); + + // write license comment + s << licenseComment(); + + QString wrapperName; + if (!classContext.forSmartPointer()) { + wrapperName = HeaderGenerator::wrapperName(metaClass); + } else { + wrapperName = HeaderGenerator::wrapperName(classContext.preciseType()); + } + QString headerGuard = getFilteredCppSignatureString(wrapperName).toUpper(); + + // Header + s << "#ifndef SBK_" << headerGuard << "_H" << endl; + s << "#define SBK_" << headerGuard << "_H" << endl<< endl; + + if (!avoidProtectedHack()) + s << "#define protected public" << endl << endl; + + s << "#include " << endl << endl; + + //Includes + s << metaClass->typeEntry()->include() << endl; + + if (shouldGenerateCppWrapper(metaClass)) { + + if (usePySideExtensions() && metaClass->isQObject()) + s << "namespace PySide { class DynamicQMetaObject; }\n\n"; + + // Class + s << "class " << wrapperName; + s << " : public " << metaClass->qualifiedCppName(); + + s << endl << '{' << endl << "public:" << endl; + + bool hasVirtualFunction = false; + const AbstractMetaFunctionList &funcs = filterFunctions(metaClass); + for (AbstractMetaFunction *func : funcs) { + if (func->isVirtual()) + hasVirtualFunction = true; + writeFunction(s, func); + } + + if (avoidProtectedHack() && metaClass->hasProtectedFields()) { + const AbstractMetaFieldList &fields = metaClass->fields(); + for (AbstractMetaField *field : fields) { + if (!field->isProtected()) + continue; + writeProtectedFieldAccessors(s, field); + } + } + + //destructor + // PYSIDE-504: When C++ 11 is used, then the destructor must always be written. + // See generator.h for further reference. + if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor() || alwaysGenerateDestructor) { + s << INDENT; + if (avoidProtectedHack() && metaClass->hasPrivateDestructor()) + s << "// C++11: need to declare (unimplemented) destructor because " + "the base class destructor is private." << endl; + if (metaClass->hasVirtualDestructor() || hasVirtualFunction) + s << "virtual "; + s << '~' << wrapperName << "();" << endl; + } + + writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode); + + if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) + && usePySideExtensions() && metaClass->isQObject()) { + s << "public:\n"; + s << INDENT << "virtual int qt_metacall(QMetaObject::Call call, int id, void** args);" << endl; + s << INDENT << "virtual void* qt_metacast(const char* _clname);" << endl; + } + + if (m_inheritedOverloads.size()) { + s << INDENT << "// Inherited overloads, because the using keyword sux" << endl; + writeInheritedOverloads(s); + } + + if (usePySideExtensions()) + s << INDENT << "static void pysideInitQtMetaTypes();" << endl; + + s << "};" << endl << endl; + } + + s << "#endif // SBK_" << headerGuard << "_H" << endl << endl; +} + +void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction* func) +{ + + // do not write copy ctors here. + if (!func->isPrivate() && func->functionType() == AbstractMetaFunction::CopyConstructorFunction) { + writeCopyCtor(s, func->ownerClass()); + return; + } + if (func->isUserAdded()) + return; + + if (avoidProtectedHack() && func->isProtected() && !func->isConstructor() && !func->isOperatorOverload()) { + s << INDENT << "inline " << (func->isStatic() ? "static " : ""); + s << functionSignature(func, QString(), QLatin1String("_protected"), Generator::EnumAsInts|Generator::OriginalTypeDescription) + << " { "; + s << (func->type() ? "return " : ""); + if (!func->isAbstract()) + s << func->ownerClass()->qualifiedCppName() << "::"; + s << func->originalName() << '('; + QStringList args; + const AbstractMetaArgumentList &arguments = func->arguments(); + for (const AbstractMetaArgument *arg : arguments) { + QString argName = arg->name(); + const TypeEntry* enumTypeEntry = 0; + if (arg->type()->isFlags()) + enumTypeEntry = reinterpret_cast(arg->type()->typeEntry())->originator(); + else if (arg->type()->isEnum()) + enumTypeEntry = arg->type()->typeEntry(); + if (enumTypeEntry) + argName = QString::fromLatin1("%1(%2)").arg(arg->type()->cppSignature(), argName); + args << argName; + } + s << args.join(QLatin1String(", ")) << ')'; + s << "; }" << endl; + } + + // pure virtual functions need a default implementation + if ((func->isPrivate() && !visibilityModifiedToPrivate(func)) + || (func->isModifiedRemoved() && !func->isAbstract())) + return; + + if (avoidProtectedHack() && func->ownerClass()->hasPrivateDestructor() + && (func->isAbstract() || func->isVirtual())) + return; + + if (func->isConstructor() || func->isAbstract() || func->isVirtual()) { + s << INDENT; + Options virtualOption = Generator::OriginalTypeDescription; + + if (func->isVirtual() || func->isAbstract()) + s << "virtual "; + else if (!func->hasSignatureModifications()) + virtualOption = Generator::NoOption; + + s << functionSignature(func, QString(), QString(), virtualOption) << ';' << endl; + + // Check if this method hide other methods in base classes + const AbstractMetaFunctionList &ownerFuncs = func->ownerClass()->functions(); + for (const AbstractMetaFunction *f : ownerFuncs) { + if (f != func + && !f->isConstructor() + && !f->isPrivate() + && !f->isVirtual() + && !f->isAbstract() + && !f->isStatic() + && f->name() == func->name()) { + m_inheritedOverloads << f; + } + } + + // TODO: when modified an abstract method ceases to be virtual but stays abstract + //if (func->isModifiedRemoved() && func->isAbstract()) { + //} + } +} + +static void _writeTypeIndexDefineLine(QTextStream& s, const QString& variableName, int typeIndex) +{ + s << "#define "; + s.setFieldWidth(60); + s << variableName; + s.setFieldWidth(0); + s << ' ' << typeIndex << endl; +} +void HeaderGenerator::writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry) +{ + if (!typeEntry || !typeEntry->generateCode()) + return; + s.setFieldAlignment(QTextStream::AlignLeft); + int typeIndex = getTypeIndex(typeEntry); + _writeTypeIndexDefineLine(s, getTypeIndexVariableName(typeEntry), typeIndex); + if (typeEntry->isComplex()) { + const ComplexTypeEntry* cType = reinterpret_cast(typeEntry); + if (cType->baseContainerType()) { + const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), cType); + if (metaClass->templateBaseClass()) + _writeTypeIndexDefineLine(s, getTypeIndexVariableName(metaClass, true), typeIndex); + } + } + if (typeEntry->isEnum()) { + const EnumTypeEntry* ete = reinterpret_cast(typeEntry); + if (ete->flags()) + writeTypeIndexDefineLine(s, ete->flags()); + } +} + +void HeaderGenerator::writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass) +{ + if (!metaClass->typeEntry()->generateCode()) + return; + writeTypeIndexDefineLine(s, metaClass->typeEntry()); + const AbstractMetaEnumList &enums = metaClass->enums(); + for (const AbstractMetaEnum *metaEnum : enums) { + if (metaEnum->isPrivate()) + continue; + writeTypeIndexDefineLine(s, metaEnum->typeEntry()); + } +} + +bool HeaderGenerator::finishGeneration() +{ + // Generate the main header for this module. + // This header should be included by binding modules + // extendind on top of this one. + QSet includes; + QString macros; + QTextStream macrosStream(¯os); + QString sbkTypeFunctions; + QTextStream typeFunctions(&sbkTypeFunctions); + QString protectedEnumSurrogates; + QTextStream protEnumsSurrogates(&protectedEnumSurrogates); + + Indentation indent(INDENT); + + macrosStream << "// Type indices" << endl; + AbstractMetaEnumList globalEnums = this->globalEnums(); + const AbstractMetaClassList &classList = classes(); + for (const AbstractMetaClass *metaClass : classList) { + writeTypeIndexDefine(macrosStream, metaClass); + lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass); + } + + for (const AbstractMetaEnum *metaEnum : qAsConst(globalEnums)) + writeTypeIndexDefineLine(macrosStream, metaEnum->typeEntry()); + + // Write the smart pointer define indexes. + int smartPointerCountIndex = getMaxTypeIndex(); + int smartPointerCount = 0; + const QVector &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; + ++smartPointerCountIndex; + ++smartPointerCount; + } + + + 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 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; + const PrimitiveTypeEntryList &primitives = primitiveTypes(); + int pCount = 0; + for (const PrimitiveTypeEntry *ptype : primitives) { + /* Note: do not generate indices for typedef'd primitive types + * as they'll use the primitive type converters instead, so we + * don't need to create any other. + */ + if (!ptype->generateCode() || !ptype->customConversion()) + continue; + + _writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(ptype), pCount++); + } + + const QVector &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 + 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; + // TODO-CONVERTER ------------------------------------------------------------------------------ + + macrosStream << "// Macros for type check" << endl; + for (const AbstractMetaEnum *cppEnum : globalEnums) { + if (cppEnum->isAnonymous() || cppEnum->isPrivate()) + continue; + includes << cppEnum->typeEntry()->include(); + writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum); + writeSbkTypeFunction(typeFunctions, cppEnum); + } + + for (AbstractMetaClass *metaClass : classList) { + if (!shouldGenerate(metaClass)) + continue; + + //Includes + const TypeEntry* classType = metaClass->typeEntry(); + includes << classType->include(); + + const AbstractMetaEnumList &enums = metaClass->enums(); + for (const AbstractMetaEnum *cppEnum : enums) { + if (cppEnum->isAnonymous() || cppEnum->isPrivate()) + continue; + EnumTypeEntry* enumType = cppEnum->typeEntry(); + includes << enumType->include(); + writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum); + writeSbkTypeFunction(typeFunctions, cppEnum); + } + + if (!metaClass->isNamespace()) + writeSbkTypeFunction(typeFunctions, metaClass); + } + + for (const AbstractMetaType *metaType : instantiatedSmartPtrs) { + const TypeEntry *classType = metaType->typeEntry(); + includes << classType->include(); + writeSbkTypeFunction(typeFunctions, metaType); + } + + QString moduleHeaderFileName(outputDirectory() + + QDir::separator() + subDirectoryForPackage(packageName()) + + QDir::separator() + getModuleHeaderFileName()); + + QString includeShield(QLatin1String("SBK_") + moduleName().toUpper() + QLatin1String("_PYTHON_H")); + + FileOut file(moduleHeaderFileName); + QTextStream& s = file.stream; + // write license comment + s << licenseComment() << endl << endl; + + s << "#ifndef " << includeShield << endl; + s << "#define " << includeShield << endl<< endl; + if (!avoidProtectedHack()) { + s << "//workaround to access protected functions" << endl; + s << "#define protected public" << endl << endl; + } + + s << "#include " << endl; + s << "#include " << endl; + s << "#include " << endl; + s << "#include " << endl; + s << "#include " << endl; + s << "#include " << endl << endl; + if (usePySideExtensions()) + s << "#include " << endl; + + QStringList requiredTargetImports = TypeDatabase::instance()->requiredTargetImports(); + if (!requiredTargetImports.isEmpty()) { + s << "// Module Includes" << endl; + for (const QString &requiredModule : qAsConst(requiredTargetImports)) + s << "#include <" << getModuleHeaderFileName(requiredModule) << ">" << endl; + s << endl; + } + + s << "// Binded library includes" << endl; + for (const Include &include : qAsConst(includes)) + s << include; + + if (!primitiveTypes().isEmpty()) { + s << "// Conversion Includes - Primitive Types" << endl; + const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes(); + for (const PrimitiveTypeEntry *ptype : primitiveTypeList) + s << ptype->include(); + s << endl; + } + + if (!containerTypes().isEmpty()) { + s << "// Conversion Includes - Container Types" << endl; + const ContainerTypeEntryList &containerTypeList = containerTypes(); + for (const ContainerTypeEntry *ctype : containerTypeList) + s << ctype->include(); + s << endl; + } + + s << macros << endl; + + if (!protectedEnumSurrogates.isEmpty()) { + s << "// Protected enum surrogates" << endl; + s << protectedEnumSurrogates << endl; + } + + s << "namespace Shiboken" << endl << '{' << endl << endl; + + s << "// PyType functions, to get the PyObjectType for a type T\n"; + s << sbkTypeFunctions << endl; + + s << "} // namespace Shiboken" << endl << endl; + + s << "#endif // " << includeShield << endl << endl; + + return file.done() != FileOut::Failure; +} + +void HeaderGenerator::writeProtectedEnumSurrogate(QTextStream& s, const AbstractMetaEnum* cppEnum) +{ + if (avoidProtectedHack() && cppEnum->isProtected()) + s << "enum " << protectedEnumSurrogateName(cppEnum) << " {};" << endl; +} + +void HeaderGenerator::writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum) +{ + QString enumName; + if (avoidProtectedHack() && cppEnum->isProtected()) { + enumName = protectedEnumSurrogateName(cppEnum); + } else { + enumName = cppEnum->name(); + if (cppEnum->enclosingClass()) + enumName = cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::") + enumName; + } + + s << "template<> inline PyTypeObject* SbkType< ::" << enumName << " >() "; + s << "{ return " << cpythonTypeNameExt(cppEnum->typeEntry()) << "; }\n"; + + FlagsTypeEntry* flag = cppEnum->typeEntry()->flags(); + if (flag) { + s << "template<> inline PyTypeObject* SbkType< ::" << flag->name() << " >() " + << "{ return " << cpythonTypeNameExt(flag) << "; }\n"; + } +} + +void HeaderGenerator::writeSbkTypeFunction(QTextStream& s, const AbstractMetaClass* cppClass) +{ + s << "template<> inline PyTypeObject* SbkType< ::" << cppClass->qualifiedCppName() << " >() " + << "{ return reinterpret_cast(" << cpythonTypeNameExt(cppClass->typeEntry()) << "); }\n"; +} + +void HeaderGenerator::writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType) +{ + s << "template<> inline PyTypeObject* SbkType< ::" << metaType->cppSignature() << " >() " + << "{ return reinterpret_cast(" << cpythonTypeNameExt(metaType) << "); }\n"; +} + +void HeaderGenerator::writeInheritedOverloads(QTextStream& s) +{ + for (const AbstractMetaFunction *func : qAsConst(m_inheritedOverloads)) { + s << INDENT << "inline "; + s << functionSignature(func, QString(), QString(), Generator::EnumAsInts|Generator::OriginalTypeDescription) << " { "; + s << (func->type() ? "return " : ""); + s << func->ownerClass()->qualifiedCppName() << "::" << func->originalName() << '('; + QStringList args; + const AbstractMetaArgumentList &arguments = func->arguments(); + for (const AbstractMetaArgument *arg : arguments) { + QString argName = arg->name(); + const TypeEntry* enumTypeEntry = 0; + if (arg->type()->isFlags()) + enumTypeEntry = reinterpret_cast(arg->type()->typeEntry())->originator(); + else if (arg->type()->isEnum()) + enumTypeEntry = arg->type()->typeEntry(); + if (enumTypeEntry) + argName = arg->type()->cppSignature() + QLatin1Char('(') + argName + QLatin1Char(')'); + args << argName; + } + s << args.join(QLatin1String(", ")) << ')'; + s << "; }" << endl; + } +} diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.h b/sources/shiboken2/generator/shiboken2/headergenerator.h new file mode 100644 index 000000000..5c1ffec35 --- /dev/null +++ b/sources/shiboken2/generator/shiboken2/headergenerator.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 HEADERGENERATOR_H +#define HEADERGENERATOR_H + +#include "shibokengenerator.h" + +#include + +class AbstractMetaFunction; + +/** + * The HeaderGenerator generate the declarations of C++ bindings classes. + */ +class HeaderGenerator : public ShibokenGenerator +{ +public: + QMap options() const override { return QMap(); } +protected: + QString fileNamePrefix() const override; + QString fileNameForContext(GeneratorContext &context) const override; + void generateClass(QTextStream& s, GeneratorContext &classContext) override; + bool finishGeneration() override; + +private: + void writeCopyCtor(QTextStream &s, const AbstractMetaClass* metaClass) const; + void writeProtectedFieldAccessors(QTextStream& s, const AbstractMetaField* field) const; + void writeFunction(QTextStream& s, const AbstractMetaFunction* func); + void writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum); + void writeSbkTypeFunction(QTextStream& s, const AbstractMetaClass* cppClass); + void writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType); + void writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry); + void writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass); + void writeProtectedEnumSurrogate(QTextStream& s, const AbstractMetaEnum* cppEnum); + void writeInheritedOverloads(QTextStream& s); + + QSet m_inheritedOverloads; +}; + +#endif // HEADERGENERATOR_H + diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp new file mode 100644 index 000000000..876185cbe --- /dev/null +++ b/sources/shiboken2/generator/shiboken2/overloaddata.cpp @@ -0,0 +1,1092 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 +#include +#include +#include "overloaddata.h" +#include "shibokengenerator.h" + +#include +#include +#include + +static const TypeEntry *getReferencedTypeEntry(const TypeEntry *typeEntry) +{ + if (typeEntry->isPrimitive()) { + const PrimitiveTypeEntry* pte = dynamic_cast(typeEntry); + while (pte->referencedTypeEntry()) + pte = pte->referencedTypeEntry(); + typeEntry = pte; + } + return typeEntry; +} + +static QString getTypeName(const AbstractMetaType* type) +{ + const TypeEntry* typeEntry = getReferencedTypeEntry(type->typeEntry()); + QString typeName = typeEntry->name(); + if (typeEntry->isContainer()) { + QStringList types; + const AbstractMetaTypeList &instantiations = type->instantiations(); + for (const AbstractMetaType *cType : instantiations) { + const TypeEntry *typeEntry = getReferencedTypeEntry(cType->typeEntry()); + types << typeEntry->name(); + } + typeName += QLatin1Char('<') + types.join(QLatin1Char(',')) + QLatin1String(" >"); + } + return typeName; +} + +static QString getTypeName(const OverloadData* ov) +{ + return ov->hasArgumentTypeReplace() ? ov->argumentTypeReplaced() : getTypeName(ov->argType()); +} + +static bool typesAreEqual(const AbstractMetaType* typeA, const AbstractMetaType* typeB) +{ + if (typeA->typeEntry() == typeB->typeEntry()) { + if (typeA->isContainer() || typeA->isSmartPointer()) { + if (typeA->instantiations().size() != typeB->instantiations().size()) + return false; + + for (int i = 0; i < typeA->instantiations().size(); ++i) { + if (!typesAreEqual(typeA->instantiations().at(i), typeB->instantiations().at(i))) + return false; + } + return true; + } + + return !(ShibokenGenerator::isCString(typeA) ^ ShibokenGenerator::isCString(typeB)); + } + return false; +} + + +/** + * OverloadSortData just helps writing clearer code in the + * OverloadData::sortNextOverloads method. + */ +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 + * or could not appear in overloaded signatures not processed yet. + */ + void mapType(const QString& typeName) + { + if (map.contains(typeName)) + return; + map[typeName] = counter; + if (!reverseMap.contains(counter)) + reverseMap[counter] = 0; + counter++; + } + + void mapType(OverloadData* overloadData) + { + QString typeName = getTypeName(overloadData); + map[typeName] = counter; + reverseMap[counter] = overloadData; + counter++; + } + + int lastProcessedItemId() { return counter - 1; } + + int counter; + QHash map; // typeName -> id + QHash reverseMap; // id -> OverloadData; +}; + +/** + * Helper function that returns the name of a container get from containerType argument and + * an instantiation taken either from an implicit conversion expressed by the function argument, + * or from the string argument implicitConvTypeName. + */ +static QString getImplicitConversionTypeName(const AbstractMetaType* containerType, + const AbstractMetaType* instantiation, + const AbstractMetaFunction* function, + const QString& implicitConvTypeName = QString()) +{ + QString impConv; + if (!implicitConvTypeName.isEmpty()) + impConv = implicitConvTypeName; + else if (function->isConversionOperator()) + impConv = function->ownerClass()->typeEntry()->name(); + else + impConv = getTypeName(function->arguments().first()->type()); + + QStringList types; + const AbstractMetaTypeList &instantiations = containerType->instantiations(); + for (const AbstractMetaType *otherType : instantiations) + types << (otherType == instantiation ? impConv : getTypeName(otherType)); + + const ContainerTypeEntry* containerTypeEntry = dynamic_cast(containerType->typeEntry()); + return containerTypeEntry->qualifiedCppName() + QLatin1Char('<') + + types.join(QLatin1String(", ")) + QLatin1String(" >"); +} + +static QString msgCyclicDependency(const QString &funcName, const QString &graphName, + const OverloadData::MetaFunctionList &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; +} + +/** + * Topologically sort the overloads by implicit convertion order + * + * This avoids using an implicit conversion if there's an explicit + * overload for the convertible type. So, if there's an implicit convert + * like TargetType(ConvertibleType foo) and both are in the overload list, + * ConvertibleType is checked before TargetType. + * + * Side effects: Modifies m_nextOverloadData + */ +void OverloadData::sortNextOverloads() +{ + OverloadSortData sortData; + bool checkPyObject = false; + int pyobjectIndex = 0; + bool checkPySequence = false; + int pySeqIndex = 0; + bool checkQString = false; + int qstringIndex = 0; + bool checkQVariant = false; + int qvariantIndex = 0; + bool checkPyBuffer = false; + int pyBufferIndex = 0; + + // Primitive types that are not int, long, short, + // char and their respective unsigned counterparts. + QStringList nonIntegerPrimitives; + nonIntegerPrimitives << QLatin1String("float") << QLatin1String("double") + << QLatin1String("bool"); + + // Signed integer primitive types. + QStringList signedIntegerPrimitives; + signedIntegerPrimitives << QLatin1String("int") << QLatin1String("short") + << QLatin1String("long"); + + // sort the children overloads + for (OverloadData *ov : m_nextOverloadData) + ov->sortNextOverloads(); + + if (m_nextOverloadData.size() <= 1) + return; + + // Populates the OverloadSortData object containing map and reverseMap, to map type names to ids, + // these ids will be used by the topological sort algorithm, because is easier and faster to work + // with graph sorting using integers. + for (OverloadData *ov : m_nextOverloadData) { + sortData.mapType(ov); + + const QString typeName(getTypeName(ov)); + + if (!checkPyObject && typeName.contains(QLatin1String("PyObject"))) { + checkPyObject = true; + pyobjectIndex = sortData.lastProcessedItemId(); + } else if (!checkPySequence && typeName == QLatin1String("PySequence")) { + checkPySequence = true; + pySeqIndex = sortData.lastProcessedItemId(); + } else if (!checkPyBuffer && typeName == QLatin1String("PyBuffer")) { + checkPyBuffer = true; + pyBufferIndex = sortData.lastProcessedItemId(); + } else if (!checkQVariant && typeName == QLatin1String("QVariant")) { + checkQVariant = true; + qvariantIndex = sortData.lastProcessedItemId(); + } else if (!checkQString && typeName == QLatin1String("QString")) { + checkQString = true; + qstringIndex = sortData.lastProcessedItemId(); + } + + const AbstractMetaTypeList &instantiations = ov->argType()->instantiations(); + for (const AbstractMetaType *instantiation : instantiations) { + // Add dependencies for type instantiation of container. + QString typeName = getTypeName(instantiation); + sortData.mapType(typeName); + + // Build dependency for implicit conversion types instantiations for base container. + // For example, considering signatures "method(list)" and "method(list)", + // and being PointF implicitly convertible from Point, an list instantiation with T + // as Point must come before the PointF instantiation, or else list will never + // be called. In the case of primitive types, list must come before list. + if (instantiation->isPrimitive() && (signedIntegerPrimitives.contains(instantiation->name()))) { + for (const QString &primitive : qAsConst(nonIntegerPrimitives)) + sortData.mapType(getImplicitConversionTypeName(ov->argType(), instantiation, 0, primitive)); + } else { + const AbstractMetaFunctionList &funcs = m_generator->implicitConversions(instantiation); + for (const AbstractMetaFunction *function : funcs) + sortData.mapType(getImplicitConversionTypeName(ov->argType(), instantiation, function)); + } + } + } + + + // Create the graph of type dependencies based on implicit conversions. + Graph graph(sortData.reverseMap.count()); + // All C++ primitive types, add any forgotten type AT THE END OF THIS LIST! + const char* primitiveTypes[] = {"int", + "unsigned int", + "long", + "unsigned long", + "short", + "unsigned short", + "bool", + "unsigned char", + "char", + "float", + "double", + "const char*" + }; + const int numPrimitives = sizeof(primitiveTypes)/sizeof(const char*); + bool hasPrimitive[numPrimitives]; + for (int i = 0; i < numPrimitives; ++i) + hasPrimitive[i] = sortData.map.contains(QLatin1String(primitiveTypes[i])); + + if (checkPySequence && checkPyObject) + graph.addEdge(pySeqIndex, pyobjectIndex); + + QStringList classesWithIntegerImplicitConversion; + + MetaFunctionList involvedConversions; + + for (OverloadData *ov : m_nextOverloadData) { + const AbstractMetaType* targetType = ov->argType(); + const QString targetTypeEntryName(getTypeName(ov)); + int targetTypeId = sortData.map[targetTypeEntryName]; + + // Process implicit conversions + const AbstractMetaFunctionList &functions = m_generator->implicitConversions(targetType); + for (AbstractMetaFunction *function : functions) { + QString convertibleType; + if (function->isConversionOperator()) + convertibleType = function->ownerClass()->typeEntry()->name(); + else + convertibleType = getTypeName(function->arguments().first()->type()); + + if (convertibleType == QLatin1String("int") || convertibleType == QLatin1String("unsigned int")) + classesWithIntegerImplicitConversion << targetTypeEntryName; + + if (!sortData.map.contains(convertibleType)) + continue; + + int convertibleTypeId = sortData.map[convertibleType]; + + // If a reverse pair already exists, remove it. Probably due to the + // container check (This happened to QVariant and QHash) + graph.removeEdge(targetTypeId, convertibleTypeId); + graph.addEdge(convertibleTypeId, targetTypeId); + involvedConversions.append(function); + } + + // Process inheritance relationships + if (targetType->isValue() || targetType->isObject()) { + const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_generator->classes(), targetType->typeEntry()); + const AbstractMetaClassList &ancestors = m_generator->getAllAncestors(metaClass); + for (const AbstractMetaClass *ancestor : ancestors) { + QString ancestorTypeName = ancestor->typeEntry()->name(); + if (!sortData.map.contains(ancestorTypeName)) + continue; + int ancestorTypeId = sortData.map[ancestorTypeName]; + graph.removeEdge(ancestorTypeId, targetTypeId); + graph.addEdge(targetTypeId, ancestorTypeId); + } + } + + // Process template instantiations + const AbstractMetaTypeList &instantiations = targetType->instantiations(); + for (const AbstractMetaType *instantiation : instantiations) { + if (sortData.map.contains(getTypeName(instantiation))) { + int convertible = sortData.map[getTypeName(instantiation)]; + + if (!graph.containsEdge(targetTypeId, convertible)) // Avoid cyclic dependency. + graph.addEdge(convertible, targetTypeId); + + if (instantiation->isPrimitive() && (signedIntegerPrimitives.contains(instantiation->name()))) { + for (const QString &primitive : qAsConst(nonIntegerPrimitives)) { + QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, 0, primitive); + if (!graph.containsEdge(targetTypeId, sortData.map[convertibleTypeName])) // Avoid cyclic dependency. + graph.addEdge(sortData.map[convertibleTypeName], targetTypeId); + } + + } else { + const AbstractMetaFunctionList &funcs = m_generator->implicitConversions(instantiation); + for (const AbstractMetaFunction *function : funcs) { + QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, function); + if (!graph.containsEdge(targetTypeId, sortData.map[convertibleTypeName])) { // Avoid cyclic dependency. + graph.addEdge(sortData.map[convertibleTypeName], targetTypeId); + involvedConversions.append(function); + } + } + } + } + } + + + if ((checkPySequence || checkPyObject || checkPyBuffer) + && !targetTypeEntryName.contains(QLatin1String("PyObject")) + && !targetTypeEntryName.contains(QLatin1String("PyBuffer")) + && !targetTypeEntryName.contains(QLatin1String("PySequence"))) { + if (checkPySequence) { + // PySequence will be checked after all more specific types, but before PyObject. + graph.addEdge(targetTypeId, pySeqIndex); + } else if (checkPyBuffer) { + // PySequence will be checked after all more specific types, but before PyObject. + graph.addEdge(targetTypeId, pyBufferIndex); + } else { + // Add dependency on PyObject, so its check is the last one (too generic). + graph.addEdge(targetTypeId, pyobjectIndex); + } + } else if (checkQVariant && targetTypeEntryName != QLatin1String("QVariant")) { + if (!graph.containsEdge(qvariantIndex, targetTypeId)) // Avoid cyclic dependency. + graph.addEdge(targetTypeId, qvariantIndex); + } else if (checkQString && ShibokenGenerator::isPointer(ov->argType()) + && targetTypeEntryName != QLatin1String("QString") + && targetTypeEntryName != QLatin1String("QByteArray") + && (!checkPyObject || targetTypeId != pyobjectIndex)) { + if (!graph.containsEdge(qstringIndex, targetTypeId)) // Avoid cyclic dependency. + graph.addEdge(targetTypeId, qstringIndex); + } + + if (targetType->isEnum()) { + // Enum values must precede primitive types. + for (int i = 0; i < numPrimitives; ++i) { + if (hasPrimitive[i]) + graph.addEdge(targetTypeId, sortData.map[QLatin1String(primitiveTypes[i])]); + } + } + } + + // QByteArray args need to be checked after QString args + if (sortData.map.contains(QLatin1String("QString")) && sortData.map.contains(QLatin1String("QByteArray"))) + graph.addEdge(sortData.map[QLatin1String("QString")], sortData.map[QLatin1String("QByteArray")]); + + for (OverloadData *ov : m_nextOverloadData) { + const AbstractMetaType* targetType = ov->argType(); + if (!targetType->isEnum()) + continue; + + QString targetTypeEntryName = getTypeName(targetType); + // Enum values must precede types implicitly convertible from "int" or "unsigned int". + for (const QString &implicitFromInt : qAsConst(classesWithIntegerImplicitConversion)) + graph.addEdge(sortData.map[targetTypeEntryName], sortData.map[implicitFromInt]); + } + + + // Special case for double(int i) (not tracked by m_generator->implicitConversions + for (const QString &signedIntegerName : qAsConst(signedIntegerPrimitives)) { + if (sortData.map.contains(signedIntegerName)) { + for (const QString &nonIntegerName : qAsConst(nonIntegerPrimitives)) { + if (sortData.map.contains(nonIntegerName)) + graph.addEdge(sortData.map[nonIntegerName], sortData.map[signedIntegerName]); + } + } + } + + // sort the overloads topologically based on the dependency graph. + const QLinkedList unmappedResult = graph.topologicalSort(); + if (unmappedResult.isEmpty()) { + QString funcName = referenceFunction()->name(); + if (referenceFunction()->ownerClass()) + funcName.prepend(referenceFunction()->ownerClass()->name() + QLatin1Char('.')); + + // Dump overload graph + QString graphName = QDir::tempPath() + QLatin1Char('/') + funcName + QLatin1String(".dot"); + QHash::const_iterator it = sortData.map.begin(); + QHash nodeNames; + for (; it != sortData.map.end(); ++it) + nodeNames.insert(it.value(), it.key()); + graph.dumpDot(nodeNames, graphName); + qCWarning(lcShiboken).noquote() << qPrintable(msgCyclicDependency(funcName, graphName, involvedConversions)); + } + + m_nextOverloadData.clear(); + for (int i : unmappedResult) { + if (!sortData.reverseMap[i]) + continue; + m_nextOverloadData << sortData.reverseMap[i]; + } +} + +/** + * Root constructor for OverloadData + * + * This constructor receives the list of overloads for a given function and iterates generating + * the graph of OverloadData instances. Each OverloadData instance references an argument/type + * combination. + * + * Example: + * addStuff(double, PyObject *) + * addStuff(double, int) + * + * Given these two overloads, there will be the following graph: + * + * addStuff - double - PyObject* + * \- int + * + */ +OverloadData::OverloadData(const AbstractMetaFunctionList& overloads, const ShibokenGenerator* generator) + : m_minArgs(256), m_maxArgs(0), m_argPos(-1), m_argType(0), + m_headOverloadData(this), m_previousOverloadData(0), m_generator(generator) +{ + for (const AbstractMetaFunction *func : overloads) { + m_overloads.append(func); + int argSize = func->arguments().size() - numberOfRemovedArguments(func); + if (m_minArgs > argSize) + m_minArgs = argSize; + else if (m_maxArgs < argSize) + m_maxArgs = argSize; + OverloadData* currentOverloadData = this; + const AbstractMetaArgumentList &arguments = func->arguments(); + for (const AbstractMetaArgument *arg : arguments) { + if (func->argumentRemoved(arg->argumentIndex() + 1)) + continue; + currentOverloadData = currentOverloadData->addOverloadData(func, arg); + } + } + + // Sort the overload possibilities so that the overload decisor code goes for the most + // important cases first, based on the topological order of the implicit conversions + sortNextOverloads(); + + // Fix minArgs + if (minArgs() > maxArgs()) + m_headOverloadData->m_minArgs = maxArgs(); +} + +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) +{ + if (func) + this->addOverload(func); +} + +void OverloadData::addOverload(const AbstractMetaFunction* func) +{ + int origNumArgs = func->arguments().size(); + int removed = numberOfRemovedArguments(func); + int numArgs = origNumArgs - removed; + + if (numArgs > m_headOverloadData->m_maxArgs) + m_headOverloadData->m_maxArgs = numArgs; + + if (numArgs < m_headOverloadData->m_minArgs) + m_headOverloadData->m_minArgs = numArgs; + + for (int i = 0; m_headOverloadData->m_minArgs > 0 && i < origNumArgs; i++) { + if (func->argumentRemoved(i + 1)) + continue; + if (!ShibokenGenerator::getDefaultValue(func, func->arguments()[i]).isEmpty()) { + int fixedArgIndex = i - removed; + if (fixedArgIndex < m_headOverloadData->m_minArgs) + m_headOverloadData->m_minArgs = fixedArgIndex; + } + } + + m_overloads.append(func); +} + +OverloadData* OverloadData::addOverloadData(const AbstractMetaFunction* func, + const AbstractMetaArgument* arg) +{ + const AbstractMetaType* argType = arg->type(); + OverloadData* overloadData = 0; + if (!func->isOperatorOverload()) { + for (OverloadData *tmp : qAsConst(m_nextOverloadData)) { + // TODO: 'const char *', 'char *' and 'char' will have the same TypeEntry? + + // If an argument have a type replacement, then we should create a new overloaddata + // for it, unless the next argument also have a identical type replacement. + QString replacedArg = func->typeReplaced(tmp->m_argPos + 1); + bool argsReplaced = !replacedArg.isEmpty() || !tmp->m_argTypeReplaced.isEmpty(); + if ((!argsReplaced && typesAreEqual(tmp->m_argType, argType)) + || (argsReplaced && replacedArg == tmp->argumentTypeReplaced())) { + tmp->addOverload(func); + overloadData = tmp; + } + } + } + + if (!overloadData) { + overloadData = new OverloadData(m_headOverloadData, func, argType, m_argPos + 1); + overloadData->m_previousOverloadData = this; + overloadData->m_generator = this->m_generator; + QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1); + + if (!typeReplaced.isEmpty()) + overloadData->m_argTypeReplaced = typeReplaced; + m_nextOverloadData.append(overloadData); + } + + return overloadData; +} + +QStringList OverloadData::returnTypes() const +{ + QSet retTypes; + for (const AbstractMetaFunction *func : m_overloads) { + if (!func->typeReplaced(0).isEmpty()) + retTypes << func->typeReplaced(0); + else if (func->type() && !func->argumentRemoved(0)) + retTypes << func->type()->cppSignature(); + else + retTypes << QLatin1String("void"); + } + return QStringList(retTypes.toList()); +} + +bool OverloadData::hasNonVoidReturnType() const +{ + QStringList retTypes = returnTypes(); + return !retTypes.contains(QLatin1String("void")) || retTypes.size() > 1; +} + +bool OverloadData::hasVarargs() const +{ + for (const AbstractMetaFunction *func : m_overloads) { + AbstractMetaArgumentList args = func->arguments(); + if (args.size() > 1 && args.last()->type()->isVarargs()) + return true; + } + return false; +} + +bool OverloadData::hasAllowThread() const +{ + for (const AbstractMetaFunction *func : m_overloads) { + if (func->allowThread()) + return true; + } + return false; +} + +bool OverloadData::hasStaticFunction(const AbstractMetaFunctionList& overloads) +{ + for (const AbstractMetaFunction *func : qAsConst(overloads)) { + if (func->isStatic()) + return true; + } + return false; +} + +bool OverloadData::hasStaticFunction() const +{ + for (const AbstractMetaFunction *func : m_overloads) { + if (func->isStatic()) + return true; + } + return false; +} + +bool OverloadData::hasInstanceFunction(const AbstractMetaFunctionList& overloads) +{ + for (const AbstractMetaFunction *func : qAsConst(overloads)) { + if (!func->isStatic()) + return true; + } + return false; +} + +bool OverloadData::hasInstanceFunction() const +{ + for (const AbstractMetaFunction *func : m_overloads) { + if (!func->isStatic()) + return true; + } + return false; +} + +bool OverloadData::hasStaticAndInstanceFunctions(const AbstractMetaFunctionList& overloads) +{ + return OverloadData::hasStaticFunction(overloads) && OverloadData::hasInstanceFunction(overloads); +} + +bool OverloadData::hasStaticAndInstanceFunctions() const +{ + return OverloadData::hasStaticFunction() && OverloadData::hasInstanceFunction(); +} + +const AbstractMetaFunction* OverloadData::referenceFunction() const +{ + return m_overloads.first(); +} + +const AbstractMetaArgument* OverloadData::argument(const AbstractMetaFunction* func) const +{ + if (isHeadOverloadData() || !m_overloads.contains(func)) + return 0; + + int argPos = 0; + int removed = 0; + for (int i = 0; argPos <= m_argPos; i++) { + if (func->argumentRemoved(i + 1)) + removed++; + else + argPos++; + } + + return func->arguments()[m_argPos + removed]; +} + +OverloadDataList OverloadData::overloadDataOnPosition(OverloadData* overloadData, int argPos) const +{ + OverloadDataList overloadDataList; + if (overloadData->argPos() == argPos) { + overloadDataList.append(overloadData); + } else if (overloadData->argPos() < argPos) { + const OverloadDataList &data = overloadData->nextOverloadData(); + for (OverloadData *pd : data) + overloadDataList += overloadDataOnPosition(pd, argPos); + } + return overloadDataList; +} + +OverloadDataList OverloadData::overloadDataOnPosition(int argPos) const +{ + OverloadDataList overloadDataList; + overloadDataList += overloadDataOnPosition(m_headOverloadData, argPos); + return overloadDataList; +} + +bool OverloadData::nextArgumentHasDefaultValue() const +{ + for (OverloadData *overloadData : m_nextOverloadData) { + if (overloadData->getFunctionWithDefaultValue()) + return true; + } + return false; +} + +static OverloadData* _findNextArgWithDefault(OverloadData* overloadData) +{ + if (overloadData->getFunctionWithDefaultValue()) + return overloadData; + + OverloadData* result = 0; + const OverloadDataList &data = overloadData->nextOverloadData(); + for (OverloadData *odata : data) { + OverloadData* tmp = _findNextArgWithDefault(odata); + if (!result || (tmp && result->argPos() > tmp->argPos())) + result = tmp; + } + return result; +} + +OverloadData* OverloadData::findNextArgWithDefault() +{ + return _findNextArgWithDefault(this); +} + +bool OverloadData::isFinalOccurrence(const AbstractMetaFunction* func) const +{ + for (const OverloadData *pd : m_nextOverloadData) { + if (pd->overloads().contains(func)) + return false; + } + return true; +} + +OverloadData::MetaFunctionList OverloadData::overloadsWithoutRepetition() const +{ + MetaFunctionList overloads = m_overloads; + for (const AbstractMetaFunction *func : m_overloads) { + if (func->minimalSignature().endsWith(QLatin1String("const"))) + continue; + for (const AbstractMetaFunction *f : qAsConst(overloads)) { + if ((func->minimalSignature() + QLatin1String("const")) == f->minimalSignature()) { + overloads.removeOne(f); + break; + } + } + } + return overloads; +} + +const AbstractMetaFunction* OverloadData::getFunctionWithDefaultValue() const +{ + for (const AbstractMetaFunction *func : m_overloads) { + int removedArgs = 0; + for (int i = 0; i <= m_argPos + removedArgs; i++) { + if (func->argumentRemoved(i + 1)) + removedArgs++; + } + if (!ShibokenGenerator::getDefaultValue(func, func->arguments()[m_argPos + removedArgs]).isEmpty()) + return func; + } + return 0; +} + +QVector OverloadData::invalidArgumentLengths() const +{ + QSet validArgLengths; + + for (const AbstractMetaFunction *func : qAsConst(m_headOverloadData->m_overloads)) { + const AbstractMetaArgumentList args = func->arguments(); + int offset = 0; + for (int i = 0; i < args.size(); ++i) { + if (func->argumentRemoved(i+1)) { + offset++; + } else { + if (!ShibokenGenerator::getDefaultValue(func, args[i]).isEmpty()) + validArgLengths << i-offset; + } + } + validArgLengths << args.size() - offset; + } + + QVector invalidArgLengths; + for (int i = minArgs() + 1; i < maxArgs(); i++) { + if (!validArgLengths.contains(i)) + invalidArgLengths.append(i); + } + + return invalidArgLengths; +} + +int OverloadData::numberOfRemovedArguments(const AbstractMetaFunction* func, int finalArgPos) +{ + int removed = 0; + if (finalArgPos < 0) { + for (int i = 0; i < func->arguments().size(); i++) { + if (func->argumentRemoved(i + 1)) + removed++; + } + } else { + for (int i = 0; i < finalArgPos + removed; i++) { + if (func->argumentRemoved(i + 1)) + removed++; + } + } + return removed; +} + +QPair OverloadData::getMinMaxArguments(const AbstractMetaFunctionList& overloads) +{ + int minArgs = 10000; + int maxArgs = 0; + for (int i = 0; i < overloads.size(); i++) { + const AbstractMetaFunction* func = overloads[i]; + int origNumArgs = func->arguments().size(); + int removed = numberOfRemovedArguments(func); + int numArgs = origNumArgs - removed; + if (maxArgs < numArgs) + maxArgs = numArgs; + if (minArgs > numArgs) + minArgs = numArgs; + for (int j = 0; j < origNumArgs; j++) { + if (func->argumentRemoved(j + 1)) + continue; + int fixedArgIndex = j - removed; + if (fixedArgIndex < minArgs && !ShibokenGenerator::getDefaultValue(func, func->arguments()[j]).isEmpty()) + minArgs = fixedArgIndex; + } + } + return QPair(minArgs, maxArgs); +} + +bool OverloadData::isSingleArgument(const AbstractMetaFunctionList& overloads) +{ + bool singleArgument = true; + for (const AbstractMetaFunction *func : overloads) { + if (func->arguments().size() - numberOfRemovedArguments(func) != 1) { + singleArgument = false; + break; + } + } + return singleArgument; +} + +void OverloadData::dumpGraph(QString filename) const +{ + QFile file(filename); + if (file.open(QFile::WriteOnly)) { + QTextStream s(&file); + s << m_headOverloadData->dumpGraph(); + } +} + +static inline QString toHtml(QString s) +{ + s.replace(QLatin1Char('<'), QLatin1String("<")); + s.replace(QLatin1Char('>'), QLatin1String(">")); + s.replace(QLatin1Char('&'), QLatin1String("&")); + return s; +} + +QString OverloadData::dumpGraph() const +{ + QString indent(4, QLatin1Char(' ')); + QString result; + QTextStream s(&result); + if (m_argPos == -1) { + const AbstractMetaFunction* rfunc = referenceFunction(); + s << "digraph OverloadedFunction {" << endl; + s << indent << "graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];" << endl; + + // Shows all function signatures + s << "legend [fontsize=9 fontname=freemono shape=rect label=\""; + for (const AbstractMetaFunction *func : m_overloads) { + s << "f" << functionNumber(func) << " : "; + if (func->type()) + s << toHtml(func->type()->cppSignature()); + else + s << "void"; + s << ' ' << toHtml(func->minimalSignature()) << "\\l"; + } + s << "\"];" << endl; + + // Function box title + s << indent << '"' << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 "; + s << "label=<"; + s << ""; + + // Function return type + s << ""; + + // Shows type changes for all function signatures + for (const AbstractMetaFunction *func : m_overloads) { + if (func->typeReplaced(0).isEmpty()) + continue; + s << ""; + } + + // Minimum and maximum number of arguments + s << ""; + s << ""; + + if (rfunc->ownerClass()) { + if (rfunc->implementingClass() != rfunc->ownerClass()) + s << ""; + if (rfunc->declaringClass() != rfunc->ownerClass() && rfunc->declaringClass() != rfunc->implementingClass()) + s << ""; + } + + // Overloads for the signature to present point + s << ""; + + s << "
"; + if (rfunc->ownerClass()) + s << rfunc->ownerClass()->name() << "::"; + s << toHtml(rfunc->name()) << ""; + if (rfunc->isVirtual()) { + s << "
<<"; + if (rfunc->isAbstract()) + s << "pure "; + s << "virtual>>"; + } + s << "
original type"; + if (rfunc->type()) + s << toHtml(rfunc->type()->cppSignature()); + else + s << "void"; + s << "
f" << functionNumber(func); + s << "-type"; + s << toHtml(func->typeReplaced(0)) << "
minArgs"; + s << minArgs() << "
maxArgs"; + s << maxArgs() << "
implementor" << rfunc->implementingClass()->name() << "
declarator" << rfunc->declaringClass()->name() << "
overloads"; + for (const AbstractMetaFunction *func : m_overloads) + s << 'f' << functionNumber(func) << ' '; + s << "
> ];" << endl; + + for (const OverloadData *pd : m_nextOverloadData) + s << indent << '"' << rfunc->name() << "\" -> " << pd->dumpGraph(); + + s << "}" << endl; + } else { + QString argId = QLatin1String("arg_") + QString::number(quintptr(this)); + s << argId << ';' << endl; + + s << indent << '"' << argId << "\" [shape=\"plaintext\" style=\"filled,bold\" margin=\"0\" fontname=\"freemono\" fillcolor=\"white\" penwidth=1 "; + s << "label=<"; + + // Argument box title + s << ""; + + // Argument type information + QString type = hasArgumentTypeReplace() ? argumentTypeReplaced() : argType()->cppSignature(); + s << ""; + if (hasArgumentTypeReplace()) { + s << ""; + } + + // Overloads for the signature to present point + s << ""; + + // Show default values (original and modified) for various functions + for (const AbstractMetaFunction *func : m_overloads) { + const AbstractMetaArgument* arg = argument(func); + if (!arg) + continue; + QString argDefault = ShibokenGenerator::getDefaultValue(func, arg); + if (!argDefault.isEmpty() || + argDefault != arg->originalDefaultValueExpression()) { + s << ""; + } + if (argDefault != arg->originalDefaultValueExpression()) { + s << ""; + } + } + + s << "
"; + s << "arg #" << argPos() << "
type"; + s << toHtml(type) << "
orig. type"; + s << toHtml(argType()->cppSignature()) << "
overloads"; + for (const AbstractMetaFunction *func : m_overloads) + s << 'f' << functionNumber(func) << ' '; + s << "
f" << functionNumber(func); + s << "-default"; + s << argDefault << "
f" << functionNumber(func); + s << "-orig-default"; + s << arg->originalDefaultValueExpression() << "
>];" << endl; + + for (const OverloadData *pd : m_nextOverloadData) + s << indent << argId << " -> " << pd->dumpGraph(); + } + return result; +} + +int OverloadData::functionNumber(const AbstractMetaFunction* func) const +{ + return m_headOverloadData->m_overloads.indexOf(func); +} + +OverloadData::~OverloadData() +{ + while (!m_nextOverloadData.isEmpty()) + delete m_nextOverloadData.takeLast(); +} + +bool OverloadData::hasArgumentTypeReplace() const +{ + return !m_argTypeReplaced.isEmpty(); +} + +QString OverloadData::argumentTypeReplaced() const +{ + return m_argTypeReplaced; +} + +bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunctionList& overloads) +{ + if (OverloadData::getMinMaxArguments(overloads).second == 0) + return false; + for (const AbstractMetaFunction *func : overloads) { + if (hasArgumentWithDefaultValue(func)) + return true; + } + return false; +} + +bool OverloadData::hasArgumentWithDefaultValue() const +{ + if (maxArgs() == 0) + return false; + for (const AbstractMetaFunction *func : m_overloads) { + if (hasArgumentWithDefaultValue(func)) + return true; + } + return false; +} + +bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunction* func) +{ + const AbstractMetaArgumentList &arguments = func->arguments(); + for (const AbstractMetaArgument *arg : arguments) { + if (func->argumentRemoved(arg->argumentIndex() + 1)) + continue; + if (!ShibokenGenerator::getDefaultValue(func, arg).isEmpty()) + return true; + } + return false; +} + +AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const AbstractMetaFunction* func) +{ + AbstractMetaArgumentList args; + const AbstractMetaArgumentList &arguments = func->arguments(); + for (AbstractMetaArgument *arg : arguments) { + if (ShibokenGenerator::getDefaultValue(func, arg).isEmpty() + || func->argumentRemoved(arg->argumentIndex() + 1)) + continue; + args << arg; + } + return args; +} + +#ifndef QT_NO_DEBUG_STREAM +void OverloadData::formatDebug(QDebug &d) const +{ + const int count = m_overloads.size(); + d << "argType=" << m_argType << ", minArgs=" << m_minArgs << ", maxArgs=" << m_maxArgs + << ", argPos=" << m_argPos << ", argTypeReplaced=\"" << m_argTypeReplaced + << "\", overloads[" << count << "]=("; + const int oldVerbosity = d.verbosity(); + d.setVerbosity(3); + for (int i = 0; i < count; ++i) { + if (i) + d << '\n'; + d << m_overloads.at(i); + } + d << ')'; + d.setVerbosity(oldVerbosity); +} + +QDebug operator<<(QDebug d, const OverloadData *od) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "OverloadData("; + if (od) + od->formatDebug(d); + else + d << '0'; + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.h b/sources/shiboken2/generator/shiboken2/overloaddata.h new file mode 100644 index 000000000..2d815f6bb --- /dev/null +++ b/sources/shiboken2/generator/shiboken2/overloaddata.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 OVERLOADDATA_H +#define OVERLOADDATA_H + +#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QDebug) + +class ShibokenGenerator; + +class OverloadData; +typedef QVector OverloadDataList; + +class OverloadData +{ +public: + typedef QVector MetaFunctionList; + + OverloadData(const AbstractMetaFunctionList& overloads, const ShibokenGenerator* generator); + ~OverloadData(); + + int minArgs() const { return m_headOverloadData->m_minArgs; } + int maxArgs() const { return m_headOverloadData->m_maxArgs; } + int argPos() const { return m_argPos; } + + const AbstractMetaType* argType() const { return m_argType; } + + /// Returns a string list containing all the possible return types (including void) for the current OverloadData. + QStringList returnTypes() const; + + /// Returns true if any of the overloads for the current OverloadData has a return type different from void. + bool hasNonVoidReturnType() const; + + /// Returns true if any of the overloads for the current OverloadData has a varargs argument. + bool hasVarargs() const; + + /// Returns true if any of the overloads for the current OverloadData allows threads when called. + bool hasAllowThread() const; + + /// Returns true if any of the overloads for the current OverloadData is static. + bool hasStaticFunction() const; + + /// Returns true if any of the overloads passed as argument is static. + static bool hasStaticFunction(const AbstractMetaFunctionList& overloads); + + /// Returns true if any of the overloads for the current OverloadData is not static. + bool hasInstanceFunction() const; + + /// Returns true if any of the overloads passed as argument is not static. + static bool hasInstanceFunction(const AbstractMetaFunctionList& overloads); + + /// Returns true if among the overloads for the current OverloadData there are static and non-static methods altogether. + bool hasStaticAndInstanceFunctions() const; + + /// Returns true if among the overloads passed as argument there are static and non-static methods altogether. + static bool hasStaticAndInstanceFunctions(const AbstractMetaFunctionList& overloads); + + const AbstractMetaFunction* referenceFunction() const; + const AbstractMetaArgument* argument(const AbstractMetaFunction* func) const; + OverloadDataList overloadDataOnPosition(int argPos) const; + + bool isHeadOverloadData() const { return this == m_headOverloadData; } + + /// Returns the root OverloadData object that represents all the overloads. + OverloadData* headOverloadData() const { return m_headOverloadData; } + + /// Returns the function that has a default value at the current OverloadData argument position, otherwise returns null. + const AbstractMetaFunction* getFunctionWithDefaultValue() const; + + bool nextArgumentHasDefaultValue() const; + /// Returns the nearest occurrence, including this instance, of an argument with a default value. + OverloadData* findNextArgWithDefault(); + bool isFinalOccurrence(const AbstractMetaFunction* func) const; + + /// Returns the list of overloads removing repeated constant functions (ex.: "foo()" and "foo()const", the second is removed). + MetaFunctionList overloadsWithoutRepetition() const; + const MetaFunctionList& overloads() const { return m_overloads; } + OverloadDataList nextOverloadData() const { return m_nextOverloadData; } + OverloadData* previousOverloadData() const { return m_previousOverloadData; } + + QVector invalidArgumentLengths() const; + + static int numberOfRemovedArguments(const AbstractMetaFunction* func, int finalArgPos = -1); + static QPair getMinMaxArguments(const AbstractMetaFunctionList& overloads); + /// Returns true if all overloads have no more than one argument. + static bool isSingleArgument(const AbstractMetaFunctionList& overloads); + + void dumpGraph(QString filename) const; + QString dumpGraph() const; + + bool hasArgumentTypeReplace() const; + QString argumentTypeReplaced() const; + + bool hasArgumentWithDefaultValue() const; + static bool hasArgumentWithDefaultValue(const AbstractMetaFunctionList& overloads); + static bool hasArgumentWithDefaultValue(const AbstractMetaFunction* func); + + /// Returns a list of function arguments which have default values and were not removed. + static AbstractMetaArgumentList getArgumentsWithDefaultValues(const AbstractMetaFunction* func); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &) const; +#endif + +private: + OverloadData(OverloadData* headOverloadData, const AbstractMetaFunction* func, + const AbstractMetaType* argType, int argPos); + + void addOverload(const AbstractMetaFunction* func); + OverloadData* addOverloadData(const AbstractMetaFunction* func, const AbstractMetaArgument* arg); + + void sortNextOverloads(); + + int functionNumber(const AbstractMetaFunction* func) const; + OverloadDataList overloadDataOnPosition(OverloadData* overloadData, int argPos) const; + + int m_minArgs; + int m_maxArgs; + int m_argPos; + const AbstractMetaType* m_argType; + QString m_argTypeReplaced; + MetaFunctionList m_overloads; + + OverloadData* m_headOverloadData; + OverloadDataList m_nextOverloadData; + OverloadData* m_previousOverloadData; + const ShibokenGenerator* m_generator; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug, const OverloadData *); +#endif + +#endif // OVERLOADDATA_H diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp new file mode 100644 index 000000000..4768ddc88 --- /dev/null +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -0,0 +1,2728 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "shibokengenerator.h" +#include +#include "overloaddata.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 void dumpFunction(AbstractMetaFunctionList lst); + +QHash ShibokenGenerator::m_pythonPrimitiveTypeName = QHash(); +QHash ShibokenGenerator::m_pythonOperators = QHash(); +QHash ShibokenGenerator::m_formatUnits = QHash(); +QHash ShibokenGenerator::m_tpFuncs = QHash(); +QStringList ShibokenGenerator::m_knownPythonTypes = QStringList(); + +static QRegularExpression placeHolderRegex(int index) +{ + return QRegularExpression(QLatin1Char('%') + QString::number(index) + QStringLiteral("\\b")); +} + +static QString resolveScopePrefix(const AbstractMetaClass* scope, const QString& value) +{ + if (!scope) + return QString(); + + QString name; + QStringList parts = scope->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts); + for(int i = (parts.size() - 1) ; i >= 0; i--) { + if (!value.startsWith(parts[i] + QLatin1String("::"))) + name = parts[i] + QLatin1String("::") + name; + else + name.clear(); + } + + return name; +} +ShibokenGenerator::ShibokenGenerator() : Generator() +{ + if (m_pythonPrimitiveTypeName.isEmpty()) + ShibokenGenerator::initPrimitiveTypesCorrespondences(); + + if (m_tpFuncs.isEmpty()) + ShibokenGenerator::clearTpFuncs(); + + if (m_knownPythonTypes.isEmpty()) + ShibokenGenerator::initKnownPythonTypes(); + + m_metaTypeFromStringCache = AbstractMetaTypeCache(); + + m_typeSystemConvName[TypeSystemCheckFunction] = QLatin1String("checkType"); + m_typeSystemConvName[TypeSystemIsConvertibleFunction] = QLatin1String("isConvertible"); + m_typeSystemConvName[TypeSystemToCppFunction] = QLatin1String("toCpp"); + m_typeSystemConvName[TypeSystemToPythonFunction] = QLatin1String("toPython"); + 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()); +} + +void ShibokenGenerator::clearTpFuncs() +{ + m_tpFuncs.insert(QLatin1String("__str__"), QLatin1String("0")); + m_tpFuncs.insert(QLatin1String("__repr__"), QLatin1String("0")); + m_tpFuncs.insert(QLatin1String("__iter__"), QLatin1String("0")); + m_tpFuncs.insert(QLatin1String("__next__"), QLatin1String("0")); +} + +void ShibokenGenerator::initPrimitiveTypesCorrespondences() +{ + // Python primitive types names + m_pythonPrimitiveTypeName.clear(); + + // PyBool + m_pythonPrimitiveTypeName.insert(QLatin1String("bool"), QLatin1String("PyBool")); + + // PyInt + m_pythonPrimitiveTypeName.insert(QLatin1String("char"), QLatin1String("SbkChar")); + m_pythonPrimitiveTypeName.insert(QLatin1String("signed char"), QLatin1String("SbkChar")); + m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned char"), QLatin1String("SbkChar")); + m_pythonPrimitiveTypeName.insert(QLatin1String("int"), QLatin1String("PyInt")); + m_pythonPrimitiveTypeName.insert(QLatin1String("signed int"), QLatin1String("PyInt")); + m_pythonPrimitiveTypeName.insert(QLatin1String("uint"), QLatin1String("PyInt")); + m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned int"), QLatin1String("PyInt")); + m_pythonPrimitiveTypeName.insert(QLatin1String("short"), QLatin1String("PyInt")); + m_pythonPrimitiveTypeName.insert(QLatin1String("ushort"), QLatin1String("PyInt")); + m_pythonPrimitiveTypeName.insert(QLatin1String("signed short"), QLatin1String("PyInt")); + m_pythonPrimitiveTypeName.insert(QLatin1String("signed short int"), QLatin1String("PyInt")); + m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned short"), QLatin1String("PyInt")); + m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned short int"), QLatin1String("PyInt")); + m_pythonPrimitiveTypeName.insert(QLatin1String("long"), QLatin1String("PyInt")); + + // PyFloat + m_pythonPrimitiveTypeName.insert(QLatin1String("double"), QLatin1String("PyFloat")); + m_pythonPrimitiveTypeName.insert(QLatin1String("float"), QLatin1String("PyFloat")); + + // PyLong + m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned long"), QLatin1String("PyLong")); + m_pythonPrimitiveTypeName.insert(QLatin1String("signed long"), QLatin1String("PyLong")); + m_pythonPrimitiveTypeName.insert(QLatin1String("ulong"), QLatin1String("PyLong")); + m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned long int"), QLatin1String("PyLong")); + m_pythonPrimitiveTypeName.insert(QLatin1String("long long"), QLatin1String("PyLong")); + m_pythonPrimitiveTypeName.insert(QLatin1String("__int64"), QLatin1String("PyLong")); + m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned long long"), QLatin1String("PyLong")); + m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned __int64"), QLatin1String("PyLong")); + m_pythonPrimitiveTypeName.insert(QLatin1String("size_t"), QLatin1String("PyLong")); + + // Python operators + m_pythonOperators.clear(); + + // call operator + m_pythonOperators.insert(QLatin1String("operator()"), QLatin1String("call")); + + // Arithmetic operators + m_pythonOperators.insert(QLatin1String("operator+"), QLatin1String("add")); + m_pythonOperators.insert(QLatin1String("operator-"), QLatin1String("sub")); + m_pythonOperators.insert(QLatin1String("operator*"), QLatin1String("mul")); + m_pythonOperators.insert(QLatin1String("operator/"), QLatin1String("div")); + m_pythonOperators.insert(QLatin1String("operator%"), QLatin1String("mod")); + + // Inplace arithmetic operators + m_pythonOperators.insert(QLatin1String("operator+="), QLatin1String("iadd")); + m_pythonOperators.insert(QLatin1String("operator-="), QLatin1String("isub")); + m_pythonOperators.insert(QLatin1String("operator++"), QLatin1String("iadd")); + m_pythonOperators.insert(QLatin1String("operator--"), QLatin1String("isub")); + m_pythonOperators.insert(QLatin1String("operator*="), QLatin1String("imul")); + m_pythonOperators.insert(QLatin1String("operator/="), QLatin1String("idiv")); + m_pythonOperators.insert(QLatin1String("operator%="), QLatin1String("imod")); + + // Bitwise operators + m_pythonOperators.insert(QLatin1String("operator&"), QLatin1String("and")); + m_pythonOperators.insert(QLatin1String("operator^"), QLatin1String("xor")); + m_pythonOperators.insert(QLatin1String("operator|"), QLatin1String("or")); + m_pythonOperators.insert(QLatin1String("operator<<"), QLatin1String("lshift")); + m_pythonOperators.insert(QLatin1String("operator>>"), QLatin1String("rshift")); + m_pythonOperators.insert(QLatin1String("operator~"), QLatin1String("invert")); + + // Inplace bitwise operators + m_pythonOperators.insert(QLatin1String("operator&="), QLatin1String("iand")); + m_pythonOperators.insert(QLatin1String("operator^="), QLatin1String("ixor")); + m_pythonOperators.insert(QLatin1String("operator|="), QLatin1String("ior")); + m_pythonOperators.insert(QLatin1String("operator<<="), QLatin1String("ilshift")); + m_pythonOperators.insert(QLatin1String("operator>>="), QLatin1String("irshift")); + + // Comparison operators + m_pythonOperators.insert(QLatin1String("operator=="), QLatin1String("eq")); + m_pythonOperators.insert(QLatin1String("operator!="), QLatin1String("ne")); + m_pythonOperators.insert(QLatin1String("operator<"), QLatin1String("lt")); + m_pythonOperators.insert(QLatin1String("operator>"), QLatin1String("gt")); + m_pythonOperators.insert(QLatin1String("operator<="), QLatin1String("le")); + m_pythonOperators.insert(QLatin1String("operator>="), QLatin1String("ge")); + + // Initialize format units for C++->Python->C++ conversion + m_formatUnits.clear(); + m_formatUnits.insert(QLatin1String("char"), QLatin1String("b")); + m_formatUnits.insert(QLatin1String("unsigned char"), QLatin1String("B")); + m_formatUnits.insert(QLatin1String("int"), QLatin1String("i")); + m_formatUnits.insert(QLatin1String("unsigned int"), QLatin1String("I")); + m_formatUnits.insert(QLatin1String("short"), QLatin1String("h")); + m_formatUnits.insert(QLatin1String("unsigned short"), QLatin1String("H")); + m_formatUnits.insert(QLatin1String("long"), QLatin1String("l")); + m_formatUnits.insert(QLatin1String("unsigned long"), QLatin1String("k")); + m_formatUnits.insert(QLatin1String("long long"), QLatin1String("L")); + m_formatUnits.insert(QLatin1String("__int64"), QLatin1String("L")); + m_formatUnits.insert(QLatin1String("unsigned long long"), QLatin1String("K")); + m_formatUnits.insert(QLatin1String("unsigned __int64"), QLatin1String("K")); + m_formatUnits.insert(QLatin1String("double"), QLatin1String("d")); + m_formatUnits.insert(QLatin1String("float"), QLatin1String("f")); +} + +void ShibokenGenerator::initKnownPythonTypes() +{ + m_knownPythonTypes.clear(); + m_knownPythonTypes << QLatin1String("PyBool") << QLatin1String("PyInt") + << QLatin1String("PyFloat") << QLatin1String("PyLong") << QLatin1String("PyObject") + << QLatin1String("PyString") << QLatin1String("PyBuffer") << QLatin1String("PySequence") + << QLatin1String("PyTuple") << QLatin1String("PyList") << QLatin1String("PyDict") + << QLatin1String("PyObject*") << QLatin1String("PyObject *") << QLatin1String("PyTupleObject*"); +} + +QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType* cType, + const AbstractMetaClass* context, + Options options) const +{ + if (cType->isArray()) + return translateTypeForWrapperMethod(cType->arrayElementType(), context, options) + QLatin1String("[]"); + + if (avoidProtectedHack() && cType->isEnum()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(cType); + if (metaEnum && metaEnum->isProtected()) + return protectedEnumSurrogateName(metaEnum); + } + + return translateType(cType, context, options); +} + +bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass* metaClass) const +{ + bool result = metaClass->isPolymorphic() || metaClass->hasVirtualDestructor(); + if (avoidProtectedHack()) { + result = result || metaClass->hasProtectedFields() || metaClass->hasProtectedDestructor(); + if (!result && metaClass->hasProtectedFunctions()) { + int protectedFunctions = 0; + int protectedOperators = 0; + const AbstractMetaFunctionList &funcs = metaClass->functions(); + for (const AbstractMetaFunction *func : funcs) { + if (!func->isProtected() || func->isSignal() || func->isModifiedRemoved()) + continue; + else if (func->isOperatorOverload()) + protectedOperators++; + else + protectedFunctions++; + } + result = result || (protectedFunctions > protectedOperators); + } + } else { + result = result && !metaClass->hasPrivateDestructor(); + } + return result && !metaClass->isNamespace(); +} + +void ShibokenGenerator::lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList& enumList, const AbstractMetaClass* metaClass) +{ + if (!metaClass) + return; + + if (metaClass->typeEntry()->codeGeneration() == TypeEntry::GenerateForSubclass) { + const AbstractMetaEnumList &enums = metaClass->enums(); + for (const AbstractMetaEnum *metaEnum : enums) { + if (metaEnum->isPrivate() || metaEnum->typeEntry()->codeGeneration() == TypeEntry::GenerateForSubclass) + continue; + if (!enumList.contains(const_cast(metaEnum))) + enumList.append(const_cast(metaEnum)); + } + lookForEnumsInClassesNotToBeGenerated(enumList, metaClass->enclosingClass()); + } +} + +static const AbstractMetaClass* getProperEnclosingClass(const AbstractMetaClass* metaClass) +{ + if (!metaClass) + return 0; + + if (metaClass->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass) + return metaClass; + + return getProperEnclosingClass(metaClass->enclosingClass()); +} + +const AbstractMetaClass* ShibokenGenerator::getProperEnclosingClassForEnum(const AbstractMetaEnum* metaEnum) +{ + return getProperEnclosingClass(metaEnum->enclosingClass()); +} + +QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const +{ + if (shouldGenerateCppWrapper(metaClass)) { + QString result = metaClass->name(); + if (metaClass->enclosingClass()) // is a inner class + result.replace(QLatin1String("::"), QLatin1String("_")); + + result += QLatin1String("Wrapper"); + return result; + } else { + return metaClass->qualifiedCppName(); + } +} + +QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const +{ + return metaType->cppSignature(); +} + +QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* func) +{ + QString funcName; + if (func->isOperatorOverload()) + funcName = ShibokenGenerator::pythonOperatorFunctionName(func); + else + funcName = func->name(); + if (func->ownerClass()) { + QString fullName = func->ownerClass()->fullName(); + if (func->isConstructor()) + funcName = fullName; + else + funcName.prepend(fullName + QLatin1Char('.')); + } + return funcName; +} + +QString ShibokenGenerator::protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum) +{ + return metaEnum->fullName().replace(QLatin1Char('.'), QLatin1Char('_')).replace(QLatin1String("::"), QLatin1String("_")) + QLatin1String("_Surrogate"); +} + +QString ShibokenGenerator::protectedFieldGetterName(const AbstractMetaField* field) +{ + return QStringLiteral("protected_%1_getter").arg(field->name()); +} + +QString ShibokenGenerator::protectedFieldSetterName(const AbstractMetaField* field) +{ + return QStringLiteral("protected_%1_setter").arg(field->name()); +} + +QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunction* func) +{ + QString result; + + // PYSIDE-331: For inherited functions, we need to find the same labels. + // Therefore we use the implementing class. + if (func->implementingClass()) { + result = cpythonBaseName(func->implementingClass()->typeEntry()); + if (func->isConstructor()) { + result += QLatin1String("_Init"); + } else { + result += QLatin1String("Func_"); + if (func->isOperatorOverload()) + result += ShibokenGenerator::pythonOperatorFunctionName(func); + else + result += func->name(); + } + } else { + result = QLatin1String("Sbk") + moduleName() + QLatin1String("Module_") + func->name(); + } + + return result; +} + +QString ShibokenGenerator::cpythonMethodDefinitionName(const AbstractMetaFunction* func) +{ + if (!func->ownerClass()) + return QString(); + return QStringLiteral("%1Method_%2").arg(cpythonBaseName(func->ownerClass()->typeEntry()), func->name()); +} + +QString ShibokenGenerator::cpythonGettersSettersDefinitionName(const AbstractMetaClass* metaClass) +{ + return cpythonBaseName(metaClass) + QLatin1String("_getsetlist"); +} + +QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClass* metaClass) +{ + return cpythonBaseName(metaClass) + QLatin1String("_setattro"); +} + + +QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClass* metaClass) +{ + return cpythonBaseName(metaClass) + QLatin1String("_getattro"); +} + +QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField* metaField) +{ + return QStringLiteral("%1_get_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name()); +} + +QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField* metaField) +{ + return QStringLiteral("%1_set_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name()); +} + +static QString cpythonEnumFlagsName(QString moduleName, QString qualifiedCppName) +{ + QString result = QStringLiteral("Sbk%1_%2").arg(moduleName, qualifiedCppName); + result.replace(QLatin1String("::"), QLatin1String("_")); + return result; +} + +static QString searchForEnumScope(const AbstractMetaClass* metaClass, const QString& value) +{ + QString enumValueName = value.trimmed(); + + if (!metaClass) + return QString(); + const AbstractMetaEnumList &enums = metaClass->enums(); + for (const AbstractMetaEnum* metaEnum : enums) { + const AbstractMetaEnumValueList &values = metaEnum->values(); + for (const AbstractMetaEnumValue *enumValue : values) { + if (enumValueName == enumValue->name()) + return metaClass->qualifiedCppName(); + } + } + // PYSIDE-331: We need to also search the base classes. + QString ret = searchForEnumScope(metaClass->enclosingClass(), enumValueName); + if (ret.isEmpty()) + ret = searchForEnumScope(metaClass->baseClass(), enumValueName); + return ret; +} + +/* + * This function uses some heuristics to find out the scope for a given + * argument default value. New situations may arise in the future and + * this method should be updated, do it with care. + */ +QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg) +{ + QString value = getDefaultValue(func, arg); + + if (value.isEmpty()) + return QString(); + + if (isPointer(arg->type())) + return value; + + static const QRegularExpression enumValueRegEx(QStringLiteral("^([A-Za-z_]\\w*)?$")); + Q_ASSERT(enumValueRegEx.isValid()); + // Do not qualify macros by class name, eg QSGGeometry(..., int t = GL_UNSIGNED_SHORT); + static const QRegularExpression macroRegEx(QStringLiteral("^[A-Z_][A-Z0-9_]*$")); + Q_ASSERT(macroRegEx.isValid()); + if (arg->type()->isPrimitive() && macroRegEx.match(value).hasMatch()) + return value; + + QString prefix; + QString suffix; + + if (arg->type()->isEnum()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(arg->type()); + if (metaEnum) + prefix = resolveScopePrefix(metaEnum->enclosingClass(), value); + } else if (arg->type()->isFlags()) { + static const QRegularExpression numberRegEx(QStringLiteral("^\\d+$")); // Numbers to flags + Q_ASSERT(numberRegEx.isValid()); + if (numberRegEx.match(value).hasMatch()) { + QString typeName = translateTypeForWrapperMethod(arg->type(), func->implementingClass()); + if (arg->type()->isConstant()) + typeName.remove(0, sizeof("const ") / sizeof(char) - 1); + switch (arg->type()->referenceType()) { + case NoReference: + break; + case LValueReference: + typeName.chop(1); + break; + case RValueReference: + typeName.chop(2); + break; + } + prefix = typeName + QLatin1Char('('); + suffix = QLatin1Char(')'); + } + + static const QRegularExpression enumCombinationRegEx(QStringLiteral("^([A-Za-z_][\\w:]*)\\(([^,\\(\\)]*)\\)$")); // FlagName(EnumItem|EnumItem|...) + Q_ASSERT(enumCombinationRegEx.isValid()); + const QRegularExpressionMatch match = enumCombinationRegEx.match(value); + if (prefix.isEmpty() && match.hasMatch()) { + QString flagName = match.captured(1); + QStringList enumItems = match.captured(2).split(QLatin1Char('|')); + QString scope = searchForEnumScope(func->implementingClass(), enumItems.first()); + if (!scope.isEmpty()) + scope.append(QLatin1String("::")); + + QStringList fixedEnumItems; + for (const QString &enumItem : qAsConst(enumItems)) + fixedEnumItems << QString(scope + enumItem); + + if (!fixedEnumItems.isEmpty()) { + prefix = flagName + QLatin1Char('('); + value = fixedEnumItems.join(QLatin1Char('|')); + suffix = QLatin1Char(')'); + } + } + } else if (arg->type()->typeEntry()->isValue()) { + const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), arg->type()->typeEntry()); + if (enumValueRegEx.match(value).hasMatch() && value != QLatin1String("NULL")) + prefix = resolveScopePrefix(metaClass, value); + } else if (arg->type()->isPrimitive() && arg->type()->name() == QLatin1String("int")) { + if (enumValueRegEx.match(value).hasMatch() && func->implementingClass()) + prefix = resolveScopePrefix(func->implementingClass(), value); + } else if(arg->type()->isPrimitive()) { + static const QRegularExpression unknowArgumentRegEx(QStringLiteral("^(?:[A-Za-z_][\\w:]*\\()?([A-Za-z_]\\w*)(?:\\))?$")); // [PrimitiveType(] DESIREDNAME [)] + Q_ASSERT(unknowArgumentRegEx.isValid()); + const QRegularExpressionMatch match = unknowArgumentRegEx.match(value); + if (match.hasMatch() && func->implementingClass()) { + const AbstractMetaFieldList &fields = func->implementingClass()->fields(); + for (const AbstractMetaField *field : fields) { + if (match.captured(1).trimmed() == field->name()) { + QString fieldName = field->name(); + if (field->isStatic()) { + prefix = resolveScopePrefix(func->implementingClass(), value); + fieldName.prepend(prefix); + prefix.clear(); + } else { + fieldName.prepend(QLatin1String(CPP_SELF_VAR "->")); + } + value.replace(match.captured(1), fieldName); + break; + } + } + } + } + + if (!prefix.isEmpty()) + value.prepend(prefix); + if (!suffix.isEmpty()) + value.append(suffix); + + return value; +} + +QString ShibokenGenerator::cpythonEnumName(const EnumTypeEntry* enumEntry) +{ + QString p = enumEntry->targetLangPackage(); + p.replace(QLatin1Char('.'), QLatin1Char('_')); + return cpythonEnumFlagsName(p, enumEntry->qualifiedCppName()); +} + +QString ShibokenGenerator::cpythonEnumName(const AbstractMetaEnum *metaEnum) +{ + return cpythonEnumName(metaEnum->typeEntry()); +} + +QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntry* flagsEntry) +{ + QString p = flagsEntry->targetLangPackage(); + p.replace(QLatin1Char('.'), QLatin1Char('_')); + return cpythonEnumFlagsName(p, flagsEntry->originalName()); +} + +QString ShibokenGenerator::cpythonFlagsName(const AbstractMetaEnum *metaEnum) +{ + const FlagsTypeEntry *flags = metaEnum->typeEntry()->flags(); + if (!flags) + return QString(); + return cpythonFlagsName(flags); +} + +QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClass* metaClass) +{ + return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("SpecialCastFunction"); +} + +QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName) +{ + return cpythonWrapperCPtr(metaClass->typeEntry(), argName); +} + +QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType, QString argName) +{ + if (!ShibokenGenerator::isWrapperType(metaType->typeEntry())) + return QString(); + return QLatin1String("reinterpret_cast< ::") + metaType->cppSignature() + + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(metaType) + + QLatin1String(", reinterpret_cast(") + argName + QLatin1String(")))"); +} + +QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, QString argName) +{ + if (!ShibokenGenerator::isWrapperType(type)) + return QString(); + return QLatin1String("reinterpret_cast< ::") + type->qualifiedCppName() + + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(type) + + QLatin1String(", reinterpret_cast(") + argName + QLatin1String(")))"); +} + +QString ShibokenGenerator::getFunctionReturnType(const AbstractMetaFunction* func, Options) const +{ + if (func->ownerClass() && func->isConstructor()) + return func->ownerClass()->qualifiedCppName() + QLatin1Char('*'); + + return translateTypeForWrapperMethod(func->type(), func->implementingClass()); +} + +void ShibokenGenerator::writeToPythonConversion(QTextStream & s, const AbstractMetaType* type, + const AbstractMetaClass * /* context */, + const QString& argumentName) +{ + s << cpythonToPythonConversionFunction(type) << argumentName << ')'; +} + +void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass, + const QString& inArgName, const QString& outArgName) +{ + s << cpythonToCppConversionFunction(metaClass) << inArgName << ", &" << outArgName << ')'; +} + +void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaType* type, const AbstractMetaClass* context, + const QString& inArgName, const QString& outArgName) +{ + s << cpythonToCppConversionFunction(type, context) << inArgName << ", &" << outArgName << ')'; +} + +bool ShibokenGenerator::shouldRejectNullPointerArgument(const AbstractMetaFunction* func, int argIndex) +{ + if (argIndex < 0 || argIndex >= func->arguments().count()) + return false; + + const AbstractMetaArgument* arg = func->arguments().at(argIndex); + if (isValueTypeWithCopyConstructorOnly(arg->type())) + return true; + + // Argument type is not a pointer, a None rejection should not be + // necessary because the type checking would handle that already. + if (!isPointer(arg->type())) + return false; + if (func->argumentRemoved(argIndex + 1)) + return false; + const FunctionModificationList &mods = func->modifications(); + for (const FunctionModification &funcMod : mods) { + for (const ArgumentModification &argMod : funcMod.argument_mods) { + if (argMod.index == argIndex + 1 && argMod.noNullPointers) + return true; + } + } + return false; +} + +QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunction* func, bool incRef) const +{ + QString result; + const char objType = (incRef ? 'O' : 'N'); + const AbstractMetaArgumentList &arguments = func->arguments(); + for (const AbstractMetaArgument *arg : arguments) { + if (func->argumentRemoved(arg->argumentIndex() + 1)) + continue; + + if (!func->typeReplaced(arg->argumentIndex() + 1).isEmpty()) { + result += QLatin1Char(objType); + } else if (arg->type()->isQObject() + || arg->type()->isObject() + || arg->type()->isValue() + || arg->type()->isValuePointer() + || arg->type()->isNativePointer() + || arg->type()->isEnum() + || arg->type()->isFlags() + || arg->type()->isContainer() + || arg->type()->isSmartPointer() + || arg->type()->referenceType() == LValueReference) { + result += QLatin1Char(objType); + } else if (arg->type()->isPrimitive()) { + const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) arg->type()->typeEntry(); + if (ptype->basicReferencedTypeEntry()) + ptype = ptype->basicReferencedTypeEntry(); + if (m_formatUnits.contains(ptype->name())) + result += m_formatUnits[ptype->name()]; + else + result += QLatin1Char(objType); + } else if (isCString(arg->type())) { + result += QLatin1Char('z'); + } else { + qCWarning(lcShiboken).noquote().nospace() + << "Method: " << func->ownerClass()->qualifiedCppName() + << "::" << func->signature() << " => Arg:" + << arg->name() << "index: " << arg->argumentIndex() + << " - cannot be handled properly. Use an inject-code to fix it!"; + result += QLatin1Char('?'); + } + } + return result; +} + +QString ShibokenGenerator::cpythonBaseName(const AbstractMetaType* type) +{ + if (isCString(type)) + return QLatin1String("PyString"); + return cpythonBaseName(type->typeEntry()); +} + +QString ShibokenGenerator::cpythonBaseName(const AbstractMetaClass* metaClass) +{ + return cpythonBaseName(metaClass->typeEntry()); +} + +QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type) +{ + QString baseName; + if (ShibokenGenerator::isWrapperType(type) || type->isNamespace()) { // && type->referenceType() == NoReference) { + baseName = QLatin1String("Sbk_") + type->name(); + } else if (type->isPrimitive()) { + const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) type; + while (ptype->basicReferencedTypeEntry()) + ptype = ptype->basicReferencedTypeEntry(); + if (ptype->targetLangApiName() == ptype->name()) + baseName = pythonPrimitiveTypeName(ptype->name()); + else + baseName = ptype->targetLangApiName(); + } else if (type->isEnum()) { + baseName = cpythonEnumName((const EnumTypeEntry*) type); + } else if (type->isFlags()) { + baseName = cpythonFlagsName((const FlagsTypeEntry*) type); + } else if (type->isContainer()) { + const ContainerTypeEntry* ctype = (const ContainerTypeEntry*) type; + switch (ctype->type()) { + case ContainerTypeEntry::ListContainer: + case ContainerTypeEntry::StringListContainer: + case ContainerTypeEntry::LinkedListContainer: + case ContainerTypeEntry::VectorContainer: + case ContainerTypeEntry::StackContainer: + case ContainerTypeEntry::QueueContainer: + //baseName = "PyList"; + //break; + case ContainerTypeEntry::PairContainer: + //baseName = "PyTuple"; + baseName = QLatin1String("PySequence"); + break; + case ContainerTypeEntry::SetContainer: + baseName = QLatin1String("PySet"); + break; + case ContainerTypeEntry::MapContainer: + case ContainerTypeEntry::MultiMapContainer: + case ContainerTypeEntry::HashContainer: + case ContainerTypeEntry::MultiHashContainer: + baseName = QLatin1String("PyDict"); + break; + default: + Q_ASSERT(false); + } + } else { + baseName = QLatin1String("PyObject"); + } + return baseName.replace(QLatin1String("::"), QLatin1String("_")); +} + +QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass* metaClass) +{ + return cpythonTypeName(metaClass->typeEntry()); +} + +QString ShibokenGenerator::cpythonTypeName(const TypeEntry* type) +{ + return cpythonBaseName(type) + QLatin1String("_Type"); +} + +QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry* type) +{ + return cppApiVariableName(type->targetLangPackage()) + QLatin1Char('[') + + getTypeIndexVariableName(type) + QLatin1Char(']'); +} + +QString ShibokenGenerator::converterObject(const AbstractMetaType* type) +{ + if (isCString(type)) + return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter()"); + if (isVoidPointer(type)) + return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter()"); + if (type->typeEntry()->isContainer()) { + return convertersVariableName(type->typeEntry()->targetLangPackage()) + + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']'); + } + return converterObject(type->typeEntry()); +} + +QString ShibokenGenerator::converterObject(const TypeEntry* type) +{ + if (isCppPrimitive(type)) + return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName()); + if (isWrapperType(type) || type->isEnum() || type->isFlags()) + return QString::fromLatin1("SBK_CONVERTER(%1)").arg(cpythonTypeNameExt(type)); + + if (type->isArray()) { + qDebug() << "Warning: no idea how to handle the Qt5 type " << type->qualifiedCppName(); + return QString::null; + } + + /* the typedef'd primitive types case */ + const PrimitiveTypeEntry* pte = dynamic_cast(type); + if (!pte) { + qDebug() << "Warning: the Qt5 primitive type is unknown" << type->qualifiedCppName(); + return QString::null; + } + if (pte->basicReferencedTypeEntry()) + pte = pte->basicReferencedTypeEntry(); + if (pte->isPrimitive() && !pte->isCppPrimitive() && !pte->customConversion()) + return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(pte->qualifiedCppName()); + + return convertersVariableName(type->targetLangPackage()) + + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']'); +} + +QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType* type) +{ + return cppApiVariableName(type->typeEntry()->targetLangPackage()) + QLatin1Char('[') + + 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::cpythonOperatorFunctionName(const AbstractMetaFunction* func) +{ + if (!func->isOperatorOverload()) + return QString(); + const QString pythonOp = pythonOperatorFunctionName(func->originalName()); + if (pythonOp == unknownOperator()) + qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func); + return QLatin1String("Sbk") + func->ownerClass()->name() + + QLatin1Char('_') + pythonOp; +} + +QString ShibokenGenerator::fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative) +{ + if (toNative->sourceType()) + return fixedCppTypeName(toNative->sourceType()); + return toNative->sourceTypeName(); +} +QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType* type) +{ + return fixedCppTypeName(type->typeEntry(), type->cppSignature()); +} + +static QString _fixedCppTypeName(QString typeName) +{ + typeName.remove(QLatin1Char(' ')); + typeName.replace(QLatin1Char('.'), QLatin1Char('_')); + typeName.replace(QLatin1Char(','), QLatin1Char('_')); + typeName.replace(QLatin1Char('<'), QLatin1Char('_')); + typeName.replace(QLatin1Char('>'), QLatin1Char('_')); + typeName.replace(QLatin1String("::"), QLatin1String("_")); + typeName.replace(QLatin1String("*"), QLatin1String("PTR")); + typeName.replace(QLatin1String("&"), QLatin1String("REF")); + return typeName; +} +QString ShibokenGenerator::fixedCppTypeName(const TypeEntry* type, QString typeName) +{ + if (typeName.isEmpty()) + typeName = type->qualifiedCppName(); + if (!(type->codeGeneration() & TypeEntry::GenerateTargetLang)) { + typeName.prepend(QLatin1Char('_')); + typeName.prepend(type->targetLangPackage()); + } + return _fixedCppTypeName(typeName); +} + +QString ShibokenGenerator::pythonPrimitiveTypeName(const QString& cppTypeName) +{ + QString rv = ShibokenGenerator::m_pythonPrimitiveTypeName.value(cppTypeName, QString()); + if (rv.isEmpty()) { + // activate this when some primitive types are missing, + // i.e. when shiboken itself fails to build. + // In general, this is valid while just called by isNumeric() + // used on Qt5, 2015-09-20 + if (false) { + std::cerr << "primitive type not found: " << qPrintable(cppTypeName) << std::endl; + abort(); + } + } + return rv; +} + +QString ShibokenGenerator::pythonPrimitiveTypeName(const PrimitiveTypeEntry* type) +{ + while (type->basicReferencedTypeEntry()) + type = type->basicReferencedTypeEntry(); + return pythonPrimitiveTypeName(type->name()); +} + +QString ShibokenGenerator::pythonOperatorFunctionName(QString cppOpFuncName) +{ + QString value = m_pythonOperators.value(cppOpFuncName); + if (value.isEmpty()) + return unknownOperator(); + value.prepend(QLatin1String("__")); + value.append(QLatin1String("__")); + return value; +} + +QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction* func) +{ + QString op = pythonOperatorFunctionName(func->originalName()); + if (op == unknownOperator()) + qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func); + if (func->arguments().isEmpty()) { + if (op == QLatin1String("__sub__")) + op = QLatin1String("__neg__"); + else if (op == QLatin1String("__add__")) + op = QLatin1String("__pos__"); + } else if (func->isStatic() && func->arguments().size() == 2) { + // If a operator overload function has 2 arguments and + // is static we assume that it is a reverse operator. + op = op.insert(2, QLatin1Char('r')); + } + return op; +} + +QString ShibokenGenerator::pythonRichCompareOperatorId(QString cppOpFuncName) +{ + return QLatin1String("Py_") + m_pythonOperators.value(cppOpFuncName).toUpper(); +} + +QString ShibokenGenerator::pythonRichCompareOperatorId(const AbstractMetaFunction* func) +{ + return pythonRichCompareOperatorId(func->originalName()); +} + +bool ShibokenGenerator::isNumber(QString cpythonApiName) +{ + return cpythonApiName == QLatin1String("PyInt") + || cpythonApiName == QLatin1String("PyFloat") + || cpythonApiName == QLatin1String("PyLong") + || cpythonApiName == QLatin1String("PyBool"); +} + +bool ShibokenGenerator::isNumber(const TypeEntry* type) +{ + if (!type->isPrimitive()) + return false; + return isNumber(pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type)); +} + +bool ShibokenGenerator::isNumber(const AbstractMetaType* type) +{ + return isNumber(type->typeEntry()); +} + +bool ShibokenGenerator::isPyInt(const TypeEntry* type) +{ + if (!type->isPrimitive()) + return false; + return pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type) == QLatin1String("PyInt"); +} + +bool ShibokenGenerator::isPyInt(const AbstractMetaType* type) +{ + return isPyInt(type->typeEntry()); +} + +bool ShibokenGenerator::isPairContainer(const AbstractMetaType* type) +{ + return type->isContainer() + && static_cast(type->typeEntry())->type() == ContainerTypeEntry::PairContainer; +} + +bool ShibokenGenerator::isWrapperType(const TypeEntry* type) +{ + if (type->isComplex()) + return ShibokenGenerator::isWrapperType((const ComplexTypeEntry*)type); + return type->isObject() || type->isValue() || type->isSmartPointer(); +} +bool ShibokenGenerator::isWrapperType(const ComplexTypeEntry* type) +{ + return isObjectType(type) || type->isValue() || type->isSmartPointer(); +} +bool ShibokenGenerator::isWrapperType(const AbstractMetaType* metaType) +{ + return isObjectType(metaType) + || metaType->typeEntry()->isValue() + || metaType->typeEntry()->isSmartPointer(); +} + +bool ShibokenGenerator::isPointerToWrapperType(const AbstractMetaType* type) +{ + return (isObjectType(type) && type->indirections() == 1) || type->isValuePointer(); +} + +bool ShibokenGenerator::isObjectTypeUsedAsValueType(const AbstractMetaType* type) +{ + return type->typeEntry()->isObject() && type->referenceType() == NoReference && type->indirections() == 0; +} + +bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const AbstractMetaClass* metaClass) +{ + if (!metaClass || !metaClass->typeEntry()->isValue()) + return false; + AbstractMetaFunctionList ctors = metaClass->queryFunctions(AbstractMetaClass::Constructors); + if (ctors.count() != 1) + return false; + return ctors.first()->functionType() == AbstractMetaFunction::CopyConstructorFunction; +} + +bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const TypeEntry* type) const +{ + if (!type || !type->isValue()) + return false; + return isValueTypeWithCopyConstructorOnly(AbstractMetaClass::findClass(classes(), type)); +} + +bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const AbstractMetaType* type) const +{ + if (!type || !type->typeEntry()->isValue()) + return false; + return isValueTypeWithCopyConstructorOnly(type->typeEntry()); +} + +bool ShibokenGenerator::isUserPrimitive(const TypeEntry* type) +{ + if (!type->isPrimitive()) + return false; + const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; + if (trueType->basicReferencedTypeEntry()) + trueType = trueType->basicReferencedTypeEntry(); + return trueType->isPrimitive() && !trueType->isCppPrimitive() + && trueType->qualifiedCppName() != QLatin1String("std::string"); +} + +bool ShibokenGenerator::isUserPrimitive(const AbstractMetaType* type) +{ + if (type->indirections() != 0) + return false; + return isUserPrimitive(type->typeEntry()); +} + +bool ShibokenGenerator::isCppPrimitive(const TypeEntry* type) +{ + if (type->isCppPrimitive()) + return true; + if (!type->isPrimitive()) + return false; + const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; + if (trueType->basicReferencedTypeEntry()) + trueType = trueType->basicReferencedTypeEntry(); + return trueType->qualifiedCppName() == QLatin1String("std::string"); +} + +bool ShibokenGenerator::isCppPrimitive(const AbstractMetaType* type) +{ + if (isCString(type) || isVoidPointer(type)) + return true; + if (type->indirections() != 0) + return false; + return isCppPrimitive(type->typeEntry()); +} + +bool ShibokenGenerator::shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg) +{ + return shouldDereferenceAbstractMetaTypePointer(arg->type()); +} + +bool ShibokenGenerator::shouldDereferenceAbstractMetaTypePointer(const AbstractMetaType* metaType) +{ + return metaType->referenceType() == LValueReference && isWrapperType(metaType) && !isPointer(metaType); +} + +bool ShibokenGenerator::visibilityModifiedToPrivate(const AbstractMetaFunction* func) +{ + const FunctionModificationList &mods = func->modifications(); + for (const FunctionModification &mod : mods) { + if (mod.modifiers & Modification::Private) + return true; + } + return false; +} + +QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType, bool genericNumberType) +{ + QString customCheck; + if (metaType->typeEntry()->isCustom()) { + AbstractMetaType* type; + customCheck = guessCPythonCheckFunction(metaType->typeEntry()->name(), &type); + if (type) + metaType = type; + if (!customCheck.isEmpty()) + return customCheck; + } + + if (isCppPrimitive(metaType)) { + if (isCString(metaType)) + return QLatin1String("Shiboken::String::check"); + if (isVoidPointer(metaType)) + return QLatin1String("PyObject_Check"); + return cpythonCheckFunction(metaType->typeEntry(), genericNumberType); + } else if (metaType->typeEntry()->isContainer()) { + QString typeCheck = QLatin1String("Shiboken::Conversions::"); + ContainerTypeEntry::Type type = ((const ContainerTypeEntry*)metaType->typeEntry())->type(); + if (type == ContainerTypeEntry::ListContainer + || type == ContainerTypeEntry::StringListContainer + || type == ContainerTypeEntry::LinkedListContainer + || type == ContainerTypeEntry::VectorContainer + || type == ContainerTypeEntry::StackContainer + || type == ContainerTypeEntry::SetContainer + || type == ContainerTypeEntry::QueueContainer) { + const AbstractMetaType* type = metaType->instantiations().first(); + if (isPointerToWrapperType(type)) { + typeCheck += QString::fromLatin1("checkSequenceTypes(%1, ").arg(cpythonTypeNameExt(type)); + } else if (isWrapperType(type)) { + typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast("); + typeCheck += cpythonTypeNameExt(type); + typeCheck += QLatin1String("), "); + } else { + typeCheck += QString::fromLatin1("convertibleSequenceTypes(%1, ").arg(converterObject(type)); + } + } else if (type == ContainerTypeEntry::MapContainer + || type == ContainerTypeEntry::MultiMapContainer + || type == ContainerTypeEntry::HashContainer + || type == ContainerTypeEntry::MultiHashContainer + || type == ContainerTypeEntry::PairContainer) { + QString pyType = (type == ContainerTypeEntry::PairContainer) ? QLatin1String("Pair") : QLatin1String("Dict"); + const AbstractMetaType* firstType = metaType->instantiations().first(); + const AbstractMetaType* secondType = metaType->instantiations().last(); + if (isPointerToWrapperType(firstType) && isPointerToWrapperType(secondType)) { + typeCheck += QString::fromLatin1("check%1Types(%2, %3, ").arg(pyType) + .arg(cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType)); + } else { + typeCheck += QString::fromLatin1("convertible%1Types(%2, %3, %4, %5, ") + .arg(pyType, converterObject(firstType), + isPointerToWrapperType(firstType) ? QLatin1String("true") : QLatin1String("false"), + converterObject(secondType), + isPointerToWrapperType(secondType) ? QLatin1String("true") : QLatin1String("false")); + } + } + return typeCheck; + } + return cpythonCheckFunction(metaType->typeEntry(), genericNumberType); +} + +QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool genericNumberType) +{ + QString customCheck; + if (type->isCustom()) { + AbstractMetaType* metaType; + customCheck = guessCPythonCheckFunction(type->name(), &metaType); + if (metaType) + return cpythonCheckFunction(metaType, genericNumberType); + return customCheck; + } + + 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"); + QString typeCheck; + if (type->targetLangApiName() == type->name()) + typeCheck = cpythonIsConvertibleFunction(type); + else if (type->targetLangApiName() == QLatin1String("PyUnicode")) + typeCheck = QLatin1String("Shiboken::String::check"); + else + typeCheck = type->targetLangApiName() + QLatin1String("_Check"); + return typeCheck; +} + +QString ShibokenGenerator::guessCPythonCheckFunction(const QString& type, AbstractMetaType** metaType) +{ + *metaType = 0; + if (type == QLatin1String("PyTypeObject")) + return QLatin1String("PyType_Check"); + + if (type == QLatin1String("PyBuffer")) + return QLatin1String("Shiboken::Buffer::checkType"); + + if (type == QLatin1String("str")) + return QLatin1String("Shiboken::String::check"); + + *metaType = buildAbstractMetaTypeFromString(type); + if (*metaType && !(*metaType)->typeEntry()->isCustom()) + return QString(); + + return type + QLatin1String("_Check"); +} + +QString ShibokenGenerator::guessCPythonIsConvertible(const QString& type) +{ + if (type == QLatin1String("PyTypeObject")) + return QLatin1String("PyType_Check"); + + AbstractMetaType* metaType = buildAbstractMetaTypeFromString(type); + if (metaType && !metaType->typeEntry()->isCustom()) + return cpythonIsConvertibleFunction(metaType); + + return type + QLatin1String("_Check"); +} + +QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry* type, + bool /* genericNumberType */, + bool /* checkExact */) +{ + if (isWrapperType(type)) { + QString result = QLatin1String("Shiboken::Conversions::"); + result += (type->isValue() && !isValueTypeWithCopyConstructorOnly(type)) + ? QLatin1String("isPythonToCppValueConvertible") + : QLatin1String("isPythonToCppPointerConvertible"); + result += QLatin1String("(reinterpret_cast(") + + cpythonTypeNameExt(type) + QLatin1String("), "); + return result; + } + return QString::fromLatin1("Shiboken::Conversions::isPythonToCppConvertible(%1, ") + .arg(converterObject(type)); +} +QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType* metaType, + bool /* genericNumberType */) +{ + QString customCheck; + if (metaType->typeEntry()->isCustom()) { + AbstractMetaType* type; + customCheck = guessCPythonCheckFunction(metaType->typeEntry()->name(), &type); + if (type) + metaType = type; + if (!customCheck.isEmpty()) + return customCheck; + } + + if (isWrapperType(metaType)) { + QString result = QLatin1String("Shiboken::Conversions::"); + if (isPointer(metaType) || isValueTypeWithCopyConstructorOnly(metaType)) + result += QLatin1String("isPythonToCppPointerConvertible"); + else if (metaType->referenceType() == LValueReference) + result += QLatin1String("isPythonToCppReferenceConvertible"); + else + result += QLatin1String("isPythonToCppValueConvertible"); + result += QLatin1String("(reinterpret_cast(") + + cpythonTypeNameExt(metaType) + QLatin1String("), "); + return result; + } + return QStringLiteral("Shiboken::Conversions::isPythonToCppConvertible(%1, ") + .arg(converterObject(metaType)); +} + +QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaArgument *metaArg, bool genericNumberType) +{ + return cpythonIsConvertibleFunction(metaArg->type(), genericNumberType); +} + +QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClass* metaClass) +{ + return QLatin1String("Shiboken::Conversions::pythonToCppPointer(reinterpret_cast(") + + cpythonTypeNameExt(metaClass->typeEntry()) + QLatin1String("), "); +} + +QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType *type, + const AbstractMetaClass * /* context */) +{ + if (isWrapperType(type)) { + return QLatin1String("Shiboken::Conversions::pythonToCpp") + + (isPointer(type) ? QLatin1String("Pointer") : QLatin1String("Copy")) + + QLatin1String("(reinterpret_cast(") + + cpythonTypeNameExt(type) + QLatin1String("), "); + } + return QStringLiteral("Shiboken::Conversions::pythonToCppCopy(%1, ") + .arg(converterObject(type)); +} + +QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType *type, + const AbstractMetaClass * /* context */) +{ + if (isWrapperType(type)) { + QString conversion; + if (type->referenceType() == LValueReference && !(type->isValue() && type->isConstant()) && !isPointer(type)) + conversion = QLatin1String("reference"); + else if (type->isValue() || type->isSmartPointer()) + conversion = QLatin1String("copy"); + else + conversion = QLatin1String("pointer"); + QString result = QLatin1String("Shiboken::Conversions::") + conversion + + QLatin1String("ToPython(reinterpret_cast(") + + cpythonTypeNameExt(type) + QLatin1String("), "); + if (conversion != QLatin1String("pointer")) + result += QLatin1Char('&'); + return result; + } + return QStringLiteral("Shiboken::Conversions::copyToPython(%1, %2") + .arg(converterObject(type), + (isCString(type) || isVoidPointer(type)) ? QString() : QLatin1String("&")); +} + +QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaClass* metaClass) +{ + return cpythonToPythonConversionFunction(metaClass->typeEntry()); +} + +QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry* type) +{ + if (isWrapperType(type)) { + const QString conversion = type->isValue() ? QLatin1String("copy") : QLatin1String("pointer"); + QString result = QLatin1String("Shiboken::Conversions::") + conversion + + QLatin1String("ToPython(reinterpret_cast(") + cpythonTypeNameExt(type) + + QLatin1String("), "); + if (conversion != QLatin1String("pointer")) + result += QLatin1Char('&'); + return result; + } + + return QStringLiteral("Shiboken::Conversions::copyToPython(%1, &").arg(converterObject(type)); +} + +QString ShibokenGenerator::argumentString(const AbstractMetaFunction *func, + const AbstractMetaArgument *argument, + Options options) const +{ + QString modified_type; + if (!(options & OriginalTypeDescription)) + modified_type = func->typeReplaced(argument->argumentIndex() + 1); + QString arg; + + if (modified_type.isEmpty()) + arg = translateType(argument->type(), func->implementingClass(), options); + else + arg = modified_type.replace(QLatin1Char('$'), QLatin1Char('.')); + + if (!(options & Generator::SkipName)) { + arg += QLatin1Char(' '); + arg += argument->name(); + } + + if ((options & Generator::SkipDefaultValues) != Generator::SkipDefaultValues && + !argument->originalDefaultValueExpression().isEmpty()) + { + QString default_value = argument->originalDefaultValueExpression(); + if (default_value == QLatin1String("NULL")) + default_value = QLatin1String(NULL_VALUE); + + //WORKAROUND: fix this please + if (default_value.startsWith(QLatin1String("new "))) + default_value.remove(0, 4); + + arg += QLatin1String(" = ") + default_value; + } + + return arg; +} + +void ShibokenGenerator::writeArgument(QTextStream &s, + const AbstractMetaFunction *func, + const AbstractMetaArgument *argument, + Options options) const +{ + s << argumentString(func, argument, options); +} + +void ShibokenGenerator::writeFunctionArguments(QTextStream &s, + const AbstractMetaFunction *func, + Options options) const +{ + AbstractMetaArgumentList arguments = func->arguments(); + + if (options & Generator::WriteSelf) { + s << func->implementingClass()->name() << '&'; + if (!(options & SkipName)) + s << " " PYTHON_SELF_VAR; + } + + int argUsed = 0; + for (int i = 0; i < arguments.size(); ++i) { + if ((options & Generator::SkipRemovedArguments) && func->argumentRemoved(i+1)) + continue; + + if ((options & Generator::WriteSelf) || argUsed != 0) + s << ", "; + writeArgument(s, func, arguments[i], options); + argUsed++; + } +} + +QString ShibokenGenerator::functionReturnType(const AbstractMetaFunction* func, Options options) const +{ + QString modifiedReturnType = QString(func->typeReplaced(0)); + if (!modifiedReturnType.isNull() && !(options & OriginalTypeDescription)) + return modifiedReturnType; + else + return translateType(func->type(), func->implementingClass(), options); +} + +QString ShibokenGenerator::functionSignature(const AbstractMetaFunction *func, + QString prepend, + QString append, + Options options, + int /* argCount */) const +{ + QString result; + QTextStream s(&result); + // The actual function + if (!(func->isEmptyFunction() || + func->isNormal() || + func->isSignal())) { + options |= Generator::SkipReturnType; + } else { + s << functionReturnType(func, options) << ' '; + } + + // name + QString name(func->originalName()); + if (func->isConstructor()) + name = wrapperName(func->ownerClass()); + + s << prepend << name << append << '('; + writeFunctionArguments(s, func, options); + s << ')'; + + if (func->isConstant() && !(options & Generator::ExcludeMethodConst)) + s << " const"; + + return result; +} + +void ShibokenGenerator::writeArgumentNames(QTextStream &s, + const AbstractMetaFunction *func, + Options options) const +{ + AbstractMetaArgumentList arguments = func->arguments(); + int argCount = 0; + for (int j = 0, max = arguments.size(); j < max; j++) { + + if ((options & Generator::SkipRemovedArguments) && (func->argumentRemoved(arguments.at(j)->argumentIndex()+1))) + continue; + + s << ((argCount > 0) ? ", " : "") << arguments.at(j)->name(); + + if (((options & Generator::VirtualCall) == 0) + && (!func->conversionRule(TypeSystem::NativeCode, arguments.at(j)->argumentIndex() + 1).isEmpty() + || !func->conversionRule(TypeSystem::TargetLangCode, arguments.at(j)->argumentIndex() + 1).isEmpty()) + && !func->isConstructor()) { + s << CONV_RULE_OUT_VAR_SUFFIX; + } + + argCount++; + } +} + +void ShibokenGenerator::writeFunctionCall(QTextStream& s, + const AbstractMetaFunction* func, + Options options) const +{ + if (!(options & Generator::SkipName)) + s << (func->isConstructor() ? func->ownerClass()->qualifiedCppName() : func->originalName()); + s << '('; + writeArgumentNames(s, func, options); + s << ')'; +} + +void ShibokenGenerator::writeUnusedVariableCast(QTextStream& s, const QString& variableName) +{ + s << INDENT << "SBK_UNUSED(" << variableName<< ')' << endl; +} + +AbstractMetaFunctionList ShibokenGenerator::filterFunctions(const AbstractMetaClass* metaClass) +{ + AbstractMetaFunctionList result; + const AbstractMetaFunctionList &funcs = metaClass->functions(); + for (AbstractMetaFunction *func : funcs) { + if (func->isSignal() || func->isDestructor() || func->usesRValueReferences() + || (func->isModifiedRemoved() && !func->isAbstract() + && (!avoidProtectedHack() || !func->isProtected()))) + continue; + result << func; + } + return result; +} + +ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverters() const +{ + ExtendedConverterData extConvs; + const AbstractMetaClassList &classList = classes(); + for (const AbstractMetaClass *metaClass : classList) { + // Use only the classes for the current module. + if (!shouldGenerate(metaClass)) + continue; + const AbstractMetaFunctionList &overloads = metaClass->operatorOverloads(AbstractMetaClass::ConversionOp); + for (AbstractMetaFunction *convOp : overloads) { + // Get only the conversion operators that return a type from another module, + // that are value-types and were not removed in the type system. + const TypeEntry* convType = convOp->type()->typeEntry(); + if ((convType->codeGeneration() & TypeEntry::GenerateTargetLang) + || !convType->isValue() + || convOp->isModifiedRemoved()) + continue; + extConvs[convType].append(convOp->ownerClass()); + } + } + return extConvs; +} + +QVector ShibokenGenerator::getPrimitiveCustomConversions() +{ + QVector conversions; + const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes(); + for (const PrimitiveTypeEntry *type : primitiveTypeList) { + if (!shouldGenerateTypeEntry(type) || !isUserPrimitive(type) || !type->customConversion()) + continue; + + conversions << type->customConversion(); + } + return conversions; +} + +static QString getArgumentsFromMethodCall(const QString& str) +{ + // It would be way nicer to be able to use a Perl like + // regular expression that accepts temporary variables + // to count the parenthesis. + // For more information check this: + // http://perl.plover.com/yak/regex/samples/slide083.html + static QLatin1String funcCall("%CPPSELF.%FUNCTION_NAME"); + int pos = str.indexOf(funcCall); + if (pos == -1) + return QString(); + pos = pos + funcCall.size(); + while (str.at(pos) == QLatin1Char(' ') || str.at(pos) == QLatin1Char('\t')) + ++pos; + if (str.at(pos) == QLatin1Char('(')) + ++pos; + int begin = pos; + int counter = 1; + while (counter != 0) { + if (str.at(pos) == QLatin1Char('(')) + ++counter; + else if (str.at(pos) == QLatin1Char(')')) + --counter; + ++pos; + } + return str.mid(begin, pos-begin-1); +} + +QString ShibokenGenerator::getCodeSnippets(const CodeSnipList& codeSnips, + TypeSystem::CodeSnipPosition position, + TypeSystem::Language language) +{ + QString code; + QTextStream c(&code); + for (const CodeSnip &snip : codeSnips) { + if ((position != TypeSystem::CodeSnipPositionAny && snip.position != position) || !(snip.language & language)) + continue; + QString snipCode; + QTextStream sc(&snipCode); + formatCode(sc, snip.code(), INDENT); + c << snipCode; + } + return code; +} +void ShibokenGenerator::processCodeSnip(QString& code, const AbstractMetaClass* context) +{ + if (context) { + // Replace template variable by the Python Type object + // for the class context in which the variable is used. + code.replace(QLatin1String("%PYTHONTYPEOBJECT"), + cpythonTypeName(context) + QLatin1String(".super.ht_type")); + code.replace(QLatin1String("%TYPE"), wrapperName(context)); + code.replace(QLatin1String("%CPPTYPE"), context->name()); + } + + // replace "toPython" converters + replaceConvertToPythonTypeSystemVariable(code); + + // replace "toCpp" converters + replaceConvertToCppTypeSystemVariable(code); + + // replace "isConvertible" check + replaceIsConvertibleToCppTypeSystemVariable(code); + + // replace "checkType" check + replaceTypeCheckTypeSystemVariable(code); +} + +ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentReplacement(const AbstractMetaFunction* func, + bool usePyArgs, TypeSystem::Language language, + const AbstractMetaArgument* lastArg) +{ + ArgumentVarReplacementList argReplacements; + TypeSystem::Language convLang = (language == TypeSystem::TargetLangCode) + ? TypeSystem::NativeCode : TypeSystem::TargetLangCode; + int removed = 0; + for (int i = 0; i < func->arguments().size(); ++i) { + const AbstractMetaArgument* arg = func->arguments().at(i); + QString argValue; + if (language == TypeSystem::TargetLangCode) { + bool hasConversionRule = !func->conversionRule(convLang, i+1).isEmpty(); + bool argRemoved = func->argumentRemoved(i+1); + removed = removed + (int) argRemoved; + if (argRemoved && hasConversionRule) + argValue = arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX); + else if (argRemoved || (lastArg && arg->argumentIndex() > lastArg->argumentIndex())) + argValue = QLatin1String(CPP_ARG_REMOVED) + QString::number(i); + if (!argRemoved && argValue.isEmpty()) { + int argPos = i - removed; + const AbstractMetaType* type = arg->type(); + QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1); + if (!typeReplaced.isEmpty()) { + AbstractMetaType* builtType = buildAbstractMetaTypeFromString(typeReplaced); + if (builtType) + type = builtType; + } + if (type->typeEntry()->isCustom()) { + argValue = usePyArgs + ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argPos) + : QLatin1String(PYTHON_ARG); + } else { + argValue = hasConversionRule + ? arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX) + : QLatin1String(CPP_ARG) + QString::number(argPos); + if (isWrapperType(type)) { + if (type->referenceType() == LValueReference && !isPointer(type)) + argValue.prepend(QLatin1Char('*')); + } + } + } + } else { + argValue = arg->name(); + } + if (!argValue.isEmpty()) + argReplacements << ArgumentVarReplacementPair(arg, argValue); + + } + return argReplacements; +} + +void ShibokenGenerator::writeCodeSnips(QTextStream& s, + const CodeSnipList& codeSnips, + TypeSystem::CodeSnipPosition position, + TypeSystem::Language language, + const AbstractMetaClass* context) +{ + QString code = getCodeSnippets(codeSnips, position, language); + if (code.isEmpty()) + return; + processCodeSnip(code, context); + s << INDENT << "// Begin code injection" << endl; + s << code; + 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, + TypeSystem::Language language, + const AbstractMetaFunction* func, + const AbstractMetaArgument* lastArg) +{ + QString code = getCodeSnippets(codeSnips, position, language); + if (code.isEmpty()) + return; + + // Calculate the real number of arguments. + int argsRemoved = 0; + for (int i = 0; i < func->arguments().size(); i++) { + if (func->argumentRemoved(i+1)) + argsRemoved++; + } + + OverloadData od(getFunctionGroups(func->implementingClass())[func->name()], this); + bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(od); + + // Replace %PYARG_# variables. + code.replace(QLatin1String("%PYARG_0"), QLatin1String(PYTHON_RETURN_VAR)); + + static const QRegularExpression pyArgsRegex(QStringLiteral("%PYARG_(\\d+)")); + Q_ASSERT(pyArgsRegex.isValid()); + if (language == TypeSystem::TargetLangCode) { + if (usePyArgs) { + code.replace(pyArgsRegex, QLatin1String(PYTHON_ARGS"[\\1-1]")); + } else { + static const QRegularExpression pyArgsRegexCheck(QStringLiteral("%PYARG_([2-9]+)")); + Q_ASSERT(pyArgsRegexCheck.isValid()); + const QRegularExpressionMatch match = pyArgsRegexCheck.match(code); + if (match.hasMatch()) { + qCWarning(lcShiboken).noquote().nospace() + << msgWrongIndex("%PYARG", match.captured(1), func); + return; + } + code.replace(QLatin1String("%PYARG_1"), QLatin1String(PYTHON_ARG)); + } + } else { + // Replaces the simplest case of attribution to a + // 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)")); + } + + // Replace %ARG#_TYPE variables. + const AbstractMetaArgumentList &arguments = func->arguments(); + for (const AbstractMetaArgument *arg : arguments) { + QString argTypeVar = QStringLiteral("%ARG%1_TYPE").arg(arg->argumentIndex() + 1); + QString argTypeVal = arg->type()->cppSignature(); + code.replace(argTypeVar, argTypeVal); + } + + static const QRegularExpression cppArgTypeRegexCheck(QStringLiteral("%ARG(\\d+)_TYPE")); + Q_ASSERT(cppArgTypeRegexCheck.isValid()); + QRegularExpressionMatchIterator rit = cppArgTypeRegexCheck.globalMatch(code); + while (rit.hasNext()) { + QRegularExpressionMatch match = rit.next(); + qCWarning(lcShiboken).noquote().nospace() + << msgWrongIndex("%ARG#_TYPE", match.captured(1), func); + } + + // Replace template variable for return variable name. + if (func->isConstructor()) { + code.replace(QLatin1String("%0."), QLatin1String("cptr->")); + code.replace(QLatin1String("%0"), QLatin1String("cptr")); + } else if (func->type()) { + QString returnValueOp = isPointerToWrapperType(func->type()) + ? QLatin1String("%1->") : QLatin1String("%1."); + if (ShibokenGenerator::isWrapperType(func->type())) + code.replace(QLatin1String("%0."), returnValueOp.arg(QLatin1String(CPP_RETURN_VAR))); + code.replace(QLatin1String("%0"), QLatin1String(CPP_RETURN_VAR)); + } + + // Replace template variable for self Python object. + QString pySelf = (language == TypeSystem::NativeCode) ? QLatin1String("pySelf") : QLatin1String(PYTHON_SELF_VAR); + code.replace(QLatin1String("%PYSELF"), pySelf); + + // Replace template variable for a pointer to C++ of this object. + if (func->implementingClass()) { + QString replacement = func->isStatic() ? QLatin1String("%1::") : QLatin1String("%1->"); + QString cppSelf; + if (func->isStatic()) + cppSelf = func->ownerClass()->qualifiedCppName(); + else if (language == TypeSystem::NativeCode) + cppSelf = QLatin1String("this"); + else + cppSelf = QLatin1String(CPP_SELF_VAR); + + // On comparison operator CPP_SELF_VAR is always a reference. + if (func->isComparisonOperator()) + replacement = QLatin1String("%1."); + + if (func->isVirtual() && !func->isAbstract() && (!avoidProtectedHack() || !func->isProtected())) { + QString methodCallArgs = getArgumentsFromMethodCall(code); + if (!methodCallArgs.isNull()) { + const QString pattern = QStringLiteral("%CPPSELF.%FUNCTION_NAME(%1)").arg(methodCallArgs); + if (func->name() == QLatin1String("metaObject")) { + QString wrapperClassName = wrapperName(func->ownerClass()); + QString cppSelfVar = avoidProtectedHack() + ? QLatin1String("%CPPSELF") + : QStringLiteral("reinterpret_cast<%1*>(%CPPSELF)").arg(wrapperClassName); + code.replace(pattern, + QString::fromLatin1("(Shiboken::Object::hasCppWrapper(reinterpret_cast(%1))" + " ? %2->::%3::%FUNCTION_NAME(%4)" + " : %CPPSELF.%FUNCTION_NAME(%4))").arg(pySelf, cppSelfVar, wrapperClassName, methodCallArgs)); + } else { + code.replace(pattern, + QString::fromLatin1("(Shiboken::Object::hasCppWrapper(reinterpret_cast(%1))" + " ? %CPPSELF->::%TYPE::%FUNCTION_NAME(%2)" + " : %CPPSELF.%FUNCTION_NAME(%2))").arg(pySelf, methodCallArgs)); + } + } + } + + code.replace(QLatin1String("%CPPSELF."), replacement.arg(cppSelf)); + code.replace(QLatin1String("%CPPSELF"), cppSelf); + + if (code.indexOf(QLatin1String("%BEGIN_ALLOW_THREADS")) > -1) { + if (code.count(QLatin1String("%BEGIN_ALLOW_THREADS")) == code.count(QLatin1String("%END_ALLOW_THREADS"))) { + code.replace(QLatin1String("%BEGIN_ALLOW_THREADS"), QLatin1String(BEGIN_ALLOW_THREADS)); + code.replace(QLatin1String("%END_ALLOW_THREADS"), QLatin1String(END_ALLOW_THREADS)); + } else { + qCWarning(lcShiboken) << "%BEGIN_ALLOW_THREADS and %END_ALLOW_THREADS mismatch"; + } + } + + // replace template variable for the Python Type object for the + // class implementing the method in which the code snip is written + if (func->isStatic()) { + code.replace(QLatin1String("%PYTHONTYPEOBJECT"), + cpythonTypeName(func->implementingClass()) + QLatin1String(".super.ht_type")); + } else { + code.replace(QLatin1String("%PYTHONTYPEOBJECT."), pySelf + QLatin1String("->ob_type->")); + code.replace(QLatin1String("%PYTHONTYPEOBJECT"), pySelf + QLatin1String("->ob_type")); + } + } + + // Replaces template %ARGUMENT_NAMES and %# variables by argument variables and values. + // Replaces template variables %# for individual arguments. + const ArgumentVarReplacementList &argReplacements = getArgumentReplacement(func, usePyArgs, language, lastArg); + + QStringList args; + for (const ArgumentVarReplacementPair &pair : argReplacements) { + if (pair.second.startsWith(QLatin1String(CPP_ARG_REMOVED))) + continue; + args << pair.second; + } + code.replace(QLatin1String("%ARGUMENT_NAMES"), args.join(QLatin1String(", "))); + + for (const ArgumentVarReplacementPair &pair : argReplacements) { + const AbstractMetaArgument* arg = pair.first; + int idx = arg->argumentIndex() + 1; + AbstractMetaType* type = arg->type(); + QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1); + if (!typeReplaced.isEmpty()) { + AbstractMetaType* builtType = buildAbstractMetaTypeFromString(typeReplaced); + if (builtType) + type = builtType; + } + if (isWrapperType(type)) { + QString replacement = pair.second; + if (type->referenceType() == LValueReference && !isPointer(type)) + replacement.remove(0, 1); + if (type->referenceType() == LValueReference || isPointer(type)) + code.replace(QString::fromLatin1("%%1.").arg(idx), replacement + QLatin1String("->")); + } + code.replace(placeHolderRegex(idx), pair.second); + } + + if (language == TypeSystem::NativeCode) { + // Replaces template %PYTHON_ARGUMENTS variable with a pointer to the Python tuple + // containing the converted virtual method arguments received from C++ to be passed + // to the Python override. + code.replace(QLatin1String("%PYTHON_ARGUMENTS"), QLatin1String(PYTHON_ARGS)); + + // replace variable %PYTHON_METHOD_OVERRIDE for a pointer to the Python method + // override for the C++ virtual method in which this piece of code was inserted + code.replace(QLatin1String("%PYTHON_METHOD_OVERRIDE"), QLatin1String(PYTHON_OVERRIDE_VAR)); + } + + if (avoidProtectedHack()) { + // If the function being processed was added by the user via type system, + // Shiboken needs to find out if there are other overloads for the same method + // name and if any of them is of the protected visibility. This is used to replace + // calls to %FUNCTION_NAME on user written custom code for calls to the protected + // dispatcher. + bool hasProtectedOverload = false; + if (func->isUserAdded()) { + const AbstractMetaFunctionList &funcs = getFunctionOverloads(func->ownerClass(), func->name()); + for (const AbstractMetaFunction *f : funcs) + hasProtectedOverload |= f->isProtected(); + } + + if (func->isProtected() || hasProtectedOverload) { + code.replace(QLatin1String("%TYPE::%FUNCTION_NAME"), + QStringLiteral("%1::%2_protected") + .arg(wrapperName(func->ownerClass()), func->originalName())); + code.replace(QLatin1String("%FUNCTION_NAME"), + func->originalName() + QLatin1String("_protected")); + } + } + + if (func->isConstructor() && shouldGenerateCppWrapper(func->ownerClass())) + code.replace(QLatin1String("%TYPE"), wrapperName(func->ownerClass())); + + if (func->ownerClass()) + code.replace(QLatin1String("%CPPTYPE"), func->ownerClass()->name()); + + replaceTemplateVariables(code, func); + + processCodeSnip(code); + s << INDENT << "// Begin code injection" << endl; + s << code; + s << INDENT << "// End of code injection" << endl; +} + +// Returns true if the string is an expression, +// and false if it is a variable. +static bool isVariable(const QString& code) +{ + static const QRegularExpression expr(QStringLiteral("^\\s*\\*?\\s*[A-Za-z_][A-Za-z_0-9.]*\\s*(?:\\[[^\\[]+\\])*$")); + Q_ASSERT(expr.isValid()); + return expr.match(code.trimmed()).hasMatch(); +} + +// A miniature normalizer that puts a type string into a format +// suitable for comparison with AbstractMetaType::cppSignature() +// result. +static QString miniNormalizer(const QString& varType) +{ + QString normalized = varType.trimmed(); + if (normalized.isEmpty()) + return normalized; + if (normalized.startsWith(QLatin1String("::"))) + normalized.remove(0, 2); + QString suffix; + while (normalized.endsWith(QLatin1Char('*')) || normalized.endsWith(QLatin1Char('&'))) { + suffix.prepend(normalized.at(normalized.count() - 1)); + normalized.chop(1); + normalized = normalized.trimmed(); + } + const QString result = normalized + QLatin1Char(' ') + suffix; + return result.trimmed(); +} +// The position must indicate the first character after the opening '('. +// ATTENTION: do not modify this function to trim any resulting string! +// This must be done elsewhere. +static QString getConverterTypeSystemVariableArgument(const QString& code, int pos) +{ + QString arg; + int parenthesisDepth = 0; + int count = 0; + while (pos + count < code.count()) { + char c = code.at(pos+count).toLatin1(); // toAscii is gone + if (c == '(') { + ++parenthesisDepth; + } else if (c == ')') { + if (parenthesisDepth == 0) { + arg = code.mid(pos, count).trimmed(); + break; + } + --parenthesisDepth; + } + ++count; + } + if (parenthesisDepth != 0) + qFatal("Unbalanced parenthesis on type system converter variable call."); + return arg; +} +typedef QPair StringPair; +void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code) +{ + QVector replacements; + QRegularExpressionMatchIterator rit = m_typeSystemConvRegEx[converterVariable].globalMatch(code); + while (rit.hasNext()) { + const QRegularExpressionMatch match = rit.next(); + const QStringList list = match.capturedTexts(); + QString conversionString = list.first(); + QString conversionTypeName = list.last(); + const AbstractMetaType* conversionType = buildAbstractMetaTypeFromString(conversionTypeName); + if (!conversionType) { + qFatal(qPrintable(QString::fromLatin1("Could not find type '%1' for use in '%2' conversion. " + "Make sure to use the full C++ name, e.g. 'Namespace::Class'.") + .arg(conversionTypeName).arg(m_typeSystemConvName[converterVariable])), NULL); + + } + QString conversion; + QTextStream c(&conversion); + switch (converterVariable) { + case TypeSystemToCppFunction: { + int end = match.capturedStart(); + int start = end; + while (start > 0 && code.at(start) != QLatin1Char('\n')) + --start; + while (code.at(start).isSpace()) + ++start; + QString varType = code.mid(start, end - start); + conversionString = varType + list.first(); + varType = miniNormalizer(varType); + 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); + } + c << getFullTypeName(conversionType) << ' ' << varName; + writeMinimalConstructorExpression(c, conversionType); + c << ';' << endl; + Indentation indent(INDENT); + c << INDENT; + } + c << cpythonToCppConversionFunction(conversionType); + QString prefix; + if (varName.startsWith(QLatin1Char('*'))) { + varName.remove(0, 1); + varName = varName.trimmed(); + } else { + prefix = QLatin1Char('&'); + } + QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd()); + conversionString += arg; + c << arg << ", " << prefix << '(' << varName << ')'; + break; + } + case TypeSystemCheckFunction: + conversion = cpythonCheckFunction(conversionType); + if (conversionType->typeEntry()->isPrimitive() + && (conversionType->typeEntry()->name() == QLatin1String("PyObject") + || !conversion.endsWith(QLatin1Char(' ')))) { + c << '('; + break; + } + case TypeSystemIsConvertibleFunction: + if (conversion.isEmpty()) + conversion = cpythonIsConvertibleFunction(conversionType); + case TypeSystemToPythonFunction: + if (conversion.isEmpty()) + conversion = cpythonToPythonConversionFunction(conversionType); + 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); + } + if (conversion.contains(QLatin1String("%in"))) { + conversion.prepend(QLatin1Char('(')); + conversion.replace(QLatin1String("%in"), arg); + } else { + c << arg; + } + } + } + replacements.append(qMakePair(conversionString, conversion)); + } + for (const StringPair &rep : qAsConst(replacements)) + code.replace(rep.first, rep.second); +} + +bool ShibokenGenerator::injectedCodeUsesCppSelf(const AbstractMetaFunction* func) +{ + CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode); + for (const CodeSnip &snip : qAsConst(snips)) { + if (snip.code().contains(QLatin1String("%CPPSELF"))) + return true; + } + return false; +} + +bool ShibokenGenerator::injectedCodeUsesPySelf(const AbstractMetaFunction* func) +{ + CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode); + for (const CodeSnip &snip : qAsConst(snips)) { + if (snip.code().contains(QLatin1String("%PYSELF"))) + return true; + } + return false; +} + +bool ShibokenGenerator::injectedCodeCallsCppFunction(const AbstractMetaFunction* func) +{ + QString funcCall = func->originalName() + QLatin1Char('('); + QString wrappedCtorCall; + if (func->isConstructor()) { + funcCall.prepend(QLatin1String("new ")); + wrappedCtorCall = QStringLiteral("new %1(").arg(wrapperName(func->ownerClass())); + } + CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode); + for (const CodeSnip &snip : qAsConst(snips)) { + if (snip.code().contains(QLatin1String("%FUNCTION_NAME(")) || snip.code().contains(funcCall) + || (func->isConstructor() + && ((func->ownerClass()->isPolymorphic() && snip.code().contains(wrappedCtorCall)) + || snip.code().contains(QLatin1String("new %TYPE(")))) + ) + return true; + } + return false; +} + +bool ShibokenGenerator::injectedCodeCallsPythonOverride(const AbstractMetaFunction* func) +{ + static const QRegularExpression overrideCallRegexCheck(QStringLiteral("PyObject_Call\\s*\\(\\s*%PYTHON_METHOD_OVERRIDE\\s*,")); + Q_ASSERT(overrideCallRegexCheck.isValid()); + CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode); + for (const CodeSnip &snip : qAsConst(snips)) { + if (snip.code().contains(overrideCallRegexCheck)) + return true; + } + return false; +} + +bool ShibokenGenerator::injectedCodeHasReturnValueAttribution(const AbstractMetaFunction* func, TypeSystem::Language language) +{ + static const QRegularExpression retValAttributionRegexCheck_native(QStringLiteral("%0\\s*=[^=]\\s*.+")); + Q_ASSERT(retValAttributionRegexCheck_native.isValid()); + static const QRegularExpression retValAttributionRegexCheck_target(QStringLiteral("%PYARG_0\\s*=[^=]\\s*.+")); + Q_ASSERT(retValAttributionRegexCheck_target.isValid()); + CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, language); + for (const CodeSnip &snip : qAsConst(snips)) { + if (language == TypeSystem::TargetLangCode) { + if (snip.code().contains(retValAttributionRegexCheck_target)) + return true; + } else { + if (snip.code().contains(retValAttributionRegexCheck_native)) + return true; + } + } + return false; +} + +bool ShibokenGenerator::injectedCodeUsesArgument(const AbstractMetaFunction* func, int argumentIndex) +{ + CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny); + const QRegularExpression argRegEx = placeHolderRegex(argumentIndex + 1); + for (const CodeSnip &snip : qAsConst(snips)) { + QString code = snip.code(); + if (code.contains(QLatin1String("%ARGUMENT_NAMES")) || code.contains(argRegEx)) + return true; + } + return false; +} + +bool ShibokenGenerator::hasMultipleInheritanceInAncestry(const AbstractMetaClass* metaClass) +{ + if (!metaClass || metaClass->baseClassNames().isEmpty()) + return false; + if (metaClass->baseClassNames().size() > 1) + return true; + return hasMultipleInheritanceInAncestry(metaClass->baseClass()); +} + +typedef QMap FunctionGroupMap; +typedef FunctionGroupMap::const_iterator FunctionGroupMapIt; + +bool ShibokenGenerator::classNeedsGetattroFunction(const AbstractMetaClass* metaClass) +{ + if (!metaClass) + return false; + if (metaClass->typeEntry()->isSmartPointer()) + return true; + const FunctionGroupMap &functionGroup = getFunctionGroups(metaClass); + for (FunctionGroupMapIt it = functionGroup.cbegin(), end = functionGroup.cend(); it != end; ++it) { + AbstractMetaFunctionList overloads; + for (AbstractMetaFunction *func : qAsConst(it.value())) { + if (func->isAssignmentOperator() || func->isCastOperator() || func->isModifiedRemoved() + || func->isPrivate() || func->ownerClass() != func->implementingClass() + || func->isConstructor() || func->isOperatorOverload()) + continue; + overloads.append(func); + } + if (overloads.isEmpty()) + continue; + if (OverloadData::hasStaticAndInstanceFunctions(overloads)) + return true; + } + return false; +} + +bool ShibokenGenerator::classNeedsSetattroFunction(const AbstractMetaClass *metaClass) +{ + if (!metaClass) + return false; + if (metaClass->typeEntry()->isSmartPointer()) + return true; + return false; +} + +AbstractMetaFunctionList ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass) +{ + AbstractMetaFunctionList methods; + if (metaClass) { + const FunctionGroupMap &functionGroups = getFunctionGroups(metaClass); + for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) { + AbstractMetaFunctionList overloads; + for (AbstractMetaFunction *func : qAsConst(it.value())) { + if (func->isAssignmentOperator() || func->isCastOperator() || func->isModifiedRemoved() + || func->isPrivate() || func->ownerClass() != func->implementingClass() + || func->isConstructor() || func->isOperatorOverload()) + continue; + overloads.append(func); + } + if (overloads.isEmpty()) + continue; + if (OverloadData::hasStaticAndInstanceFunctions(overloads)) + methods.append(overloads.first()); + } + } + return methods; +} + +AbstractMetaClassList ShibokenGenerator::getBaseClasses(const AbstractMetaClass* metaClass) const +{ + AbstractMetaClassList baseClasses; + if (metaClass) { + const QStringList &baseClassNames = metaClass->baseClassNames(); + for (const QString &parent : baseClassNames) { + AbstractMetaClass *clazz = AbstractMetaClass::findClass(classes(), parent); + if (clazz) + baseClasses << clazz; + } + } + return baseClasses; +} + +const AbstractMetaClass* ShibokenGenerator::getMultipleInheritingClass(const AbstractMetaClass* metaClass) +{ + if (!metaClass || metaClass->baseClassNames().isEmpty()) + return 0; + if (metaClass->baseClassNames().size() > 1) + return metaClass; + return getMultipleInheritingClass(metaClass->baseClass()); +} + +AbstractMetaClassList ShibokenGenerator::getAllAncestors(const AbstractMetaClass* metaClass) const +{ + AbstractMetaClassList result; + if (metaClass) { + AbstractMetaClassList baseClasses = getBaseClasses(metaClass); + for (AbstractMetaClass *base : qAsConst(baseClasses)) { + result.append(base); + result.append(getAllAncestors(base)); + } + } + return result; +} + +QString ShibokenGenerator::getModuleHeaderFileName(const QString& moduleName) const +{ + QString result = moduleName.isEmpty() ? packageName() : moduleName; + result.replace(QLatin1Char('.'), QLatin1Char('_')); + return result.toLower() + QLatin1String("_python.h"); +} + +QString ShibokenGenerator::extendedIsConvertibleFunctionName(const TypeEntry* targetType) const +{ + QString p = targetType->targetLangPackage(); + p.replace(QLatin1Char('.'), QLatin1Char('_')); + return QStringLiteral("ExtendedIsConvertible_%1_%2").arg(p, targetType->name()); +} + +QString ShibokenGenerator::extendedToCppFunctionName(const TypeEntry* targetType) const +{ + QString p = targetType->targetLangPackage(); + p.replace(QLatin1Char('.'), QLatin1Char('_')); + return QStringLiteral("ExtendedToCpp_%1_%2").arg(p, targetType->name()); +} + +bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass) + +{ + if (metaClass->isNamespace() || isObjectType(metaClass)) + return false; + else if (metaClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown) + return metaClass->hasCloneOperator(); + else + return (metaClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet); + + return false; +} + +AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typeSignature) +{ + typeSignature = typeSignature.trimmed(); + 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; + QStringList instantiatedTypes; + int lpos = typeString.indexOf(QLatin1Char('<')); + if (lpos > -1) { + 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); + } + } + + TypeEntry* typeEntry = TypeDatabase::instance()->findType(adjustedTypeName); + + AbstractMetaType* metaType = 0; + if (typeEntry) { + metaType = new AbstractMetaType(); + metaType->setTypeEntry(typeEntry); + metaType->setIndirections(indirections); + metaType->setReferenceType(refType); + metaType->setConstant(isConst); + metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern); + for (const QString &instantiation : qAsConst(instantiatedTypes)) { + AbstractMetaType* tmplArgType = buildAbstractMetaTypeFromString(instantiation); + metaType->addInstantiation(tmplArgType); + } + metaType->decideUsagePattern(); + m_metaTypeFromStringCache.insert(typeSignature, metaType); + } + return metaType; +} + +AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry) +{ + QString typeName = typeEntry->qualifiedCppName(); + if (typeName.startsWith(QLatin1String("::"))) + typeName.remove(0, 2); + if (m_metaTypeFromStringCache.contains(typeName)) + return m_metaTypeFromStringCache.value(typeName); + AbstractMetaType* metaType = new AbstractMetaType; + metaType->setTypeEntry(typeEntry); + metaType->setIndirections(0); + metaType->setReferenceType(NoReference); + metaType->setConstant(false); + metaType->decideUsagePattern(); + m_metaTypeFromStringCache.insert(typeName, metaType); + return metaType; +} +AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass* metaClass) +{ + return ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(metaClass->typeEntry()); +} + +/* +static void dumpFunction(AbstractMetaFunctionList lst) +{ + qDebug() << "DUMP FUNCTIONS: "; + for (AbstractMetaFunction *func : qAsConst(lst)) + qDebug() << "*" << func->ownerClass()->name() + << func->signature() + << "Private: " << func->isPrivate() + << "Empty: " << func->isEmptyFunction() + << "Static:" << func->isStatic() + << "Signal:" << func->isSignal() + << "ClassImplements: " << (func->ownerClass() != func->implementingClass()) + << "is operator:" << func->isOperatorOverload() + << "is global:" << func->isInGlobalScope(); +} +*/ + +static bool isGroupable(const AbstractMetaFunction* func) +{ + if (func->isSignal() || func->isDestructor() || (func->isModifiedRemoved() && !func->isAbstract())) + return false; + // weird operator overloads + if (func->name() == QLatin1String("operator[]") || func->name() == QLatin1String("operator->")) // FIXME: what about cast operators? + return false;; + return true; +} + +QMap< QString, AbstractMetaFunctionList > ShibokenGenerator::getFunctionGroups(const AbstractMetaClass* scope) +{ + AbstractMetaFunctionList lst = scope ? scope->functions() : globalFunctions(); + + QMap results; + for (AbstractMetaFunction *func : qAsConst(lst)) { + if (isGroupable(func)) + results[func->name()].append(func); + } + return results; +} + +AbstractMetaFunctionList ShibokenGenerator::getInheritedOverloads(const AbstractMetaFunction *func, QSet *seen) +{ + AbstractMetaFunctionList results; + AbstractMetaClass* basis; + if (func->ownerClass() && (basis = func->ownerClass()->baseClass(), basis)) { + for (; basis; basis = basis->baseClass()) { + const AbstractMetaFunction* inFunc = basis->findFunction(func->name()); + if (inFunc && !seen->contains(inFunc->minimalSignature())) { + seen->insert(inFunc->minimalSignature()); + AbstractMetaFunction* newFunc = inFunc->copy(); + newFunc->setImplementingClass(func->implementingClass()); + results << newFunc; + } + } + } + return results; +} + +AbstractMetaFunctionList ShibokenGenerator::getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet *seen) +{ + AbstractMetaFunctionList results; + seen->insert(func->minimalSignature()); + results << const_cast(func) << getInheritedOverloads(func, seen); + return results; +} + +AbstractMetaFunctionList ShibokenGenerator::getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName) +{ + AbstractMetaFunctionList lst = scope ? scope->functions() : globalFunctions(); + + AbstractMetaFunctionList results; + QSet seenSignatures; + for (AbstractMetaFunction *func : qAsConst(lst)) { + if (func->name() != functionName) + continue; + if (isGroupable(func)) { + // PYSIDE-331: look also into base classes. + results << getFunctionAndInheritedOverloads(func, &seenSignatures); + } + } + return results; +} + +QPair< int, int > ShibokenGenerator::getMinMaxArguments(const AbstractMetaFunction* metaFunction) +{ + AbstractMetaFunctionList overloads = getFunctionOverloads(metaFunction->ownerClass(), metaFunction->name()); + + int minArgs = std::numeric_limits::max(); + int maxArgs = 0; + for (const AbstractMetaFunction* func : qAsConst(overloads)) { + int numArgs = 0; + const AbstractMetaArgumentList &arguments = func->arguments(); + for (const AbstractMetaArgument *arg : arguments) { + if (!func->argumentRemoved(arg->argumentIndex() + 1)) + numArgs++; + } + maxArgs = std::max(maxArgs, numArgs); + minArgs = std::min(minArgs, numArgs); + } + return qMakePair(minArgs, maxArgs); +} + +QMap ShibokenGenerator::options() const +{ + QMap opts(Generator::options()); + opts.insert(QLatin1String(AVOID_PROTECTED_HACK), + QLatin1String("Avoid the use of the '#define protected public' hack.")); + opts.insert(QLatin1String(PARENT_CTOR_HEURISTIC), + QLatin1String("Enable heuristics to detect parent relationship on constructors.")); + opts.insert(QLatin1String(RETURN_VALUE_HEURISTIC), + QLatin1String("Enable heuristics to detect parent relationship on return values (USE WITH CAUTION!)")); + opts.insert(QLatin1String(ENABLE_PYSIDE_EXTENSIONS), + QLatin1String("Enable PySide extensions, such as support for signal/slots, use this if you are creating a binding for a Qt-based library.")); + opts.insert(QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES), + QLatin1String("Disable verbose error messages. Turn the python code hard to debug but safe few kB on the generated bindings.")); + opts.insert(QLatin1String(USE_ISNULL_AS_NB_NONZERO), + QLatin1String("If a class have an isNull()const method, it will be used to compute the value of boolean casts")); + return opts; +} + +static void getCode(QStringList& code, const CodeSnipList& codeSnips) +{ + for (const CodeSnip &snip : qAsConst(codeSnips)) + code.append(snip.code()); +} + +static void getCode(QStringList& code, const TypeEntry* type) +{ + getCode(code, type->codeSnips()); + + CustomConversion* customConversion = type->customConversion(); + if (!customConversion) + return; + + if (!customConversion->nativeToTargetConversion().isEmpty()) + code.append(customConversion->nativeToTargetConversion()); + + const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions(); + if (toCppConversions.isEmpty()) + return; + + for (CustomConversion::TargetToNativeConversion *toNative : qAsConst(toCppConversions)) + code.append(toNative->conversion()); +} + +bool ShibokenGenerator::doSetup(const QMap& args) +{ + 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(); + for (const PrimitiveTypeEntry *type : primitiveTypeList) + getCode(snips, type); + const ContainerTypeEntryList &containerTypeList = containerTypes(); + for (const ContainerTypeEntry *type : containerTypeList) + getCode(snips, type); + const AbstractMetaClassList &classList = classes(); + for (const AbstractMetaClass *metaClass : classList) + getCode(snips, metaClass->typeEntry()); + getCode(snips, td->findType(packageName())); + const FunctionGroupMap &functionGroups = getFunctionGroups(); + for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) { + for (AbstractMetaFunction *func : it.value()) + getCode(snips, func->injectedCodeSnips()); + } + + for (const QString &code : qAsConst(snips)) { + collectContainerTypesFromConverterMacros(code, true); + collectContainerTypesFromConverterMacros(code, false); + } + + return true; +} + +void ShibokenGenerator::collectContainerTypesFromConverterMacros(const QString& code, bool toPythonMacro) +{ + QString convMacro = toPythonMacro ? QLatin1String("%CONVERTTOPYTHON[") : QLatin1String("%CONVERTTOCPP["); + int offset = toPythonMacro ? sizeof("%CONVERTTOPYTHON") : sizeof("%CONVERTTOCPP"); + int start = 0; + while ((start = code.indexOf(convMacro, start)) != -1) { + int end = code.indexOf(QLatin1Char(']'), start); + start += offset; + if (code.at(start) != QLatin1Char('%')) { + QString typeString = code.mid(start, end - start); + AbstractMetaType* type = buildAbstractMetaTypeFromString(typeString); + addInstantiatedContainersAndSmartPointers(type, type->originalTypeDescription()); + } + start = end; + } +} + +bool ShibokenGenerator::useCtorHeuristic() const +{ + return m_useCtorHeuristic; +} + +bool ShibokenGenerator::useReturnValueHeuristic() const +{ + return m_userReturnValueHeuristic; +} + +bool ShibokenGenerator::usePySideExtensions() const +{ + return m_usePySideExtensions; +} + +bool ShibokenGenerator::useIsNullAsNbNonZero() const +{ + return m_useIsNullAsNbNonZero; +} + +bool ShibokenGenerator::avoidProtectedHack() const +{ + return m_avoidProtectedHack; +} + +QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const +{ + QString result = moduleName.isEmpty() ? ShibokenGenerator::packageName() : moduleName; + result.replace(QLatin1Char('.'), QLatin1Char('_')); + result.prepend(QLatin1String("Sbk")); + result.append(QLatin1String("Types")); + return result; +} + +QString ShibokenGenerator::convertersVariableName(const QString& moduleName) const +{ + QString result = cppApiVariableName(moduleName); + result.chop(1); + result.append(QLatin1String("Converters")); + return result; +} + +static QString processInstantiationsVariableName(const AbstractMetaType* type) +{ + QString res = QLatin1Char('_') + _fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper(); + const AbstractMetaTypeList &instantiations = type->instantiations(); + for (const AbstractMetaType *instantiation : instantiations) { + res += instantiation->isContainer() + ? processInstantiationsVariableName(instantiation) + : QLatin1Char('_') + _fixedCppTypeName(instantiation->cppSignature()).toUpper(); + } + return res; +} +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; + const AbstractMetaTypeList &templateBaseClassInstantiations = metaClass->templateBaseClassInstantiations(); + for (const AbstractMetaType *instantiation : templateBaseClassInstantiations) + instantiations += processInstantiationsVariableName(instantiation); + return QString::fromLatin1("SBK_%1%2_IDX").arg(base, instantiations); + } + return getTypeIndexVariableName(metaClass->typeEntry()); +} +QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type) +{ + if (type->isCppPrimitive()) { + const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; + if (trueType->basicReferencedTypeEntry()) + type = trueType->basicReferencedTypeEntry(); + } + return QString::fromLatin1("SBK_%1_IDX").arg(_fixedCppTypeName(type->qualifiedCppName()).toUpper()); +} +QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type) +{ + return QString::fromLatin1("SBK%1%2_IDX") + .arg(type->typeEntry()->isContainer() ? QLatin1Char('_') + moduleName().toUpper() : QString(), + processInstantiationsVariableName(type)); +} + +bool ShibokenGenerator::verboseErrorMessagesDisabled() const +{ + return m_verboseErrorMessagesDisabled; +} + +bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const OverloadData& overloadData) +{ + if (overloadData.referenceFunction()->isCallOperator()) + return true; + if (overloadData.referenceFunction()->isOperatorOverload()) + return false; + int maxArgs = overloadData.maxArgs(); + int minArgs = overloadData.minArgs(); + return (minArgs != maxArgs) + || (maxArgs > 1) + || overloadData.referenceFunction()->isConstructor() + || overloadData.hasArgumentWithDefaultValue(); +} + +Generator::Options ShibokenGenerator::getConverterOptions(const AbstractMetaType* metaType) +{ + // exclude const on Objects + Options flags; + const TypeEntry* type = metaType->typeEntry(); + bool isCStr = isCString(metaType); + if (metaType->indirections() && !isCStr) { + flags = ExcludeConst; + } else if (metaType->isContainer() + || (type->isPrimitive() && !isCStr) + // const refs become just the value, but pure refs must remain pure. + || (type->isValue() && metaType->isConstant() && metaType->referenceType() == LValueReference)) { + flags = ExcludeConst | ExcludeReference; + } + return flags; +} + +QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg) +{ + if (!arg->defaultValueExpression().isEmpty()) + return arg->defaultValueExpression(); + + //Check modifications + const FunctionModificationList &mods = func->modifications(); + for (const FunctionModification &m : mods) { + for (const ArgumentModification &am : m.argument_mods) { + if (am.index == (arg->argumentIndex() + 1)) + return am.replacedDefaultExpression; + } + } + return QString(); +} + +void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor) +{ + if (defaultCtor.isEmpty() && isCppPrimitive(type)) + return; + QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor; + if (ctor.isEmpty()) { + 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)) + return; + QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor; + + if (ctor.isEmpty()) { + const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->qualifiedCppName()); + qCWarning(lcShiboken()).noquote() << message; + s << ";\n#error " << message << endl; + } else { + s << " = " << ctor; + } +} + +bool ShibokenGenerator::isCppIntegralPrimitive(const TypeEntry* type) +{ + if (!type->isCppPrimitive()) + return false; + const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; + if (trueType->basicReferencedTypeEntry()) + trueType = trueType->basicReferencedTypeEntry(); + QString typeName = trueType->qualifiedCppName(); + return !typeName.contains(QLatin1String("double")) + && !typeName.contains(QLatin1String("float")) + && !typeName.contains(QLatin1String("wchar")); +} +bool ShibokenGenerator::isCppIntegralPrimitive(const AbstractMetaType* type) +{ + return isCppIntegralPrimitive(type->typeEntry()); +} + +QString ShibokenGenerator::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."); +} diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h new file mode 100644 index 000000000..1be56edc8 --- /dev/null +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h @@ -0,0 +1,556 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 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\\[([^\\[]*)\\]\\(" + +#include + +#include "typesystem.h" + +#include + +class DocParser; +class CodeSnip; +class OverloadData; + +QT_FORWARD_DECLARE_CLASS(QTextStream) + +/** + * Abstract generator that contains common methods used in CppGenerator and HeaderGenerator. + */ +class ShibokenGenerator : public Generator +{ +public: + ShibokenGenerator(); + virtual ~ShibokenGenerator(); + + QString translateTypeForWrapperMethod(const AbstractMetaType* cType, + const AbstractMetaClass* context, Options opt = NoOption) const; + + /** + * 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 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 *seen); + + /** + * 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 *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); + /** + * Returns the minimun and maximun number of arguments which this function and all overloads + * can accept. Arguments removed by typesystem are considered as well. + */ + QPair getMinMaxArguments(const AbstractMetaFunction* metaFunction); + /** + * 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; + + void writeArgumentNames(QTextStream &s, + const AbstractMetaFunction* func, + Options options = NoOption) const override; + + /** + * Function used to write the fucntion arguments on the class buffer. + * \param s the class output buffer + * \param func the pointer to metafunction information + * \param count the number of function arguments + * \param options some extra options used during the parser + */ + 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 ArgumentVarReplacementPair; + typedef QVector ArgumentVarReplacementList; + ArgumentVarReplacementList getArgumentReplacement(const AbstractMetaFunction* func, + bool usePyArgs, TypeSystem::Language language, + const AbstractMetaArgument* lastArg); + + /// Write user's custom code snippets at class or module level. + void writeCodeSnips(QTextStream& s, + const QVector & codeSnips, + TypeSystem::CodeSnipPosition position, + TypeSystem::Language language, + const AbstractMetaClass* context = 0); + /// Write user's custom code snippets at function level. + void writeCodeSnips(QTextStream& s, + const QVector & codeSnips, + TypeSystem::CodeSnipPosition position, + TypeSystem::Language language, + 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 & 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 "target" + * type needs the type system variable "%CPPSELF". + * \param func the function to check + * \return true if the function's target code snippets use "%CPPSELF" + */ + bool injectedCodeUsesCppSelf(const AbstractMetaFunction* func); + + /** + * Verifies if any of the function's code injections of the "native" + * type needs the type system variable "%PYSELF". + * \param func the function to check + * \return true if the function's native code snippets use "%PYSELF" + */ + bool injectedCodeUsesPySelf(const AbstractMetaFunction* func); + + /** + * Verifies if any of the function's code injections makes a call + * to the C++ method. This is used by the generator to avoid writing calls + * to C++ when the user custom code already does this. + * \param func the function to check + * \return true if the function's code snippets call the wrapped C++ function + */ + bool injectedCodeCallsCppFunction(const AbstractMetaFunction* func); + + /** + * Verifies if any of the function's code injections of the "native" class makes a + * call to the C++ method. This is used by the generator to avoid writing calls to + * Python overrides of C++ virtual methods when the user custom code already does this. + * \param func the function to check + * \return true if the function's code snippets call the Python override for a C++ virtual method + */ + bool injectedCodeCallsPythonOverride(const AbstractMetaFunction* func); + + /** + * Verifies if any of the function's code injections attributes values to + * the return variable (%0 or %PYARG_0). + * \param func the function to check + * \param language the kind of code snip + * \return true if the function's code attributes values to "%0" or "%PYARG_0" + */ + bool injectedCodeHasReturnValueAttribution(const AbstractMetaFunction* func, TypeSystem::Language language = TypeSystem::TargetLangCode); + + /** + * Verifies if any of the function's code injections uses the type system variable + * for function arguments of a given index. + */ + bool injectedCodeUsesArgument(const AbstractMetaFunction* func, int argumentIndex); + + /** + * Function which parse the metafunction information + * \param func the function witch will be parserd + * \param option some extra options + * \param arg_count the number of function arguments + */ + QString functionSignature(const AbstractMetaFunction* func, + QString prepend = QString(), + QString append = QString(), + Options options = NoOption, + int arg_count = -1) const; + + /// Returns true if there are cases of multiple inheritance in any of its ancestors. + bool hasMultipleInheritanceInAncestry(const AbstractMetaClass* metaClass); + + /// Returns true if the class needs to have a getattro function. + bool classNeedsGetattroFunction(const AbstractMetaClass* metaClass); + + /// Returns true if the class needs to have a setattro function. + bool classNeedsSetattroFunction(const AbstractMetaClass *metaClass); + + /// Returns a list of methods of the given class where each one is part of a different overload with both static and non-static method. + AbstractMetaFunctionList getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass); + + /// 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, + const AbstractMetaClass* context, const QString& argumentName); + void writeToCppConversion(QTextStream& s, const AbstractMetaType* type, const AbstractMetaClass* context, const QString& inArgName, const QString& outArgName); + void writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass, const QString& inArgName, const QString& outArgName); + + /// Returns true if the argument is a pointer that rejects NULL values. + bool shouldRejectNullPointerArgument(const AbstractMetaFunction* func, int argIndex); + + /// Verifies if the class should have a C++ wrapper generated for it, instead of only a Python wrapper. + bool shouldGenerateCppWrapper(const AbstractMetaClass* metaClass) const; + + /// Adds enums eligible for generation from classes/namespaces marked not to be generated. + static void lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList& enumList, const AbstractMetaClass* metaClass); + /// Returns the enclosing class for an enum, or NULL if it should be global. + const AbstractMetaClass* getProperEnclosingClassForEnum(const AbstractMetaEnum* metaEnum); + + QString wrapperName(const AbstractMetaClass* metaClass) const; + QString wrapperName(const AbstractMetaType *metaType) const; + + static QString fullPythonFunctionName(const AbstractMetaFunction* func); + static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum); + static QString protectedFieldGetterName(const AbstractMetaField* field); + static QString protectedFieldSetterName(const AbstractMetaField* field); + + static QString pythonPrimitiveTypeName(const QString& cppTypeName); + static QString pythonPrimitiveTypeName(const PrimitiveTypeEntry* type); + + static QString pythonOperatorFunctionName(QString cppOpFuncName); + static QString pythonOperatorFunctionName(const AbstractMetaFunction* func); + static QString pythonRichCompareOperatorId(QString cppOpFuncName); + static QString pythonRichCompareOperatorId(const AbstractMetaFunction* func); + + static QString cpythonOperatorFunctionName(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 TypeEntry* type); + static bool isNumber(const AbstractMetaType* type); + static bool isPyInt(const TypeEntry* type); + static bool isPyInt(const AbstractMetaType* type); + static bool isPairContainer(const AbstractMetaType* type); + + /** + * Returns true if the type passed has a Python wrapper for it. + * Although namespace has a Python wrapper, it's not considered a type. + */ + static bool isWrapperType(const TypeEntry* type); + static bool isWrapperType(const ComplexTypeEntry* type); + static bool isWrapperType(const AbstractMetaType* metaType); + + /** + * Checks if the type is an Object/QObject or pointer to Value Type. + * In other words, tells if the type is "T*" and T has a Python wrapper. + */ + static bool isPointerToWrapperType(const AbstractMetaType* type); + + /** + * Returns true if \p type is an Object Type used as a value. + */ + static bool isObjectTypeUsedAsValueType(const AbstractMetaType* type); + + static bool isValueTypeWithCopyConstructorOnly(const AbstractMetaClass* metaClass); + bool isValueTypeWithCopyConstructorOnly(const TypeEntry* type) const; + bool isValueTypeWithCopyConstructorOnly(const AbstractMetaType* type) const; + + /// Returns true if the type is a primitive but not a C++ primitive. + static bool isUserPrimitive(const TypeEntry* type); + static bool isUserPrimitive(const AbstractMetaType* type); + + /// Returns true if the type is a C++ primitive, a void*, a const char*, or a std::string. + static bool isCppPrimitive(const TypeEntry* type); + static bool isCppPrimitive(const AbstractMetaType* type); + + /// Returns true if the type is a C++ integral primitive, i.e. bool, char, int, long, and their unsigned counterparts. + static bool isCppIntegralPrimitive(const TypeEntry* type); + static bool isCppIntegralPrimitive(const AbstractMetaType* type); + + /// Checks if an argument type should be dereferenced by the Python method wrapper before calling the C++ method. + static bool shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg); + /// Checks if a meta type should be dereferenced by the Python method wrapper passing it to C++. + static bool shouldDereferenceAbstractMetaTypePointer(const AbstractMetaType* metaType); + + static bool visibilityModifiedToPrivate(const AbstractMetaFunction* func); + + QString converterObject(const AbstractMetaType* type); + QString converterObject(const TypeEntry* type); + + QString cpythonBaseName(const AbstractMetaClass* metaClass); + QString cpythonBaseName(const TypeEntry* type); + QString cpythonBaseName(const AbstractMetaType* type); + QString cpythonTypeName(const AbstractMetaClass* metaClass); + QString cpythonTypeName(const TypeEntry* type); + QString cpythonTypeNameExt(const TypeEntry* type); + QString cpythonTypeNameExt(const AbstractMetaType* type); + QString cpythonCheckFunction(const TypeEntry* type, bool genericNumberType = false); + QString cpythonCheckFunction(const AbstractMetaType* metaType, bool genericNumberType = false); + /** + * Receives the argument \p type and tries to find the appropriate AbstractMetaType for it + * or a custom type check. + * \param type A string representing the type to be discovered. + * \param metaType A pointer to an AbstractMetaType pointer, to where write a new meta type object + * if one is produced from the \p type string. This object must be deallocated by + * the caller. It will set the target variable to NULL, is \p type is a Python type. + * \return A custom check if \p type is a custom type, or an empty string if \p metaType + * receives an existing type object. + */ + QString guessCPythonCheckFunction(const QString& type, AbstractMetaType** metaType); + QString cpythonIsConvertibleFunction(const TypeEntry* type, bool genericNumberType = false, bool checkExact = false); + QString cpythonIsConvertibleFunction(const AbstractMetaType* metaType, bool genericNumberType = false); + QString cpythonIsConvertibleFunction(const AbstractMetaArgument* metaArg, bool genericNumberType = false); + QString guessCPythonIsConvertible(const QString& type); + + QString cpythonToCppConversionFunction(const AbstractMetaClass* metaClass); + QString cpythonToCppConversionFunction(const AbstractMetaType* type, const AbstractMetaClass* context = 0); + QString cpythonToPythonConversionFunction(const AbstractMetaType* type, const AbstractMetaClass* context = 0); + QString cpythonToPythonConversionFunction(const AbstractMetaClass* metaClass); + QString cpythonToPythonConversionFunction(const TypeEntry* type); + + QString cpythonFunctionName(const AbstractMetaFunction* func); + QString cpythonMethodDefinitionName(const AbstractMetaFunction* func); + QString cpythonGettersSettersDefinitionName(const AbstractMetaClass* metaClass); + QString cpythonGetattroFunctionName(const AbstractMetaClass* metaClass); + 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); + + /// Guesses the scope to where belongs an argument's default value. + QString guessScopeForDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg); + + QString cpythonEnumName(const EnumTypeEntry* enumEntry); + QString cpythonEnumName(const AbstractMetaEnum* metaEnum); + + QString cpythonFlagsName(const FlagsTypeEntry* flagsEntry); + QString cpythonFlagsName(const AbstractMetaEnum* metaEnum); + /// Returns the special cast function name, the function used to proper cast class with multiple inheritance. + QString cpythonSpecialCastFunctionName(const AbstractMetaClass* metaClass); + + QString getFunctionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const; + QString getFormatUnitString(const AbstractMetaFunction* func, bool incRef = false) const; + + /// Returns the file name for the module global header. If no module name is provided the current will be used. + QString getModuleHeaderFileName(const QString& moduleName = QString()) const; + + QString extendedIsConvertibleFunctionName(const TypeEntry* targetType) const; + QString extendedToCppFunctionName(const TypeEntry* targetType) const; + + QMap< QString, QString > options() const override; + + /// Returns true if the user enabled the so called "parent constructor heuristic". + bool useCtorHeuristic() const; + /// Returns true if the user enabled the so called "return value heuristic". + bool useReturnValueHeuristic() const; + /// Returns true if the user enabled PySide extensions. + bool usePySideExtensions() const; + /// Returns true if the generator should use the result of isNull()const to compute boolean casts. + bool useIsNullAsNbNonZero() const; + /// Returns true if the generated code should use the "#define protected public" hack. + bool avoidProtectedHack() const; + QString cppApiVariableName(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 + * and the class is a typedef for a template class instantiation, it will return an alternative name + * made of the template class and the instantiation values, or an empty string if the class isn't + * derived from a template class at all. + */ + QString getTypeIndexVariableName(const AbstractMetaClass* metaClass, bool alternativeTemplateName = false); + QString getTypeIndexVariableName(const TypeEntry* type); + QString getTypeIndexVariableName(const AbstractMetaType* type); + + /// Returns true if the user don't want verbose error messages on the generated bindings. + bool verboseErrorMessagesDisabled() const; + + /** + * Builds an AbstractMetaType object from a QString. + * Returns NULL if no type could be built from the string. + * \param typeSignature The string describing the type to be built. + * \return A new AbstractMetaType object that must be deleted by the caller, or a NULL pointer in case of failure. + */ + AbstractMetaType* buildAbstractMetaTypeFromString(QString typeSignature); + + /// Creates an AbstractMetaType object from a TypeEntry. + AbstractMetaType* buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry); + /// Creates an AbstractMetaType object from an AbstractMetaClass. + AbstractMetaType* buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass* metaClass); + + 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 return the flags to be used by a meta type when + * it needs to write some converter code. + */ + static Options getConverterOptions(const AbstractMetaType* metaType); + + /** + * Helper function to find for argument default value + */ + static QString getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg); +protected: + bool doSetup(const QMap& 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 m_pythonPrimitiveTypeName; + static QHash m_pythonOperators; + static QHash m_formatUnits; + static QHash m_tpFuncs; + static QStringList m_knownPythonTypes; + + void clearTpFuncs(); + + const char* name() const { return "Shiboken"; } + + /// Initializes correspondences between primitive and Python types. + static void initPrimitiveTypesCorrespondences(); + /// Initializes a list of Python known type names. + static void initKnownPythonTypes(); + + void writeFunctionCall(QTextStream& s, + const AbstractMetaFunction* metaFunc, + Options options = NoOption) const; + + void writeUnusedVariableCast(QTextStream& s, const QString& variableName); + + AbstractMetaFunctionList filterFunctions(const AbstractMetaClass* metaClass); + + // All data about extended converters: the type entries of the target type, and a + // list of AbstractMetaClasses accepted as argument for the conversion. + typedef QHash > ExtendedConverterData; + /// Returns all extended conversions for the current module. + ExtendedConverterData getExtendedConverters() const; + + /// Returns a list of converters for the non wrapper types of the current module. + QVector getPrimitiveCustomConversions(); + + /// Returns true if the Python wrapper for the received OverloadData must accept a list of arguments. + static bool pythonFunctionWrapperUsesListOfArguments(const OverloadData& overloadData); + + Indentor INDENT; + + enum TypeSystemConverterVariable { + TypeSystemCheckFunction = 0, + TypeSystemIsConvertibleFunction, + TypeSystemToCppFunction, + TypeSystemToPythonFunction, + TypeSystemConverterVariables + }; + void replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code); + + static QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type); + +private: + bool m_useCtorHeuristic; + bool m_userReturnValueHeuristic; + bool m_usePySideExtensions; + bool m_verboseErrorMessagesDisabled; + bool m_useIsNullAsNbNonZero; + bool m_avoidProtectedHack; + + typedef QHash AbstractMetaTypeCache; + AbstractMetaTypeCache m_metaTypeFromStringCache; + + /// Type system converter variable replacement names and regular expressions. + QString m_typeSystemConvName[TypeSystemConverterVariables]; + QRegularExpression m_typeSystemConvRegEx[TypeSystemConverterVariables]; +}; + +#endif // SHIBOKENGENERATOR_H diff --git a/sources/shiboken2/generator/shibokenconfig.h.in b/sources/shiboken2/generator/shibokenconfig.h.in new file mode 100644 index 000000000..2c86a4a3c --- /dev/null +++ b/sources/shiboken2/generator/shibokenconfig.h.in @@ -0,0 +1,6 @@ +#ifndef SHIBOKENCONFIG_H +#define SHIBOKENCONFIG_H + +#define SHIBOKEN_VERSION "@shiboken2_VERSION@" + +#endif diff --git a/sources/shiboken2/generatorrunnerconfig.h.in b/sources/shiboken2/generatorrunnerconfig.h.in new file mode 100644 index 000000000..d291fcc53 --- /dev/null +++ b/sources/shiboken2/generatorrunnerconfig.h.in @@ -0,0 +1,13 @@ +#ifndef GENERATORRUNNERCONFIG_H +#define GENERATORRUNNERCONFIG_H + +// generatorrunner version +#define GENERATORRUNNER_VERSION "@generator_VERSION@" + +// generatorrunner plugin dir +#define GENERATORRUNNER_PLUGIN_DIR "@generator_plugin_DIR@" + +// module extension +#define MODULE_EXTENSION "@CMAKE_SHARED_LIBRARY_SUFFIX@" + +#endif diff --git a/sources/shiboken2/generatorrunnermacros.h b/sources/shiboken2/generatorrunnermacros.h new file mode 100644 index 000000000..d54ed3b9a --- /dev/null +++ b/sources/shiboken2/generatorrunnermacros.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 GENERATORRUNNERMACROS_H +#define GENERATORRUNNERMACROS_H + +// GENRUNNER_API is used for the public API symbols. +#if defined _WIN32 + #define GENRUNNER_EXPORT __declspec(dllexport) + #if GENRUNNER_EXPORTS + #define GENRUNNER_API GENRUNNER_EXPORT + #endif +#elif __GNUC__ >= 4 + #define GENRUNNER_EXPORT __attribute__ ((visibility("default"))) + #define GENRUNNER_API GENRUNNER_EXPORT +#elif __GNUC__ < 4 + #define GENRUNNER_EXPORT +#endif + +#ifndef GENRUNNER_API + #define GENRUNNER_API +#endif +#endif diff --git a/sources/shiboken2/generators/shiboken/shiboken.cpp b/sources/shiboken2/generators/shiboken/shiboken.cpp new file mode 100644 index 000000000..829862f19 --- /dev/null +++ b/sources/shiboken2/generators/shiboken/shiboken.cpp @@ -0,0 +1,32 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "cppgenerator.h" +#include "headergenerator.h" + +EXPORT_GENERATOR_PLUGIN(new CppGenerator << new HeaderGenerator) diff --git a/sources/shiboken2/header.COMM b/sources/shiboken2/header.COMM new file mode 100644 index 000000000..1c8cb00e7 --- /dev/null +++ b/sources/shiboken2/header.COMM @@ -0,0 +1,20 @@ +/****************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the module. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ diff --git a/sources/shiboken2/header.LGPL-ONLY b/sources/shiboken2/header.LGPL-ONLY new file mode 100644 index 000000000..9a676032e --- /dev/null +++ b/sources/shiboken2/header.LGPL-ONLY @@ -0,0 +1,22 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you have questions regarding the use of this file, please contact +** us via http://www.qt.io/contact-us/. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ diff --git a/sources/shiboken2/header.LGPL21 b/sources/shiboken2/header.LGPL21 new file mode 100644 index 000000000..533390b07 --- /dev/null +++ b/sources/shiboken2/header.LGPL21 @@ -0,0 +1,33 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + diff --git a/sources/shiboken2/header.LGPL3 b/sources/shiboken2/header.LGPL3 new file mode 100644 index 000000000..d9a65c2e4 --- /dev/null +++ b/sources/shiboken2/header.LGPL3 @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + diff --git a/sources/shiboken2/header.LGPL3-COMM b/sources/shiboken2/header.LGPL3-COMM new file mode 100644 index 000000000..b5dc15d38 --- /dev/null +++ b/sources/shiboken2/header.LGPL3-COMM @@ -0,0 +1,28 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3-COMM$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + diff --git a/sources/shiboken2/icecc.cmake b/sources/shiboken2/icecc.cmake new file mode 100644 index 000000000..b2bf071aa --- /dev/null +++ b/sources/shiboken2/icecc.cmake @@ -0,0 +1,11 @@ +include (CMakeForceCompiler) +option(ENABLE_ICECC "Enable icecc checking, for distributed compilation") +if (ENABLE_ICECC) + find_program(ICECC icecc) + if (ICECC) + message(STATUS "icecc found! Distributed compilation for all!! huhuhu.") + cmake_force_cxx_compiler(${ICECC} icecc) + else(ICECC) + message(FATAL_ERROR "icecc NOT found! re-run cmake without -DENABLE_ICECC") + endif(ICECC) +endif(ENABLE_ICECC) diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt new file mode 100644 index 000000000..e2e5eb427 --- /dev/null +++ b/sources/shiboken2/libshiboken/CMakeLists.txt @@ -0,0 +1,69 @@ +project(libshiboken) + +option(ENABLE_VERSION_SUFFIX "Used to use current version in suffix to generated files. This is used to allow multiples versions installed simultaneous." FALSE) +if(ENABLE_VERSION_SUFFIX) + set(shiboken2_SUFFIX "-${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}") +else() + set(shiboken2_SUFFIX "") +endif() + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sbkversion.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h" @ONLY) + +set(libshiboken_MAJOR_VERSION ${shiboken_MAJOR_VERSION}) +set(libshiboken_MINOR_VERSION ${shiboken_MINOR_VERSION}) +set(libshiboken_MICRO_VERSION ${shiboken_MICRO_VERSION}) +set(libshiboken_VERSION "${libshiboken_MAJOR_VERSION}.${libshiboken_MINOR_VERSION}.${libshiboken_MICRO_VERSION}") +set(libshiboken_SOVERSION "${libshiboken_MAJOR_VERSION}.${libshiboken_MINOR_VERSION}") + +set(libshiboken_SRC +basewrapper.cpp +debugfreehook.cpp +gilstate.cpp +helper.cpp +sbkconverter.cpp +sbkenum.cpp +sbkmodule.cpp +sbkstring.cpp +bindingmanager.cpp +threadstatesaver.cpp +typeresolver.cpp +shibokenbuffer.cpp +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${SBK_PYTHON_INCLUDE_DIR}) +add_library(libshiboken SHARED ${libshiboken_SRC}) +target_link_libraries(libshiboken ${SBK_PYTHON_LIBRARIES}) +set_target_properties(libshiboken PROPERTIES OUTPUT_NAME "shiboken2${shiboken2_SUFFIX}${PYTHON_EXTENSION_SUFFIX}" + VERSION ${libshiboken_VERSION} + SOVERSION ${libshiboken_SOVERSION} + CXX_STANDARD 11 + DEFINE_SYMBOL LIBSHIBOKEN_EXPORTS) + +install(FILES + autodecref.h + basewrapper.h + bindingmanager.h + conversions.h + gilstate.h + helper.h + sbkconverter.h + sbkenum.h + sbkmodule.h + python25compat.h + sbkdbg.h + sbkstring.h + shiboken.h + shibokenmacros.h + threadstatesaver.h + typeresolver.h + shibokenbuffer.h + sbkpython.h + "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h" + DESTINATION include/shiboken2${shiboken2_SUFFIX}) +install(TARGETS libshiboken EXPORT shiboken2 + LIBRARY DESTINATION "${LIB_INSTALL_DIR}" + ARCHIVE DESTINATION "${LIB_INSTALL_DIR}" + RUNTIME DESTINATION bin) diff --git a/sources/shiboken2/libshiboken/autodecref.h b/sources/shiboken2/libshiboken/autodecref.h new file mode 100644 index 000000000..1fefcc259 --- /dev/null +++ b/sources/shiboken2/libshiboken/autodecref.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef AUTODECREF_H +#define AUTODECREF_H + +#include "sbkpython.h" +#include "basewrapper.h" + +struct SbkObject; +namespace Shiboken +{ + +/** + * AutoDecRef holds a PyObject pointer and decrement its reference counter when destroyed. + */ +struct LIBSHIBOKEN_API AutoDecRef +{ +public: + /** + * AutoDecRef constructor. + * \param pyobj A borrowed reference to a Python object + */ + explicit AutoDecRef(PyObject* pyObj) : m_pyObj(pyObj) {} + /** + * AutoDecRef constructor. + * \param pyobj A borrowed reference to a Python object + */ + explicit AutoDecRef(SbkObject* pyObj) : m_pyObj(reinterpret_cast(pyObj)) {} + + /// Decref the borrowed python reference + ~AutoDecRef() + { + Py_XDECREF(m_pyObj); + } + + inline bool isNull() const { return m_pyObj == 0; } + /// Returns the pointer of the Python object being held. + inline PyObject* object() { return m_pyObj; } + inline operator PyObject*() { return m_pyObj; } + inline operator PyTupleObject*() { return reinterpret_cast(m_pyObj); } + inline operator bool() const { return m_pyObj; } + inline PyObject* operator->() { return m_pyObj; } + + template + T cast() + { + return reinterpret_cast(m_pyObj); + } + + /** + * 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) + { + Py_XDECREF(m_pyObj); + m_pyObj = other; + } +private: + PyObject* m_pyObj; + AutoDecRef(const AutoDecRef&); + AutoDecRef& operator=(const AutoDecRef&); +}; + +} // namespace Shiboken + +#endif // AUTODECREF_H + diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp new file mode 100644 index 000000000..5ecda1eaf --- /dev/null +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -0,0 +1,1516 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "basewrapper.h" +#include "basewrapper_p.h" +#include "sbkconverter.h" +#include "sbkenum.h" +#include "autodecref.h" +#include "typeresolver.h" +#include "gilstate.h" +#include +#include +#include +#include +#include +#include +#include "threadstatesaver.h" + +namespace { + void _destroyParentInfo(SbkObject* obj, bool keepReference); +} + +extern "C" +{ + +static void SbkObjectTypeDealloc(PyObject* pyObj); +static PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); + +PyTypeObject SbkObjectType_Type = { + PyVarObject_HEAD_INIT(0, 0) + /*tp_name*/ "Shiboken.ObjectType", + /*tp_basicsize*/ sizeof(SbkObjectType), + /*tp_itemsize*/ 0, + /*tp_dealloc*/ SbkObjectTypeDealloc, + /*tp_print*/ 0, + /*tp_getattr*/ 0, + /*tp_setattr*/ 0, + /*tp_compare*/ 0, + /*tp_repr*/ 0, + /*tp_as_number*/ 0, + /*tp_as_sequence*/ 0, + /*tp_as_mapping*/ 0, + /*tp_hash*/ 0, + /*tp_call*/ 0, + /*tp_str*/ 0, + /*tp_getattro*/ 0, + /*tp_setattro*/ PyObject_GenericSetAttr, + /*tp_as_buffer*/ 0, + /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + /*tp_doc*/ 0, + /*tp_traverse*/ 0, + /*tp_clear*/ 0, + /*tp_richcompare*/ 0, + /*tp_weaklistoffset*/ 0, + /*tp_iter*/ 0, + /*tp_iternext*/ 0, + /*tp_methods*/ 0, + /*tp_members*/ 0, + /*tp_getset*/ 0, + /*tp_base*/ &PyType_Type, + /*tp_dict*/ 0, + /*tp_descr_get*/ 0, + /*tp_descr_set*/ 0, + /*tp_dictoffset*/ 0, + /*tp_init*/ 0, + /*tp_alloc*/ PyType_GenericAlloc, + /*tp_new*/ SbkObjectTypeTpNew, + /*tp_free*/ PyObject_GC_Del, + /*tp_is_gc*/ 0, + /*tp_bases*/ 0, + /*tp_mro*/ 0, + /*tp_cache*/ 0, + /*tp_subclasses*/ 0, + /*tp_weaklist*/ 0, + /*tp_del*/ 0, + /*tp_version_tag*/ 0 +}; + +static PyObject *SbkObjectGetDict(PyObject* pObj, void *) +{ + SbkObject *obj = reinterpret_cast(pObj); + if (!obj->ob_dict) + obj->ob_dict = PyDict_New(); + if (!obj->ob_dict) + return 0; + Py_INCREF(obj->ob_dict); + return obj->ob_dict; +} + +static PyGetSetDef SbkObjectGetSetList[] = { + {const_cast("__dict__"), SbkObjectGetDict, 0, 0, 0}, + {0, 0, 0, 0, 0} // Sentinel +}; + +static int SbkObject_traverse(PyObject* self, visitproc visit, void* arg) +{ + SbkObject* sbkSelf = reinterpret_cast(self); + + //Visit children + Shiboken::ParentInfo* pInfo = sbkSelf->d->parentInfo; + if (pInfo) { + std::set::const_iterator it = pInfo->children.begin(); + for(; it != pInfo->children.end(); ++it) + Py_VISIT(*it); + } + + //Visit refs + Shiboken::RefCountMap* rInfo = sbkSelf->d->referredObjects; + if (rInfo) { + Shiboken::RefCountMap::const_iterator it = rInfo->begin(); + for (; it != rInfo->end(); ++it) { + std::list::const_iterator ref = it->second.begin(); + for(; ref != it->second.end(); ++ref) + Py_VISIT(*ref); + } + } + + if (sbkSelf->ob_dict) + Py_VISIT(sbkSelf->ob_dict); + return 0; +} + +static int SbkObject_clear(PyObject* self) +{ + SbkObject* sbkSelf = reinterpret_cast(self); + + Shiboken::Object::removeParent(sbkSelf); + + if (sbkSelf->d->parentInfo) + _destroyParentInfo(sbkSelf, true); + + Shiboken::Object::clearReferences(sbkSelf); + + if (sbkSelf->ob_dict) + Py_CLEAR(sbkSelf->ob_dict); + return 0; +} + +SbkObjectType SbkObject_Type = { { { + PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0) + /*tp_name*/ "Shiboken.Object", + /*tp_basicsize*/ sizeof(SbkObject), + /*tp_itemsize*/ 0, + /*tp_dealloc*/ SbkDeallocWrapperWithPrivateDtor, + /*tp_print*/ 0, + /*tp_getattr*/ 0, + /*tp_setattr*/ 0, + /*tp_compare*/ 0, + /*tp_repr*/ 0, + /*tp_as_number*/ 0, + /*tp_as_sequence*/ 0, + /*tp_as_mapping*/ 0, + /*tp_hash*/ 0, + /*tp_call*/ 0, + /*tp_str*/ 0, + /*tp_getattro*/ 0, + /*tp_setattro*/ 0, + /*tp_as_buffer*/ 0, + /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + /*tp_doc*/ 0, + /*tp_traverse*/ SbkObject_traverse, + /*tp_clear*/ SbkObject_clear, + /*tp_richcompare*/ 0, + /*tp_weaklistoffset*/ offsetof(SbkObject, weakreflist), + /*tp_iter*/ 0, + /*tp_iternext*/ 0, + /*tp_methods*/ 0, + /*tp_members*/ 0, + /*tp_getset*/ SbkObjectGetSetList, + /*tp_base*/ 0, + /*tp_dict*/ 0, + /*tp_descr_get*/ 0, + /*tp_descr_set*/ 0, + /*tp_dictoffset*/ offsetof(SbkObject, ob_dict), + /*tp_init*/ 0, + /*tp_alloc*/ 0, + /*tp_new*/ 0, + /*tp_free*/ 0, + /*tp_is_gc*/ 0, + /*tp_bases*/ 0, + /*tp_mro*/ 0, + /*tp_cache*/ 0, + /*tp_subclasses*/ 0, + /*tp_weaklist*/ 0, + /*tp_del*/ 0, + /*tp_version_tag*/ 0 +}, }, + /*priv_data*/ 0 +}; + + +static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) +{ + SbkObject* sbkObj = reinterpret_cast(pyObj); + PyTypeObject* pyType = Py_TYPE(pyObj); + + // Need to decref the type if this is the dealloc func; if type + // is subclassed, that dealloc func will decref (see subtype_dealloc + // in typeobject.c in the python sources) + bool needTypeDecref = (pyType->tp_dealloc == SbkDeallocWrapper + || pyType->tp_dealloc == SbkDeallocWrapperWithPrivateDtor); + + // Ensure that the GC is no longer tracking this object to avoid a + // possible reentrancy problem. Since there are multiple steps involved + // in deallocating a SbkObject it is possible for the garbage collector to + // be invoked and it trying to delete this object while it is still in + // progress from the first time around, resulting in a double delete and a + // crash. + PyObject_GC_UnTrack(pyObj); + + // Check that Python is still initialized as sometimes this is called by a static destructor + // after Python interpeter is shutdown. + if (sbkObj->weakreflist && Py_IsInitialized()) + PyObject_ClearWeakRefs(pyObj); + + // If I have ownership and is valid delete C++ pointer + if (canDelete && sbkObj->d->hasOwnership && sbkObj->d->validCppObject) { + SbkObjectType* sbkType = reinterpret_cast(pyType); + if (sbkType->d->is_multicpp) { + Shiboken::DeallocVisitor visitor(sbkObj); + Shiboken::walkThroughClassHierarchy(pyObj->ob_type, &visitor); + } else { + void* cptr = sbkObj->d->cptr[0]; + Shiboken::Object::deallocData(sbkObj, true); + + Shiboken::ThreadStateSaver threadSaver; + if (Py_IsInitialized()) + threadSaver.save(); + sbkType->d->cpp_dtor(cptr); + } + } else { + Shiboken::Object::deallocData(sbkObj, true); + } + + if (needTypeDecref) + Py_DECREF(pyType); +} + +void SbkDeallocWrapper(PyObject* pyObj) +{ + SbkDeallocWrapperCommon(pyObj, true); +} + +void SbkDeallocWrapperWithPrivateDtor(PyObject* self) +{ + SbkDeallocWrapperCommon(self, false); +} + +void SbkObjectTypeDealloc(PyObject* pyObj) +{ + SbkObjectType* sbkType = reinterpret_cast(pyObj); + + PyObject_GC_UnTrack(pyObj); + Py_TRASHCAN_SAFE_BEGIN(pyObj); + if (sbkType->d) { + if(sbkType->d->user_data && sbkType->d->d_func) { + sbkType->d->d_func(sbkType->d->user_data); + sbkType->d->user_data = 0; + } + free(sbkType->d->original_name); + sbkType->d->original_name = 0; + if (!Shiboken::ObjectType::isUserType(reinterpret_cast(sbkType))) + Shiboken::Conversions::deleteConverter(sbkType->d->converter); + delete sbkType->d; + sbkType->d = 0; + } + Py_TRASHCAN_SAFE_END(pyObj); +} + +PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds) +{ +#ifndef IS_PY3K + // Check if all bases are new style before calling type.tp_new + // Was causing gc assert errors in test_bug704.py when + // this check happened after creating the type object. + // Argument parsing take from type.tp_new code. + PyObject* name; + PyObject* pyBases; + PyObject* dict; + static const char* kwlist[] = { "name", "bases", "dict", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:sbktype", (char**)kwlist, + &name, + &PyTuple_Type, &pyBases, + &PyDict_Type, &dict)) + return NULL; + + for(int i=0, i_max=PyTuple_GET_SIZE(pyBases); i < i_max; i++) { + PyObject* baseType = PyTuple_GET_ITEM(pyBases, i); + if (PyClass_Check(baseType)) { + PyErr_Format(PyExc_TypeError, "Invalid base class used in type %s. PySide only support multiple inheritance from python new style class.", metatype->tp_name); + return 0; + } + } +#endif + + // The meta type creates a new type when the Python programmer extends a wrapped C++ class. + SbkObjectType* newType = reinterpret_cast(PyType_Type.tp_new(metatype, args, kwds)); + if (!newType) + return 0; + + Shiboken::ObjectType::initPrivateData(newType); + SbkObjectTypePrivate* d = newType->d; + + std::list bases = Shiboken::getCppBaseClasses(reinterpret_cast(newType)); + if (bases.size() == 1) { + SbkObjectTypePrivate* parentType = bases.front()->d; + d->mi_offsets = parentType->mi_offsets; + d->mi_init = parentType->mi_init; + d->mi_specialcast = parentType->mi_specialcast; + d->type_discovery = parentType->type_discovery; + d->cpp_dtor = parentType->cpp_dtor; + d->is_multicpp = 0; + d->converter = parentType->converter; + } else { + d->mi_offsets = 0; + d->mi_init = 0; + d->mi_specialcast = 0; + d->type_discovery = 0; + d->cpp_dtor = 0; + d->is_multicpp = 1; + d->converter = 0; + } + if (bases.size() == 1) + d->original_name = strdup(bases.front()->d->original_name); + else + d->original_name = strdup("object"); + d->user_data = 0; + d->d_func = 0; + d->is_user_type = 1; + + std::list::const_iterator it = bases.begin(); + for (; it != bases.end(); ++it) { + if ((*it)->d->subtype_init) + (*it)->d->subtype_init(newType, args, kwds); + } + + return reinterpret_cast(newType); +} + +PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*) +{ + SbkObject* self = PyObject_GC_New(SbkObject, subtype); + Py_INCREF(reinterpret_cast(subtype)); + SbkObjectPrivate* d = new SbkObjectPrivate; + + SbkObjectType* sbkType = reinterpret_cast(subtype); + int numBases = ((sbkType->d && sbkType->d->is_multicpp) ? Shiboken::getNumberOfCppBaseClasses(subtype) : 1); + d->cptr = new void*[numBases]; + std::memset(d->cptr, 0, sizeof(void*)*numBases); + d->hasOwnership = 1; + d->containsCppWrapper = 0; + d->validCppObject = 0; + d->parentInfo = 0; + d->referredObjects = 0; + d->cppObjectCreated = 0; + self->ob_dict = 0; + self->weakreflist = 0; + self->d = d; + PyObject_GC_Track(reinterpret_cast(self)); + return reinterpret_cast(self); +} + + +} //extern "C" + + +namespace +{ + +void _destroyParentInfo(SbkObject* obj, bool keepReference) +{ + Shiboken::ParentInfo* pInfo = obj->d->parentInfo; + if (pInfo) { + while(!pInfo->children.empty()) { + SbkObject* first = *pInfo->children.begin(); + // Mark child as invalid + Shiboken::Object::invalidate(first); + Shiboken::Object::removeParent(first, false, keepReference); + } + Shiboken::Object::removeParent(obj, false); + } +} + +} + +namespace Shiboken +{ + +static void decRefPyObjectList(const std::list &pyObj, PyObject* skip = 0); + +static void _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) { + PyTypeObject* type = reinterpret_cast(PyTuple_GET_ITEM(bases, i)); + + if (!PyType_IsSubtype(type, reinterpret_cast(&SbkObject_Type))) { + continue; + } else { + SbkObjectType* sbkType = reinterpret_cast(type); + if (sbkType->d->is_user_type) + _walkThroughClassHierarchy(type, visitor); + else + visitor->visit(sbkType); + } + if (visitor->wasFinished()) + break; + } +} + +void walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor) +{ + _walkThroughClassHierarchy(currentType, visitor); + visitor->done(); +} + + +bool importModule(const char* moduleName, PyTypeObject*** cppApiPtr) +{ + PyObject* sysModules = PyImport_GetModuleDict(); + PyObject* module = PyDict_GetItemString(sysModules, moduleName); + if (!module) { + module = PyImport_ImportModule(moduleName); + if (!module) + return false; + } else { + Py_INCREF(module); + } + + Shiboken::AutoDecRef cppApi(PyObject_GetAttrString(module, "_Cpp_Api")); + Py_DECREF(module); + + if (cppApi.isNull()) + return false; + +#ifdef IS_PY3K + if (PyCapsule_CheckExact(cppApi)) + *cppApiPtr = reinterpret_cast(PyCapsule_GetPointer(cppApi, 0)); +#else + // Python 2.6 doesn't have PyCapsule API, so let's keep usign PyCObject on all Python 2.x + if (PyCObject_Check(cppApi)) + *cppApiPtr = reinterpret_cast(PyCObject_AsVoidPtr(cppApi)); +#endif + return true; +} + +// Wrapper metatype and base type ---------------------------------------------------------- + +void DtorCallerVisitor::visit(SbkObjectType* node) +{ + m_ptrs.push_back(std::make_pair(m_pyObj->d->cptr[m_ptrs.size()], node)); +} + +void DtorCallerVisitor::done() +{ + std::list >::const_iterator it = m_ptrs.begin(); + for (; it != m_ptrs.end(); ++it) { + Shiboken::ThreadStateSaver threadSaver; + threadSaver.save(); + it->second->d->cpp_dtor(it->first); + } +} + +void DeallocVisitor::done() +{ + Shiboken::Object::deallocData(m_pyObj, true); + DtorCallerVisitor::done(); +} + +namespace Conversions { void init(); } + +void init() +{ + static bool shibokenAlreadInitialised = false; + if (shibokenAlreadInitialised) + return; + + Conversions::init(); + + initTypeResolver(); + PyEval_InitThreads(); + + //Init private data + Shiboken::ObjectType::initPrivateData(&SbkObject_Type); + + if (PyType_Ready(&SbkEnumType_Type) < 0) + Py_FatalError("[libshiboken] Failed to initialise Shiboken.SbkEnumType metatype."); + + if (PyType_Ready(&SbkObjectType_Type) < 0) + Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapperType metatype."); + + if (PyType_Ready(reinterpret_cast(&SbkObject_Type)) < 0) + Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapper type."); + + shibokenAlreadInitialised = true; +} + +void setErrorAboutWrongArguments(PyObject* args, const char* funcName, const char** cppOverloads) +{ + std::string msg; + std::string params; + if (args) { + if (PyTuple_Check(args)) { + for (Py_ssize_t i = 0, max = PyTuple_GET_SIZE(args); i < max; ++i) { + if (i) + params += ", "; + PyObject* arg = PyTuple_GET_ITEM(args, i); + params += arg->ob_type->tp_name; + } + } else { + params = args->ob_type->tp_name; + } + } + + if (!cppOverloads) { + msg = "'" + std::string(funcName) + "' called with wrong argument types: " + params; + } else { + msg = "'" + std::string(funcName) + "' called with wrong argument types:\n "; + msg += funcName; + msg += '('; + msg += params; + msg += ")\n"; + msg += "Supported signatures:"; + for (int i = 0; cppOverloads[i]; ++i) { + msg += "\n "; + msg += funcName; + msg += '('; + msg += cppOverloads[i]; + msg += ')'; + } + } + PyErr_SetString(PyExc_TypeError, msg.c_str()); + +} + +class FindBaseTypeVisitor : public HierarchyVisitor +{ + public: + FindBaseTypeVisitor(PyTypeObject* typeToFind) : m_found(false), m_typeToFind(typeToFind) {} + virtual void visit(SbkObjectType* node) + { + if (reinterpret_cast(node) == m_typeToFind) { + m_found = true; + finish(); + } + } + bool found() const { return m_found; } + + private: + bool m_found; + PyTypeObject* m_typeToFind; +}; + +std::list splitPyObject(PyObject* pyObj) +{ + std::list result; + if (PySequence_Check(pyObj)) { + AutoDecRef lst(PySequence_Fast(pyObj, "Invalid keep reference object.")); + if (!lst.isNull()) { + for (Py_ssize_t i = 0, i_max = PySequence_Fast_GET_SIZE(lst.object()); i < i_max; ++i) { + PyObject* item = PySequence_Fast_GET_ITEM(lst.object(), i); + if (Object::checkType(item)) + result.push_back(reinterpret_cast(item)); + } + } + } else { + result.push_back(reinterpret_cast(pyObj)); + } + return result; +} + +static void decRefPyObjectList(const std::list& lst, PyObject *skip) +{ + std::list::const_iterator iter = lst.begin(); + while(iter != lst.end()) { + if (*iter != skip) + Py_DECREF(*iter); + ++iter; + } +} + +namespace ObjectType +{ + +bool checkType(PyTypeObject* type) +{ + return PyType_IsSubtype(type, reinterpret_cast(&SbkObject_Type)); +} + +bool isUserType(PyTypeObject* type) +{ + return checkType(type) && reinterpret_cast(type)->d->is_user_type; +} + +bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) +{ + FindBaseTypeVisitor visitor(ctorType); + walkThroughClassHierarchy(myType, &visitor); + if (!visitor.found()) { + PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", ctorType->tp_name, myType->tp_name); + return false; + } + return true; +} + + +bool hasExternalCppConversions(SbkObjectType*) { return false; } // DEPRECATED. +bool isExternalConvertible(SbkObjectType *, PyObject *) { return false; } // DEPRECATED. +void setExternalCppConversionFunction(SbkObjectType*, ExtendedToCppFunc) {} // DEPRECATED. +void setExternalIsConvertibleFunction(SbkObjectType*, ExtendedIsConvertibleFunc) {} // DEPRECATED. +void* callExternalCppConversion(SbkObjectType*, PyObject*) { return 0; } // DEPRECATED. + + +bool hasCast(SbkObjectType* type) +{ + return type->d->mi_specialcast; +} + +void* cast(SbkObjectType* sourceType, SbkObject* obj, PyTypeObject* targetType) +{ + return sourceType->d->mi_specialcast(Object::cppPointer(obj, targetType), reinterpret_cast(targetType)); +} + +void setCastFunction(SbkObjectType* type, SpecialCastFunction func) +{ + type->d->mi_specialcast = func; +} + +void setOriginalName(SbkObjectType* self, const char* name) +{ + if (self->d->original_name) + free(self->d->original_name); + self->d->original_name = strdup(name); +} + +const char* getOriginalName(SbkObjectType* self) +{ + return self->d->original_name; +} + +void setTypeDiscoveryFunctionV2(SbkObjectType* self, TypeDiscoveryFuncV2 func) +{ + self->d->type_discovery = func; +} + +void setTypeDiscoveryFunction(SbkObjectType* self, TypeDiscoveryFunc func) +{ + self->d->type_discovery = (TypeDiscoveryFuncV2)func; +} + +TypeDiscoveryFunc getTypeDiscoveryFunction(SbkObjectType* self) +{ + // This is an illegal cast because the return value is different, + // but nobody ever used this function, so... =] + return (TypeDiscoveryFunc)self->d->type_discovery; +} + +void copyMultimpleheritance(SbkObjectType* self, SbkObjectType* other) +{ + self->d->mi_init = other->d->mi_init; + self->d->mi_offsets = other->d->mi_offsets; + self->d->mi_specialcast = other->d->mi_specialcast; +} + +void setMultipleIheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction function) +{ + self->d->mi_init = function; +} + +MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* self) +{ + return self->d->mi_init; +} + +void setDestructorFunction(SbkObjectType* self, ObjectDestructor func) +{ + self->d->cpp_dtor = func; +} + +void initPrivateData(SbkObjectType* self) +{ + self->d = new SbkObjectTypePrivate; + memset(self->d, 0, sizeof(SbkObjectTypePrivate)); +} + +bool introduceWrapperType(PyObject* enclosingObject, + const char* typeName, const char* originalName, + SbkObjectType* type, ObjectDestructor cppObjDtor, + SbkObjectType* baseType, PyObject* baseTypes, + bool isInnerClass) +{ + initPrivateData(type); + setOriginalName(type, originalName); + setDestructorFunction(type, cppObjDtor); + + if (baseType) { + type->super.ht_type.tp_base = reinterpret_cast(baseType); + if (baseTypes) { + for (int i = 0; i < PySequence_Fast_GET_SIZE(baseTypes); ++i) + BindingManager::instance().addClassInheritance(reinterpret_cast(PySequence_Fast_GET_ITEM(baseTypes, i)), type); + type->super.ht_type.tp_bases = baseTypes; + } else { + BindingManager::instance().addClassInheritance(baseType, type); + } + } + + if (PyType_Ready(reinterpret_cast(type)) < 0) + return false; + + if (isInnerClass) + return PyDict_SetItemString(enclosingObject, typeName, reinterpret_cast(type)) == 0; + + //PyModule_AddObject steals type's reference. + Py_INCREF(reinterpret_cast(type)); + return PyModule_AddObject(enclosingObject, typeName, reinterpret_cast(type)) == 0; +} + +void setSubTypeInitHook(SbkObjectType* self, SubTypeInitHook func) +{ + self->d->subtype_init = func; +} + +void* getTypeUserData(SbkObjectType* self) +{ + return self->d->user_data; +} + +void setTypeUserData(SbkObjectType* self, void* userData, DeleteUserDataFunc d_func) +{ + self->d->user_data = userData; + self->d->d_func = d_func; +} + +} // namespace ObjectType + + +namespace Object +{ + +static void recursive_invalidate(SbkObject* self, std::set& seen); + +bool checkType(PyObject* pyObj) +{ + return ObjectType::checkType(pyObj->ob_type); +} + +bool isUserType(PyObject* pyObj) +{ + return ObjectType::isUserType(pyObj->ob_type); +} + +Py_hash_t hash(PyObject* pyObj) +{ + assert(Shiboken::Object::checkType(pyObj)); + return reinterpret_cast(pyObj); +} + +static void setSequenceOwnership(PyObject* pyObj, bool owner) +{ + if (PySequence_Check(pyObj)) { + std::list objs = splitPyObject(pyObj); + std::list::const_iterator it = objs.begin(); + for(; it != objs.end(); ++it) { + if (owner) + getOwnership(*it); + else + releaseOwnership(*it); + } + } else if (Object::checkType(pyObj)) { + if (owner) + getOwnership(reinterpret_cast(pyObj)); + else + releaseOwnership(reinterpret_cast(pyObj)); + } +} + +void setValidCpp(SbkObject* pyObj, bool value) +{ + pyObj->d->validCppObject = value; +} + +void setHasCppWrapper(SbkObject* pyObj, bool value) +{ + pyObj->d->containsCppWrapper = value; +} + +bool hasCppWrapper(SbkObject* pyObj) +{ + return pyObj->d->containsCppWrapper; +} + +bool wasCreatedByPython(SbkObject* pyObj) +{ + return pyObj->d->cppObjectCreated; +} + +void callCppDestructors(SbkObject* pyObj) +{ + SbkObjectType* sbkType = reinterpret_cast(Py_TYPE(pyObj)); + if (sbkType->d->is_multicpp) { + Shiboken::DtorCallerVisitor visitor(pyObj); + Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor); + } else { + Shiboken::ThreadStateSaver threadSaver; + threadSaver.save(); + sbkType->d->cpp_dtor(pyObj->d->cptr[0]); + } + + /* invalidate needs to be called before deleting pointer array because + it needs to delete entries for them from the BindingManager hash table; + also release wrapper explicitly if object contains C++ wrapper because + invalidate doesn't */ + invalidate(pyObj); + if (pyObj->d->validCppObject && pyObj->d->containsCppWrapper) { + BindingManager::instance().releaseWrapper(pyObj); + } + + delete[] pyObj->d->cptr; + pyObj->d->cptr = 0; + pyObj->d->validCppObject = false; +} + +bool hasOwnership(SbkObject* pyObj) +{ + return pyObj->d->hasOwnership; +} + +void getOwnership(SbkObject* self) +{ + // skip if already have the ownership + if (self->d->hasOwnership) + return; + + // skip if this object has parent + if (self->d->parentInfo && self->d->parentInfo->parent) + return; + + // Get back the ownership + self->d->hasOwnership = true; + + if (self->d->containsCppWrapper) + Py_DECREF(reinterpret_cast(self)); // Remove extra ref + else + makeValid(self); // Make the object valid again +} + +void getOwnership(PyObject* pyObj) +{ + if (pyObj) + setSequenceOwnership(pyObj, true); +} + +void releaseOwnership(SbkObject* self) +{ + // skip if the ownership have already moved to c++ + SbkObjectType* selfType = reinterpret_cast(Py_TYPE(self)); + if (!self->d->hasOwnership || Shiboken::Conversions::pythonTypeIsValueType(selfType->d->converter)) + return; + + // remove object ownership + self->d->hasOwnership = false; + + // If We have control over object life + if (self->d->containsCppWrapper) + Py_INCREF(reinterpret_cast(self)); // keep the python object alive until the wrapper destructor call + else + invalidate(self); // If I do not know when this object will die We need to invalidate this to avoid use after +} + +void releaseOwnership(PyObject* self) +{ + setSequenceOwnership(self, false); +} + +/* Needed forward declarations */ +static void recursive_invalidate(PyObject* pyobj, std::set& seen); +static void recursive_invalidate(SbkObject* self, std::set& seen); + +void invalidate(PyObject* pyobj) +{ + std::set seen; + recursive_invalidate(pyobj, seen); +} + +void invalidate(SbkObject* self) +{ + std::set seen; + recursive_invalidate(self, seen); +} + +static void recursive_invalidate(PyObject* pyobj, std::set& seen) +{ + std::list objs = splitPyObject(pyobj); + std::list::const_iterator it = objs.begin(); + for (; it != objs.end(); it++) + recursive_invalidate(*it, seen); +} + +static void recursive_invalidate(SbkObject* self, std::set& seen) +{ + // Skip if this object not is a valid object or if it's already been seen + if (!self || reinterpret_cast(self) == Py_None || seen.find(self) != seen.end()) + return; + seen.insert(self); + + if (!self->d->containsCppWrapper) { + self->d->validCppObject = false; // Mark object as invalid only if this is not a wrapper class + BindingManager::instance().releaseWrapper(self); + } + + // If it is a parent invalidate all children. + if (self->d->parentInfo) { + // Create a copy because this list can be changed during the process + ChildrenList copy = self->d->parentInfo->children; + ChildrenList::iterator it = copy.begin(); + + for (; it != copy.end(); ++it) { + // invalidate the child + recursive_invalidate(*it, 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); + } + } + + // 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 lst = iter->second; + std::list::const_iterator it = lst.begin(); + while(it != lst.end()) { + recursive_invalidate(*it, seen); + ++it; + } + } + } +} + +void makeValid(SbkObject* self) +{ + // Skip if this object not is a valid object + if (!self || reinterpret_cast(self) == Py_None || self->d->validCppObject) + return; + + // Mark object as invalid only if this is not a wrapper class + self->d->validCppObject = true; + + // If it is a parent make all children valid + if (self->d->parentInfo) { + ChildrenList::iterator it = self->d->parentInfo->children.begin(); + for (; it != self->d->parentInfo->children.end(); ++it) + makeValid(*it); + } + + // 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 lst = iter->second; + std::list::const_iterator it = lst.begin(); + while(it != lst.end()) { + if (Shiboken::Object::checkType(*it)) + makeValid(reinterpret_cast(*it)); + ++it; + } + } + } +} + +bool hasParentInfo(SbkObject* pyObj) +{ + return pyObj->d->parentInfo; +} + +void* cppPointer(SbkObject* pyObj, PyTypeObject* desiredType) +{ + PyTypeObject* type = Py_TYPE(pyObj); + int idx = 0; + if (reinterpret_cast(type)->d->is_multicpp) + idx = getTypeIndexOnHierarchy(type, desiredType); + if (pyObj->d->cptr) + return pyObj->d->cptr[idx]; + return 0; +} + +std::vector cppPointers(SbkObject* pyObj) +{ + int n = getNumberOfCppBaseClasses(Py_TYPE(pyObj)); + std::vector ptrs(n); + for (int i = 0; i < n; ++i) + ptrs[i] = pyObj->d->cptr[i]; + return ptrs; +} + + +bool setCppPointer(SbkObject* sbkObj, PyTypeObject* desiredType, void* cptr) +{ + int idx = 0; + if (reinterpret_cast(Py_TYPE(sbkObj))->d->is_multicpp) + idx = getTypeIndexOnHierarchy(Py_TYPE(sbkObj), desiredType); + + bool alreadyInitialized = sbkObj->d->cptr[idx]; + if (alreadyInitialized) + PyErr_SetString(PyExc_RuntimeError, "You can't initialize an object twice!"); + else + sbkObj->d->cptr[idx] = cptr; + + sbkObj->d->cppObjectCreated = true; + return !alreadyInitialized; +} + +bool isValid(PyObject* pyObj) +{ + if (!pyObj || pyObj == Py_None + || Py_TYPE(pyObj->ob_type) != &SbkObjectType_Type) { + return true; + } + + SbkObjectPrivate* priv = reinterpret_cast(pyObj)->d; + + if (!priv->cppObjectCreated && isUserType(pyObj)) { + PyErr_Format(PyExc_RuntimeError, "'__init__' method of object's base class (%s) not called.", pyObj->ob_type->tp_name); + return false; + } + + if (!priv->validCppObject) { + PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", pyObj->ob_type->tp_name); + return false; + } + + return true; +} + +bool isValid(SbkObject* pyObj, bool throwPyError) +{ + if (!pyObj) + return false; + + SbkObjectPrivate* priv = pyObj->d; + if (!priv->cppObjectCreated && isUserType(reinterpret_cast(pyObj))) { + if (throwPyError) + PyErr_Format(PyExc_RuntimeError, "Base constructor of the object (%s) not called.", Py_TYPE(pyObj)->tp_name); + return false; + } + + if (!priv->validCppObject) { + if (throwPyError) + PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", Py_TYPE(pyObj)->tp_name); + return false; + } + + return true; +} + +bool isValid(PyObject* pyObj, bool throwPyError) +{ + if (!pyObj || pyObj == Py_None || + !PyType_IsSubtype(pyObj->ob_type, reinterpret_cast(&SbkObject_Type))) { + return true; + } + return isValid(reinterpret_cast(pyObj), throwPyError); +} + +SbkObject *findColocatedChild(SbkObject *wrapper, + const SbkObjectType *instanceType) +{ + // Degenerate case, wrapper is the correct wrapper. + if (reinterpret_cast(Py_TYPE(wrapper)) == reinterpret_cast(instanceType)) + return wrapper; + + if (!(wrapper->d && wrapper->d->cptr)) + return 0; + + ParentInfo* pInfo = wrapper->d->parentInfo; + if (!pInfo) + return 0; + + ChildrenList& children = pInfo->children; + + ChildrenList::iterator childrenEnd = children.end(); + for (ChildrenList::iterator iChild = children.begin(); iChild != childrenEnd; ++iChild) { + if (!((*iChild)->d && (*iChild)->d->cptr)) + continue; + if ((*iChild)->d->cptr[0] == wrapper->d->cptr[0]) { + if (reinterpret_cast(Py_TYPE(*iChild)) == reinterpret_cast(instanceType)) + return const_cast((*iChild)); + else + return findColocatedChild(const_cast(*iChild), instanceType); + } + } + return 0; +} + + +PyObject *newObject(SbkObjectType* instanceType, + void* cptr, + bool hasOwnership, + bool isExactType, + const char* typeName) +{ + // Try to find the exact type of cptr. + if (!isExactType) { + PyTypeObject* exactType = 0; + if (typeName) { + exactType = Shiboken::Conversions::getPythonTypeObject(typeName); + if (exactType) + instanceType = reinterpret_cast(exactType); + } + if (!exactType) + instanceType = BindingManager::instance().resolveType(&cptr, instanceType); + } + + bool shouldCreate = true; + bool shouldRegister = true; + SbkObject* self = 0; + + // Some logic to ensure that colocated child field does not overwrite the parent + if (BindingManager::instance().hasWrapper(cptr)) { + SbkObject* existingWrapper = BindingManager::instance().retrieveWrapper(cptr); + + self = findColocatedChild(existingWrapper, instanceType); + if (self) { + // Wrapper already registered for cptr. + // This should not ideally happen, binding code should know when a wrapper + // already exists and retrieve it instead. + shouldRegister = shouldCreate = false; + } else if (hasOwnership && + (!(Shiboken::Object::hasCppWrapper(existingWrapper) || + Shiboken::Object::hasOwnership(existingWrapper)))) { + // Old wrapper is likely junk, since we have ownership and it doesn't. + BindingManager::instance().releaseWrapper(existingWrapper); + } else { + // Old wrapper may be junk caused by some bug in identifying object deletion + // but it may not be junk when a colocated field is accessed for an + // object which was not created by python (returned from c++ factory function). + // Hence we cannot release the wrapper confidently so we do not register. + shouldRegister = false; + } + } + + if (shouldCreate) { + self = reinterpret_cast(SbkObjectTpNew(reinterpret_cast(instanceType), 0, 0)); + self->d->cptr[0] = cptr; + self->d->hasOwnership = hasOwnership; + self->d->validCppObject = 1; + if (shouldRegister) { + BindingManager::instance().registerWrapper(self, cptr); + } + } else { + Py_IncRef(reinterpret_cast(self)); + } + return reinterpret_cast(self); +} + +void destroy(SbkObject* self) +{ + destroy(self, 0); +} + +void destroy(SbkObject* self, void* cppData) +{ + // Skip if this is called with NULL pointer this can happen in derived classes + if (!self) + return; + + // This can be called in c++ side + Shiboken::GilState gil; + + // Remove all references attached to this object + clearReferences(self); + + // Remove the object from parent control + + // Verify if this object has parent + bool hasParent = (self->d->parentInfo && self->d->parentInfo->parent); + + if (self->d->parentInfo) { + // Check for children information and make all invalid if they exists + _destroyParentInfo(self, true); + // If this object has parent then the pyobject can be invalid now, because we remove the last ref after remove from parent + } + + //if !hasParent this object could still alive + if (!hasParent && self->d->containsCppWrapper && !self->d->hasOwnership) { + // Remove extra ref used by c++ object this will case the pyobject destruction + // This can cause the object death + Py_DECREF(reinterpret_cast(self)); + } + + //Python Object is not destroyed yet + if (cppData && Shiboken::BindingManager::instance().hasWrapper(cppData)) { + // Remove from BindingManager + Shiboken::BindingManager::instance().releaseWrapper(self); + self->d->hasOwnership = false; + + // the cpp object instance was deleted + delete[] self->d->cptr; + self->d->cptr = 0; + } + + // After this point the object can be death do not use the self pointer bellow +} + +void removeParent(SbkObject* child, bool giveOwnershipBack, bool keepReference) +{ + ParentInfo* pInfo = child->d->parentInfo; + if (!pInfo || !pInfo->parent) { + if (pInfo && pInfo->hasWrapperRef) { + pInfo->hasWrapperRef = false; + } + return; + } + + ChildrenList& oldBrothers = pInfo->parent->d->parentInfo->children; + // Verify if this child is part of parent list + ChildrenList::iterator iChild = std::find(oldBrothers.begin(), oldBrothers.end(), child); + if (iChild == oldBrothers.end()) + return; + + oldBrothers.erase(iChild); + + pInfo->parent = 0; + + // This will keep the wrapper reference, will wait for wrapper destruction to remove that + if (keepReference && + child->d->containsCppWrapper) { + //If have already a extra ref remove this one + if (pInfo->hasWrapperRef) + Py_DECREF(child); + else + pInfo->hasWrapperRef = true; + return; + } + + // Transfer ownership back to Python + child->d->hasOwnership = giveOwnershipBack; + + // Remove parent ref + Py_DECREF(child); +} + +void setParent(PyObject* parent, PyObject* child) +{ + if (!child || child == Py_None || child == parent) + return; + + /* + * setParent is recursive when the child is a native Python sequence, i.e. objects not binded by Shiboken + * like tuple and list. + * + * This "limitation" exists to fix the following problem: A class multiple inherits QObject and QString, + * so if you pass this class to someone that takes the ownership, we CAN'T enter in this if, but hey! QString + * follows the sequence protocol. + */ + if (PySequence_Check(child) && !Object::checkType(child)) { + Shiboken::AutoDecRef seq(PySequence_Fast(child, 0)); + for (Py_ssize_t i = 0, max = PySequence_Size(seq); i < max; ++i) + setParent(parent, PySequence_Fast_GET_ITEM(seq.object(), i)); + return; + } + + bool parentIsNull = !parent || parent == Py_None; + SbkObject* parent_ = reinterpret_cast(parent); + SbkObject* child_ = reinterpret_cast(child); + + if (!parentIsNull) { + if (!parent_->d->parentInfo) + parent_->d->parentInfo = new ParentInfo; + + // do not re-add a child + if (child_->d->parentInfo && (child_->d->parentInfo->parent == parent_)) + return; + } + + ParentInfo* pInfo = child_->d->parentInfo; + bool hasAnotherParent = pInfo && pInfo->parent && pInfo->parent != parent_; + + //Avoid destroy child during reparent operation + Py_INCREF(child); + + // check if we need to remove this child from the old parent + if (parentIsNull || hasAnotherParent) + removeParent(child_); + + // Add the child to the new parent + pInfo = child_->d->parentInfo; + if (!parentIsNull) { + if (!pInfo) + pInfo = child_->d->parentInfo = new ParentInfo; + + pInfo->parent = parent_; + parent_->d->parentInfo->children.insert(child_); + + // Add Parent ref + Py_INCREF(child_); + + // Remove ownership + child_->d->hasOwnership = false; + } + + // Remove previous safe ref + Py_DECREF(child); +} + +void deallocData(SbkObject* self, bool cleanup) +{ + // Make cleanup if this is not a wrapper otherwise this will be done on wrapper destructor + if(cleanup) { + removeParent(self); + + if (self->d->parentInfo) + _destroyParentInfo(self, true); + + clearReferences(self); + } + + if (self->d->cptr) { + // Remove from BindingManager + Shiboken::BindingManager::instance().releaseWrapper(self); + delete[] self->d->cptr; + self->d->cptr = 0; + // delete self->d; PYSIDE-205: wrong! + } + delete self->d; // PYSIDE-205: always delete d. + Py_XDECREF(self->ob_dict); + Py_TYPE(self)->tp_free(self); +} + +void setTypeUserData(SbkObject* wrapper, void* userData, DeleteUserDataFunc d_func) +{ + SbkObjectType* ob_type = reinterpret_cast(Py_TYPE(wrapper)); + if (ob_type->d->user_data) + ob_type->d->d_func(ob_type->d->user_data); + + ob_type->d->d_func = d_func; + ob_type->d->user_data = userData; +} + +void* getTypeUserData(SbkObject* wrapper) +{ + return reinterpret_cast(Py_TYPE(wrapper))->d->user_data; +} + +void keepReference(SbkObject* self, const char* key, PyObject* referredObject, bool append) +{ + 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 objects; + if (iter != refCountMap.end()) { + objects = (*iter).second; + std::list::const_iterator found = std::find(objects.begin(), objects.end(), referredObject); + + // skip if objects already exists + if (found != objects.end()) + return; + } + + 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); + } + } +} + +void removeReference(SbkObject* self, const char* key, PyObject* referredObject) +{ + if (!referredObject || (referredObject == Py_None)) + return; + + if (!self->d->referredObjects) + return; + + RefCountMap& refCountMap = *(self->d->referredObjects); + RefCountMap::iterator iter = refCountMap.find(key); + if (iter != refCountMap.end()) { + decRefPyObjectList(iter->second); + refCountMap.erase(iter); + } +} + +void clearReferences(SbkObject* self) +{ + if (!self->d->referredObjects) + return; + + RefCountMap& refCountMap = *(self->d->referredObjects); + RefCountMap::iterator iter; + for (iter = refCountMap.begin(); iter != refCountMap.end(); ++iter) + decRefPyObjectList(iter->second); + self->d->referredObjects->clear(); +} + +std::string info(SbkObject* self) +{ + std::ostringstream s; + std::list bases; + + if (self->d && self->d->cptr) { + if (ObjectType::isUserType(Py_TYPE(self))) + bases = getCppBaseClasses(Py_TYPE(self)); + else + bases.push_back(reinterpret_cast(Py_TYPE(self))); + + s << "C++ address....... "; + std::list::const_iterator it = bases.begin(); + for (int i = 0; it != bases.end(); ++it, ++i) + s << reinterpret_cast(*it)->tp_name << '/' << self->d->cptr[i] << ' '; + s << "\n"; + } + else { + s << "C++ address....... <>\n"; + } + + s << "hasOwnership...... " << bool(self->d->hasOwnership) << "\n" + "containsCppWrapper " << self->d->containsCppWrapper << "\n" + "validCppObject.... " << self->d->validCppObject << "\n" + "wasCreatedByPython " << self->d->cppObjectCreated << "\n"; + + + if (self->d->parentInfo && self->d->parentInfo->parent) { + s << "parent............ "; + Shiboken::AutoDecRef parent(PyObject_Str(reinterpret_cast(self->d->parentInfo->parent))); + s << String::toCString(parent) << "\n"; + } + + if (self->d->parentInfo && self->d->parentInfo->children.size()) { + 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(*it))); + s << String::toCString(child) << ' '; + } + s << '\n'; + } + + if (self->d->referredObjects && self->d->referredObjects->size()) { + 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::const_iterator j = it->second.begin(); + for (; j != it->second.end(); ++j) { + Shiboken::AutoDecRef obj(PyObject_Str(*j)); + s << String::toCString(obj) << ' '; + } + s << ' '; + } + s << '\n'; + } + return s.str(); +} + +} // namespace Object + +} // namespace Shiboken diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h new file mode 100644 index 000000000..002337f3c --- /dev/null +++ b/sources/shiboken2/libshiboken/basewrapper.h @@ -0,0 +1,451 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef BASEWRAPPER_H +#define BASEWRAPPER_H + +#include "sbkpython.h" +#include "shibokenmacros.h" + +#include +#include + +extern "C" +{ + +struct SbkConverter; +struct SbkObjectPrivate; + +/// Base Python object for all the wrapped C++ classes. +struct LIBSHIBOKEN_API SbkObject +{ + PyObject_HEAD + /// Instance dictionary. + PyObject* ob_dict; + /// List of weak references + PyObject* weakreflist; + SbkObjectPrivate* d; +}; + + +/// Dealloc the python object \p pyObj and the C++ object represented by it. +LIBSHIBOKEN_API void SbkDeallocWrapper(PyObject* pyObj); +LIBSHIBOKEN_API void SbkDeallocWrapperWithPrivateDtor(PyObject* self); + +struct SbkObjectType; + +/// Function signature for the multiple inheritance information initializers that should be provided by classes with multiple inheritance. +typedef int* (*MultipleInheritanceInitFunction)(const void*); + +/** + * Special cast function is used to correctly cast an object when it's + * part of a multiple inheritance hierarchy. + * The implementation of this function is auto generated by the generator and you don't need to care about it. + */ +typedef void* (*SpecialCastFunction)(void*, SbkObjectType*); +typedef SbkObjectType* (*TypeDiscoveryFunc)(void*, SbkObjectType*); +typedef void* (*TypeDiscoveryFuncV2)(void*, SbkObjectType*); + +typedef void* (*ExtendedToCppFunc)(PyObject*); // DEPRECATED. +typedef bool (*ExtendedIsConvertibleFunc)(PyObject*); // DEPRECATED. + +// Used in userdata dealloc function +typedef void (*DeleteUserDataFunc)(void*); + +typedef void (*ObjectDestructor)(void*); + +typedef void (*SubTypeInitHook)(SbkObjectType*, PyObject*, PyObject*); + +extern LIBSHIBOKEN_API PyTypeObject SbkObjectType_Type; +extern LIBSHIBOKEN_API SbkObjectType SbkObject_Type; + + +struct SbkObjectTypePrivate; +/// PyTypeObject extended with C++ multiple inheritance information. +struct LIBSHIBOKEN_API SbkObjectType +{ + PyHeapTypeObject super; + SbkObjectTypePrivate* d; +}; + +LIBSHIBOKEN_API PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*); + +} // extern "C" + +namespace Shiboken +{ + +/** +* Init shiboken library. +*/ +LIBSHIBOKEN_API void init(); + + +/// Delete the class T allocated on \p cptr. +template +void callCppDestructor(void* cptr) +{ + delete reinterpret_cast(cptr); +} + +/** + * Shiboken::importModule is DEPRECATED. Use Shiboken::Module::import() instead. + */ +SBK_DEPRECATED(LIBSHIBOKEN_API bool importModule(const char* moduleName, PyTypeObject*** cppApiPtr)); +LIBSHIBOKEN_API void setErrorAboutWrongArguments(PyObject* args, const char* funcName, const char** cppOverloads); + +namespace ObjectType { + +/** +* Returns true if the object is an instance of a type created by the Shiboken generator. +*/ +LIBSHIBOKEN_API bool checkType(PyTypeObject* pyObj); + +/** +* Returns true if this object is an instance of an user defined type derived from an Shiboken type. +*/ +LIBSHIBOKEN_API bool isUserType(PyTypeObject* pyObj); + +/** +* Returns true if the constructor of \p ctorType can be called for a instance of type \p myType. +* \note This function set a python error when returning false. +*/ +LIBSHIBOKEN_API bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType); + + +LIBSHIBOKEN_API bool hasExternalCppConversions(SbkObjectType*); // DEPRECATED. +LIBSHIBOKEN_API bool isExternalConvertible(SbkObjectType*, PyObject*); // DEPRECATED. +LIBSHIBOKEN_API void setExternalCppConversionFunction(SbkObjectType*, ExtendedToCppFunc); // DEPRECATED. +LIBSHIBOKEN_API void setExternalIsConvertibleFunction(SbkObjectType*, ExtendedIsConvertibleFunc); // DEPRECATED. +LIBSHIBOKEN_API void* callExternalCppConversion(SbkObjectType*, PyObject*); // DEPRECATED. + + +/** + * Tells if the \p type represents an object of a class with multiple inheritance in C++. + * When this occurs, the C++ pointer held by the Python wrapper will need to be cast when + * passed as a parameter that expects a type of its ancestry. + * \returns true if a call to ObjectType::cast() is needed to obtain the correct + * C++ pointer for Python objects of type \p type. + */ +LIBSHIBOKEN_API bool hasCast(SbkObjectType* type); +/** + * Cast the C++ pointer held by a Python object \p obj of type \p sourceType, + * to a C++ pointer of a C++ class indicated by type \p targetType. + * \returns The cast C++ pointer. + */ +LIBSHIBOKEN_API void* cast(SbkObjectType* sourceType, SbkObject* obj, PyTypeObject* targetType); +/// Set the C++ cast function for \p type. +LIBSHIBOKEN_API void setCastFunction(SbkObjectType* type, SpecialCastFunction func); + +LIBSHIBOKEN_API void setOriginalName(SbkObjectType* self, const char* name); +LIBSHIBOKEN_API const char* getOriginalName(SbkObjectType* self); + +LIBSHIBOKEN_API void setTypeDiscoveryFunctionV2(SbkObjectType* self, TypeDiscoveryFuncV2 func); +LIBSHIBOKEN_API SBK_DEPRECATED(void setTypeDiscoveryFunction(SbkObjectType* self, TypeDiscoveryFunc func)); +LIBSHIBOKEN_API SBK_DEPRECATED(TypeDiscoveryFunc getTypeDiscoveryFunction(SbkObjectType* self)); + +LIBSHIBOKEN_API void copyMultimpleheritance(SbkObjectType* self, SbkObjectType* other); +LIBSHIBOKEN_API void setMultipleIheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction func); +LIBSHIBOKEN_API MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* self); + +LIBSHIBOKEN_API void setDestructorFunction(SbkObjectType* self, ObjectDestructor func); + +LIBSHIBOKEN_API void initPrivateData(SbkObjectType* self); + +/** + * Initializes a Shiboken wrapper type and adds it to the module, + * or to the enclosing class if the type is an inner class. + * This function also calls initPrivateData and setDestructorFunction. + * \param enclosingObject The module or enclosing class to where the new \p type will be added. + * \param typeName Name by which the type will be known in Python. + * \param originalName Original C++ name of the type. + * \param type The new type to be initialized and added to the module. + * \param cppObjDtor Memory deallocation function for the C++ object held by \p type. + * Should not be used if the underlying C++ class has a private destructor. + * \param baseType Base type from whom the new \p type inherits. + * \param baseTypes Other base types from whom the new \p type inherits. + * \param isInnerClass Tells if the new \p type is an inner class (the default is that it isn't). + * If false then the \p enclosingObject is a module, otherwise it is another + * wrapper type. + * \returns true if the initialization went fine, false otherwise. + */ +LIBSHIBOKEN_API bool introduceWrapperType(PyObject* enclosingObject, + const char* typeName, const char* originalName, + SbkObjectType* type, ObjectDestructor cppObjDtor = 0, + SbkObjectType* baseType = 0, PyObject* baseTypes = 0, + bool isInnerClass = false); + +/** + * Set the subtype init hook for a type. + * + * This hook will be invoked every time the user creates a sub-type inherited from a Shiboken based type. + * The hook gets 3 params, they are: The new type being created, args and kwds. The last two are the very + * same got from tp_new. + */ +LIBSHIBOKEN_API void setSubTypeInitHook(SbkObjectType* self, SubTypeInitHook func); + +/** + * Get the user data previously set by Shiboken::Object::setTypeUserData + */ +LIBSHIBOKEN_API void* getTypeUserData(SbkObjectType* self); +LIBSHIBOKEN_API void setTypeUserData(SbkObjectType* self, void* userData, DeleteUserDataFunc d_func); + +} + +namespace Object { + +/** + * Returns a string with information about the internal state of the instance object, useful for debug purposes. + */ +LIBSHIBOKEN_API std::string info(SbkObject* self); + +/** +* Returns true if the object is an instance of a type created by the Shiboken generator. +*/ +LIBSHIBOKEN_API bool checkType(PyObject* pyObj); + +/** + * Returns true if this object type is an instance of an user defined type derived from an Shiboken type. + * \see Shiboken::ObjectType::isUserType + */ +LIBSHIBOKEN_API bool isUserType(PyObject* pyObj); + +/** + * Generic function used to make ObjectType hashable, the C++ pointer is used as hash value. + */ +LIBSHIBOKEN_API Py_hash_t hash(PyObject* pyObj); + +/** + * Find a child of given wrapper having same address having the specified type. + */ +LIBSHIBOKEN_API SbkObject *findColocatedChild(SbkObject *wrapper, + const SbkObjectType *instanceType); + +/** + * Bind a C++ object to Python. + * \param instanceType equivalent Python type for the C++ object. + * \param hasOwnership if true, Python will try to delete the underlying C++ object when there's no more refs. + * \param isExactType if false, Shiboken will use some heuristics to detect the correct Python type of this C++ + * object, in any case you must provide \p instanceType, it'll be used as search starting point + * and as fallback. + * \param typeName If non-null, this will be used as helper to find the correct Python type for this object. + */ +LIBSHIBOKEN_API PyObject* newObject(SbkObjectType* instanceType, + void* cptr, + bool hasOwnership = true, + bool isExactType = false, + const char* typeName = 0); + +/** + * Changes the valid flag of a PyObject, invalid objects will raise an exception when someone tries to access it. + */ +LIBSHIBOKEN_API void setValidCpp(SbkObject* pyObj, bool value); +/** + * Tells shiboken the Python object \p pyObj has a C++ wrapper used to intercept virtual method calls. + */ +LIBSHIBOKEN_API void setHasCppWrapper(SbkObject* pyObj, bool value); +/** + * Return true if the Python object \p pyObj has a C++ wrapper used to intercept virtual method calls. + */ +LIBSHIBOKEN_API bool hasCppWrapper(SbkObject* pyObj); + +/** + * Return true if the Python object was created by Python, false otherwise. + * \note This function was added to libshiboken only to be used by shiboken.wasCreatedByPython() + */ +LIBSHIBOKEN_API bool wasCreatedByPython(SbkObject* pyObj); + +/** + * Call the C++ object destructor and invalidates the Python object. + * \note This function was added to libshiboken only to be used by shiboken.delete() + */ +LIBSHIBOKEN_API void callCppDestructors(SbkObject* pyObj); + +/** + * Return true if the Python is responsible for deleting the underlying C++ object. + */ +LIBSHIBOKEN_API bool hasOwnership(SbkObject* pyObj); + +/** + * Sets python as responsible to delete the underlying C++ object. + * \note You this overload only when the PyObject can be a sequence and you want to + * call this function for every item in the sequence. + * \see getOwnership(SbkObject*) + */ +LIBSHIBOKEN_API void getOwnership(PyObject* pyObj); + +/** + * Sets python as responsible to delete the underlying C++ object. + */ +LIBSHIBOKEN_API void getOwnership(SbkObject* pyObj); + +/** + * Release the ownership, so Python will not delete the underlying C++ object. + * \note You this overload only when the PyObject can be a sequence and you want to + * call this function for every item in the sequence. + * \see releaseOwnership(SbkObject*) + */ +LIBSHIBOKEN_API void releaseOwnership(PyObject* pyObj); +/** + * Release the ownership, so Python will not delete the underlying C++ object. + */ +LIBSHIBOKEN_API void releaseOwnership(SbkObject* pyObj); + +/** + * Returns true if the pyObj holds information about their parents. + */ +LIBSHIBOKEN_API bool hasParentInfo(SbkObject* pyObj); + +/** + * Get the C++ pointer of type \p desiredType from a Python object. + */ +LIBSHIBOKEN_API void* cppPointer(SbkObject* pyObj, PyTypeObject* desiredType); + +/** + * Return a list with all C++ pointers held from a Python object. + * \note This function was added to libshiboken only to be used by shiboken.getCppPointer() + */ +LIBSHIBOKEN_API std::vector cppPointers(SbkObject* pyObj); + +/** + * Set the C++ pointer of type \p desiredType of a Python object. + */ +LIBSHIBOKEN_API bool setCppPointer(SbkObject* sbkObj, PyTypeObject* desiredType, void* cptr); + +/** + * Returns false and sets a Python RuntimeError if the Python wrapper is not marked as valid. + */ +LIBSHIBOKEN_API bool isValid(PyObject* pyObj); + +/** + * Returns false if the Python wrapper is not marked as valid. + * \param pyObj the object. + * \param throwPyError sets a Python RuntimeError when the object isn't valid. + */ +LIBSHIBOKEN_API bool isValid(SbkObject* pyObj, bool throwPyError = true); + +/** + * Returns false if the Python wrapper is not marked as valid. + * \param pyObj the object. + * \param throwPyError sets a Python RuntimeError when the object isn't valid. + */ +LIBSHIBOKEN_API bool isValid(PyObject* pyObj, bool throwPyError); + +/** +* Set the parent of \p child to \p parent. +* When an object dies, all their children, grandchildren, etc, are tagged as invalid. +* \param parent the parent object, if null, the child will have no parents. +* \param child the child. +*/ +LIBSHIBOKEN_API void setParent(PyObject* parent, PyObject* child); + +/** +* Remove this child from their parent, if any. +* \param child the child. +*/ +LIBSHIBOKEN_API void removeParent(SbkObject* child, bool giveOwnershipBack = true, bool keepReferenc = false); + +/** +* \internal This is an internal function called by tp_dealloc, it's exported just for technical reasons. +* \note Do not call this function inside your bindings. +*/ +LIBSHIBOKEN_API void destroyParentInfo(SbkObject* obj, bool removeFromParent = true); + +/** + * Mark the object as invalid + */ +LIBSHIBOKEN_API void invalidate(SbkObject* self); + +/** + * Help function can be used to invalidate a sequence of object + **/ +LIBSHIBOKEN_API void invalidate(PyObject* pyobj); + +/** + * Make the object valid again + */ +LIBSHIBOKEN_API void makeValid(SbkObject* self); + +/// \deprecated Use destroy(SbkObject*, void*) +SBK_DEPRECATED(LIBSHIBOKEN_API void destroy(SbkObject* self)); + +/** + * Destroy any data in Shiboken structure and c++ pointer if the pyboject has the ownership + */ +LIBSHIBOKEN_API void destroy(SbkObject* self, void* cppData); + +/** + * Set user data on type of \p wrapper. + * \param wrapper instance object, the user data will be set on his type + * \param userData the user data + * \param d_func a function used to delete the user data + */ +LIBSHIBOKEN_API void setTypeUserData(SbkObject* wrapper, void* userData, DeleteUserDataFunc d_func); +/** + * Get the user data previously set by Shiboken::Object::setTypeUserData + */ +LIBSHIBOKEN_API void* getTypeUserData(SbkObject* wrapper); + +/** + * Increments the reference count of the referred Python object. + * A previous Python object in the same position identified by the 'key' parameter + * will have its reference counter decremented automatically when replaced. + * All the kept references should be decremented when the Python wrapper indicated by + * 'self' dies. + * No checking is done for any of the passed arguments, since it is meant to be used + * by generated code it is supposed that the generator is correct. + * \param self the wrapper instance that keeps references to other objects. + * \param key a key that identifies the C++ method signature and argument where the referred Object came from. + * \param referredObject the object whose reference is used by the self object. + */ +LIBSHIBOKEN_API void keepReference(SbkObject* self, const char* key, PyObject* referredObject, bool append = false); + +/** + * Removes any reference previously added by keepReference function + * \param self the wrapper instance that keeps references to other objects. + * \param key a key that identifies the C++ method signature and argument from where the referred Object came. + * \param referredObject the object whose reference is used by the self object. + */ +LIBSHIBOKEN_API void removeReference(SbkObject* self, const char* key, PyObject* referredObject); + +} // namespace Object + +} // namespace Shiboken + +#endif // BASEWRAPPER_H diff --git a/sources/shiboken2/libshiboken/basewrapper_p.h b/sources/shiboken2/libshiboken/basewrapper_p.h new file mode 100644 index 000000000..129322246 --- /dev/null +++ b/sources/shiboken2/libshiboken/basewrapper_p.h @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef BASEWRAPPER_P_H +#define BASEWRAPPER_P_H + +#include "sbkpython.h" +#include "basewrapper.h" + +#include +#include +#include +#include + +struct SbkObject; +struct SbkObjectType; +struct SbkConverter; + +namespace Shiboken +{ +/** + * This mapping associates a method and argument of an wrapper object with the wrapper of + * said argument when it needs the binding to help manage its reference count. + */ +typedef std::map > RefCountMap; + +/// Linked list of SbkBaseWrapper pointers +typedef std::set ChildrenList; + +/// Structure used to store information about object parent and children. +struct ParentInfo +{ + /// Default ctor. + ParentInfo() : parent(0), hasWrapperRef(false) {} + /// Pointer to parent object. + SbkObject* parent; + /// List of object children. + ChildrenList children; + /// has internal ref + bool hasWrapperRef; +}; + +} // namespace Shiboken + +extern "C" +{ + +/** + * \internal + * Private data for SbkBaseWrapper + */ +struct SbkObjectPrivate +{ + /// Pointer to the C++ class. + void** cptr; + /// True when Python is responsible for freeing the used memory. + unsigned int hasOwnership : 1; + /// This is true when the C++ class of the wrapped object has a virtual destructor AND was created by Python. + unsigned int containsCppWrapper : 1; + /// Marked as false when the object is lost to C++ and the binding can not know if it was deleted or not. + unsigned int validCppObject : 1; + /// Marked as true when the object constructor was called + unsigned int cppObjectCreated : 1; + /// Information about the object parents and children, may be null. + Shiboken::ParentInfo* parentInfo; + /// Manage reference count of objects that are referred to but not owned from. + Shiboken::RefCountMap* referredObjects; + + ~SbkObjectPrivate() + { + delete parentInfo; + parentInfo = 0; + delete referredObjects; + referredObjects = 0; + } +}; + +// TODO-CONVERTERS: to be deprecated/removed +/// The type behaviour was not defined yet +#define BEHAVIOUR_UNDEFINED 0 +/// The type is a value type +#define BEHAVIOUR_VALUETYPE 1 +/// The type is an object type +#define BEHAVIOUR_OBJECTTYPE 2 + +struct SbkObjectTypePrivate +{ + SbkConverter* converter; + int* mi_offsets; + MultipleInheritanceInitFunction mi_init; + + /// Special cast function, null if this class doesn't have multiple inheritance. + SpecialCastFunction mi_specialcast; + TypeDiscoveryFuncV2 type_discovery; + /// Pointer to a function responsible for deletion of the C++ instance calling the proper destructor. + ObjectDestructor cpp_dtor; + /// True if this type holds two or more C++ instances, e.g.: a Python class which inherits from two C++ classes. + int is_multicpp : 1; + /// True if this type was defined by the user. + int is_user_type : 1; + /// 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; + /// C++ name + char* original_name; + /// Type user data + void* user_data; + DeleteUserDataFunc d_func; + void (*subtype_init)(SbkObjectType*, PyObject*, PyObject*); +}; + + +} // extern "C" + +namespace Shiboken +{ +/** + * Utility function used to transform a PyObject that implements sequence protocol into a std::list. + **/ +std::list splitPyObject(PyObject* pyObj); + +/** +* Visitor class used by walkOnClassHierarchy function. +*/ +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; +}; + +class BaseCountVisitor : public HierarchyVisitor +{ +public: + BaseCountVisitor() : m_count(0) {} + + void visit(SbkObjectType*) + { + m_count++; + } + + int count() const { return m_count; } +private: + int m_count; +}; + +class BaseAccumulatorVisitor : public HierarchyVisitor +{ +public: + BaseAccumulatorVisitor() {} + + void visit(SbkObjectType* node) + { + m_bases.push_back(node); + } + + std::list bases() const { return m_bases; } +private: + std::list 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(node), m_desiredType)) + finish(); + } + int index() const { return m_index; } + +private: + int m_index; + PyTypeObject* m_desiredType; +}; + +/// Call the destructor of each C++ object held by a Python object +class DtorCallerVisitor : public HierarchyVisitor +{ +public: + DtorCallerVisitor(SbkObject* pyObj) : m_pyObj(pyObj) {} + void visit(SbkObjectType* node); + void done(); +protected: + std::list > m_ptrs; + SbkObject* m_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(); +}; + +/// \internal Internal function used to walk on classes inheritance trees. +/** +* Walk on class hierarchy using a DFS algorithm. +* 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); + +inline int getTypeIndexOnHierarchy(PyTypeObject* baseType, PyTypeObject* desiredType) +{ + GetIndexVisitor visitor(desiredType); + walkThroughClassHierarchy(baseType, &visitor); + return visitor.index(); +} + +inline int getNumberOfCppBaseClasses(PyTypeObject* baseType) +{ + BaseCountVisitor visitor; + walkThroughClassHierarchy(baseType, &visitor); + return visitor.count(); +} + +inline std::list getCppBaseClasses(PyTypeObject* baseType) +{ + BaseAccumulatorVisitor visitor; + walkThroughClassHierarchy(baseType, &visitor); + return visitor.bases(); +} + +namespace Object +{ +/** +* Decrements the reference counters of every object referred by self. +* \param self the wrapper instance that keeps references to other objects. +*/ +void clearReferences(SbkObject* self); + +/** + * Destroy internal data + **/ +void deallocData(SbkObject* self, bool doCleanup); + +} // namespace Object + +} // namespace Shiboken + +#endif diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp new file mode 100644 index 000000000..3308ef972 --- /dev/null +++ b/sources/shiboken2/libshiboken/bindingmanager.cpp @@ -0,0 +1,341 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "basewrapper.h" +#include "basewrapper_p.h" +#include "bindingmanager.h" +#include "sbkdbg.h" +#include "gilstate.h" +#include "sbkstring.h" +#include "debugfreehook.h" + +#include +#include +#include + +namespace Shiboken +{ + +typedef std::unordered_map WrapperMap; + +class Graph +{ +public: + typedef std::list NodeList; + typedef std::unordered_map Edges; + + Edges m_edges; + + Graph() + { + } + + void addEdge(SbkObjectType* from, SbkObjectType* to) + { + m_edges[from].push_back(to); + } + +#ifndef NDEBUG + void dumpDotGraph() + { + std::ofstream file("/tmp/shiboken_graph.dot"); + + file << "digraph D {\n"; + + Edges::const_iterator i = m_edges.begin(); + for (; i != m_edges.end(); ++i) { + SbkObjectType* node1 = i->first; + const NodeList& nodeList = i->second; + NodeList::const_iterator j = nodeList.begin(); + for (; j != nodeList.end(); ++j) + file << '"' << (*j)->super.ht_type.tp_name << "\" -> \"" << node1->super.ht_type.tp_name << "\"\n"; + } + file << "}\n"; + } +#endif + + SbkObjectType* identifyType(void** cptr, SbkObjectType* type, SbkObjectType* baseType) const + { + 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); + if (newType) + return newType; + } + } + void* typeFound = ((type->d && type->d->type_discovery) ? type->d->type_discovery(*cptr, baseType) : 0); + if (typeFound) { + // This "typeFound != type" is needed for backwards compatibility with old modules using a newer version of + // libshiboken because old versions of type_discovery function used to return a SbkObjectType* instead of + // a possible variation of the C++ instance pointer (*cptr). + if (typeFound != type) + *cptr = typeFound; + return type; + } else { + return 0; + } + } +}; + + +#ifndef NDEBUG +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, + static_cast(sbkObj), + Py_TYPE(sbkObj)->tp_name, + int(reinterpret_cast(sbkObj)->ob_refcnt)); + } + fprintf(stderr, "-------------------------------\n"); + } +} +#endif + +struct BindingManager::BindingManagerPrivate { + WrapperMap wrapperMapper; + Graph classHierarchy; + bool destroying; + + BindingManagerPrivate() : destroying(false) {} + bool releaseWrapper(void* cptr, SbkObject* wrapper); + void assignWrapper(SbkObject* wrapper, const void* cptr); + +}; + +bool BindingManager::BindingManagerPrivate::releaseWrapper(void* cptr, SbkObject* wrapper) +{ + // The wrapper argument is checked to ensure that the correct wrapper is released. + // Returns true if the correct wrapper is found and released. + // If wrapper argument is NULL, no such check is performed. + WrapperMap::iterator iter = wrapperMapper.find(cptr); + if (iter != wrapperMapper.end() && (wrapper == 0 || iter->second == wrapper)) { + wrapperMapper.erase(iter); + return true; + } + return false; +} + +void BindingManager::BindingManagerPrivate::assignWrapper(SbkObject* wrapper, const void* cptr) +{ + assert(cptr); + WrapperMap::iterator iter = wrapperMapper.find(cptr); + if (iter == wrapperMapper.end()) + wrapperMapper.insert(std::make_pair(cptr, wrapper)); +} + +BindingManager::BindingManager() +{ + m_d = new BindingManager::BindingManagerPrivate; + +#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK + debugInstallFreeHook(); +#endif +} + +BindingManager::~BindingManager() +{ +#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK + debugRemoveFreeHook(); +#endif +#ifndef NDEBUG + showWrapperMap(m_d->wrapperMapper); +#endif + /* Cleanup hanging references. We just invalidate them as when + * the BindingManager is being destroyed the interpreter is alredy + * shutting down. */ + if (Py_IsInitialized()) { // ensure the interpreter is still valid + while (!m_d->wrapperMapper.empty()) { + Object::destroy(m_d->wrapperMapper.begin()->second, const_cast(m_d->wrapperMapper.begin()->first)); + } + assert(m_d->wrapperMapper.size() == 0); + } + delete m_d; +} + +BindingManager& BindingManager::instance() { + static BindingManager singleton; + return singleton; +} + +bool BindingManager::hasWrapper(const void* cptr) +{ + return m_d->wrapperMapper.find(cptr) != m_d->wrapperMapper.end(); +} + +void BindingManager::registerWrapper(SbkObject* pyObj, void* cptr) +{ + SbkObjectType* instanceType = reinterpret_cast(Py_TYPE(pyObj)); + SbkObjectTypePrivate* d = instanceType->d; + + if (!d) + return; + + if (d->mi_init && !d->mi_offsets) + d->mi_offsets = d->mi_init(cptr); + m_d->assignWrapper(pyObj, cptr); + if (d->mi_offsets) { + int* offset = d->mi_offsets; + while (*offset != -1) { + if (*offset > 0) + m_d->assignWrapper(pyObj, reinterpret_cast((std::size_t) cptr + (*offset))); + offset++; + } + } +} + +void BindingManager::releaseWrapper(SbkObject* sbkObj) +{ + SbkObjectType* sbkType = reinterpret_cast(Py_TYPE(sbkObj)); + SbkObjectTypePrivate* d = sbkType->d; + int numBases = ((d && d->is_multicpp) ? getNumberOfCppBaseClasses(Py_TYPE(sbkObj)) : 1); + + void** cptrs = reinterpret_cast(sbkObj)->d->cptr; + for (int i = 0; i < numBases; ++i) { + unsigned char *cptr = reinterpret_cast(cptrs[i]); + m_d->releaseWrapper(cptr, sbkObj); + if (d && d->mi_offsets) { + int* offset = d->mi_offsets; + while (*offset != -1) { + if (*offset > 0) + m_d->releaseWrapper(reinterpret_cast((std::size_t) cptr + (*offset)), sbkObj); + offset++; + } + } + } + sbkObj->d->validCppObject = false; +} + +SbkObject* BindingManager::retrieveWrapper(const void* cptr) +{ + WrapperMap::iterator iter = m_d->wrapperMapper.find(cptr); + if (iter == m_d->wrapperMapper.end()) + return 0; + return iter->second; +} + +PyObject* BindingManager::getOverride(const void* cptr, const char* methodName) +{ + SbkObject* wrapper = retrieveWrapper(cptr); + // The refcount can be 0 if the object is dieing and someone called + // a virtual method from the destructor + if (!wrapper || reinterpret_cast(wrapper)->ob_refcnt == 0) + return 0; + + if (wrapper->ob_dict) { + PyObject* method = PyDict_GetItemString(wrapper->ob_dict, methodName); + if (method) { + Py_INCREF(reinterpret_cast(method)); + return method; + } + } + + PyObject* pyMethodName = Shiboken::String::fromCString(methodName); + PyObject *method = PyObject_GetAttr(reinterpret_cast(wrapper), pyMethodName); + + if (method && PyMethod_Check(method) + && reinterpret_cast(method)->im_self == reinterpret_cast(wrapper)) { + PyObject* defaultMethod; + PyObject* mro = Py_TYPE(wrapper)->tp_mro; + + // The first class in the mro (index 0) is the class being checked and it should not be tested. + // The last class in the mro (size - 1) is the base Python object class which should not be tested also. + for (int i = 1; i < PyTuple_GET_SIZE(mro) - 1; i++) { + PyTypeObject* parent = reinterpret_cast(PyTuple_GET_ITEM(mro, i)); + if (parent->tp_dict) { + defaultMethod = PyDict_GetItem(parent->tp_dict, pyMethodName); + if (defaultMethod && reinterpret_cast(method)->im_func != defaultMethod) { + Py_DECREF(pyMethodName); + return method; + } + } + } + } + + Py_XDECREF(method); + Py_DECREF(pyMethodName); + return 0; +} + +void BindingManager::addClassInheritance(SbkObjectType* parent, SbkObjectType* child) +{ + m_d->classHierarchy.addEdge(parent, child); +} + +SbkObjectType* BindingManager::resolveType(void* cptr, SbkObjectType* type) +{ + return resolveType(&cptr, type); +} + +SbkObjectType* BindingManager::resolveType(void** cptr, SbkObjectType* type) +{ + SbkObjectType* identifiedType = m_d->classHierarchy.identifyType(cptr, type, type); + return identifiedType ? identifiedType : type; +} + +std::set BindingManager::getAllPyObjects() +{ + std::set pyObjects; + const WrapperMap& wrappersMap = m_d->wrapperMapper; + WrapperMap::const_iterator it = wrappersMap.begin(); + for (; it != wrappersMap.end(); ++it) + pyObjects.insert(reinterpret_cast(it->second)); + + return pyObjects; +} + +void BindingManager::visitAllPyObjects(ObjectVisitor visitor, void* data) +{ + WrapperMap copy = m_d->wrapperMapper; + for (WrapperMap::iterator it = copy.begin(); it != copy.end(); ++it) { + if (hasWrapper(it->first)) + visitor(it->second, data); + } +} + +} // namespace Shiboken + diff --git a/sources/shiboken2/libshiboken/bindingmanager.h b/sources/shiboken2/libshiboken/bindingmanager.h new file mode 100644 index 000000000..80c5add2f --- /dev/null +++ b/sources/shiboken2/libshiboken/bindingmanager.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef BINDINGMANAGER_H +#define BINDINGMANAGER_H + +#include "sbkpython.h" +#include +#include "shibokenmacros.h" + +struct SbkObject; +struct SbkObjectType; + +namespace Shiboken +{ + +typedef void (*ObjectVisitor)(SbkObject*, void*); + +class LIBSHIBOKEN_API BindingManager +{ +public: + static BindingManager& instance(); + + bool hasWrapper(const void *cptr); + + void registerWrapper(SbkObject* pyObj, void* cptr); + void releaseWrapper(SbkObject* wrapper); + + SbkObject* retrieveWrapper(const void* cptr); + PyObject* getOverride(const void* cptr, const char* methodName); + + void addClassInheritance(SbkObjectType* parent, SbkObjectType* child); + /** + * \deprecated Use \fn resolveType(void**, SbkObjectType*), this version is broken when used with multiple inheritance + * because the \p cptr pointer of the discovered type may be different of the given \p cptr in case + * of multiple inheritance + */ + SBK_DEPRECATED(SbkObjectType* resolveType(void* cptr, SbkObjectType* type)); + /** + * Try to find the correct type of *cptr knowing that it's at least of type \p type. + * In case of multiple inheritance this function may change the contents of cptr. + * \param cptr a pointer to a pointer to the instance of type \p type + * \param type type of *cptr + * \warning This function is slow, use it only as last resort. + */ + SbkObjectType* resolveType(void** cptr, SbkObjectType* type); + + std::set getAllPyObjects(); + + /** + * Calls the function \p visitor for each object registered on binding manager. + * \note As various C++ pointers can point to the same PyObject due to multiple inheritance + * a PyObject can be called more than one time for each PyObject. + * \param visitor function called for each object. + * \param data user data passed as second argument to the visitor function. + */ + void visitAllPyObjects(ObjectVisitor visitor, void* data); + +private: + ~BindingManager(); + // disable copy + BindingManager(); + BindingManager(const BindingManager&); + BindingManager& operator=(const BindingManager&); + + struct BindingManagerPrivate; + BindingManagerPrivate* m_d; +}; + +} // namespace Shiboken + +#endif // BINDINGMANAGER_H + diff --git a/sources/shiboken2/libshiboken/conversions.h b/sources/shiboken2/libshiboken/conversions.h new file mode 100644 index 000000000..f0af2be8e --- /dev/null +++ b/sources/shiboken2/libshiboken/conversions.h @@ -0,0 +1,731 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef CONVERSIONS_H +#define CONVERSIONS_H + +#include "sbkpython.h" +#include +#include + +#include "sbkstring.h" +#include "sbkenum.h" +#include "basewrapper.h" +#include "bindingmanager.h" +#include "sbkdbg.h" + +// When the user adds a function with an argument unknown for the typesystem, the generator writes type checks as +// TYPENAME_Check, so this macro allows users to add PyObject arguments to their added functions. +#define PyObject_Check(X) true +#define SbkChar_Check(X) (SbkNumber_Check(X) || Shiboken::String::checkChar(X)) +#include "autodecref.h" + +namespace Shiboken +{ +/** +* This function template is used to get the PyTypeObject of a C++ type T. +* All implementations should be provided by template specializations generated by the generator when +* T isn't a C++ primitive type. +* \see SpecialCastFunction +*/ +template +PyTypeObject* SbkType() +{ + return 0; +} + +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType() { return &PyBool_Type; } +template<> inline PyTypeObject* SbkType() { return &PyFloat_Type; } +template<> inline PyTypeObject* SbkType() { return &PyFloat_Type; } +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } + +/** + * Convenience template to create wrappers using the proper Python type for a given C++ class instance. + */ +template +inline PyObject* createWrapper(const T* cppobj, bool hasOwnership = false, bool isExactType = false) +{ + const char* typeName = 0; + if (!isExactType) + typeName = typeid(*const_cast(cppobj)).name(); + return Object::newObject(reinterpret_cast(SbkType()), + const_cast(cppobj), hasOwnership, isExactType, typeName); +} + +// Base Conversions ---------------------------------------------------------- +// The basic converter must be empty to avoid object types being converted by value. +template struct Converter {}; + +// Pointer conversion specialization for value types. +template +struct Converter +{ + static inline bool checkType(PyObject* pyObj) + { + return Converter::checkType(pyObj); + } + + static inline bool isConvertible(PyObject* pyObj) + { + return pyObj == Py_None || PyObject_TypeCheck(pyObj, SbkType()); + } + + static PyObject* toPython(const T* cppobj) + { + if (!cppobj) + Py_RETURN_NONE; + PyObject* pyobj = reinterpret_cast(BindingManager::instance().retrieveWrapper(cppobj)); + if (pyobj) + Py_INCREF(pyobj); + else + pyobj = createWrapper(cppobj); + return pyobj; + } + + static T* toCpp(PyObject* pyobj) + { + if (PyObject_TypeCheck(pyobj, SbkType())) + return reinterpret_cast(Object::cppPointer(reinterpret_cast(pyobj), SbkType())); + else if (Converter::isConvertible(pyobj)) + return new T(Converter::toCpp(pyobj)); + else if (pyobj == Py_None) + return 0; + + assert(false); + return 0; + } +}; +template struct Converter : Converter {}; + +// Specialization for reference conversions. +template +struct Converter +{ + static inline bool checkType(PyObject* pyObj) { return Converter::checkType(pyObj); } + static inline bool isConvertible(PyObject* pyObj) { return Converter::isConvertible(pyObj); } + static inline PyObject* toPython(const T& cppobj) { return Converter::toPython(&cppobj); } + static inline T& toCpp(PyObject* pyobj) { return *Converter::toCpp(pyobj); } +}; + +// Void pointer conversions. +template<> +struct Converter +{ + static inline bool checkType(PyObject *) { return false; } + static inline bool isConvertible(PyObject *) { return true; } + static PyObject* toPython(void* cppobj) + { + if (!cppobj) + Py_RETURN_NONE; + PyObject *result = reinterpret_cast(cppobj); + Py_INCREF(result); + return result; + } + static void* toCpp(PyObject* pyobj) { return pyobj; } +}; + +// Base converter meant to be inherited by converters for classes that could be +// passed by value. +// Example: "struct Converter : ValueTypeConverter" +template +struct ValueTypeConverter +{ + static inline bool checkType(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType()); } + + // The basic version of this method also tries to use the extended 'isConvertible' method. + static inline bool isConvertible(PyObject* pyobj) + { + if (PyObject_TypeCheck(pyobj, SbkType())) + return true; + SbkObjectType* shiboType = reinterpret_cast(SbkType()); + return ObjectType::isExternalConvertible(shiboType, pyobj); + } + static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } + static inline PyObject* toPython(const T& cppobj) + { + PyObject* obj = createWrapper(new T(cppobj), true, true); +// SbkBaseWrapper_setContainsCppWrapper(obj, SbkTypeInfo::isCppWrapper); + return obj; + } + // Classes with implicit conversions are expected to reimplement 'toCpp' to build T from + // its various implicit constructors. Even classes without implicit conversions could + // get some of those via other modules defining conversion operator for them, thus + // the basic Converter for value types checks for extended conversion and tries to + // use them if it is the case. + static inline T toCpp(PyObject* pyobj) + { + if (!PyObject_TypeCheck(pyobj, SbkType())) { + SbkObjectType* shiboType = reinterpret_cast(SbkType()); + if (ObjectType::hasExternalCppConversions(shiboType) && isConvertible(pyobj)) { + T* cptr = reinterpret_cast(ObjectType::callExternalCppConversion(shiboType, pyobj)); + const T result = *cptr; + delete cptr; + return result; + } + assert(false); + } + return *reinterpret_cast(Object::cppPointer(reinterpret_cast(pyobj), SbkType())); + } +}; + +// Base converter meant to be inherited by converters for abstract classes and object types +// (i.e. classes with private copy constructors and = operators). +// Example: "struct Converter : ObjectTypeConverter" +template +struct ObjectTypeConverter +{ + static inline bool checkType(PyObject* pyObj) { return pyObj == Py_None || PyObject_TypeCheck(pyObj, SbkType()); } + /// Py_None objects are the only objects convertible to an object type (in the form of a NULL pointer). + static inline bool isConvertible(PyObject* pyObj) { return pyObj == Py_None || PyObject_TypeCheck(pyObj, SbkType()); } + /// Convenience overload that calls "toPython(const T*)" method. + static inline PyObject* toPython(void* cppobj) { return toPython(reinterpret_cast(cppobj)); } + /// Returns a new Python wrapper for the C++ object or an existing one with its reference counter incremented. + static PyObject* toPython(const T* cppobj) + { + if (!cppobj) + Py_RETURN_NONE; + PyObject* pyobj = reinterpret_cast(BindingManager::instance().retrieveWrapper(cppobj)); + if (pyobj) + Py_INCREF(pyobj); + else + pyobj = createWrapper(cppobj); + return pyobj; + } + /// Returns the wrapped C++ pointer casted properly, or a NULL pointer if the argument is a Py_None. + static T* toCpp(PyObject* pyobj) + { + if (pyobj == Py_None) + return 0; + SbkObject *sbkObj = reinterpret_cast(pyobj); + SbkObjectType* shiboType = reinterpret_cast(pyobj->ob_type); + if (ObjectType::hasCast(shiboType)) + return reinterpret_cast(ObjectType::cast(shiboType, sbkObj, SbkType())); + return reinterpret_cast(Object::cppPointer(sbkObj, SbkType())); + } +}; + +template +struct ObjectTypeReferenceConverter : ObjectTypeConverter +{ + static inline bool checkType(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType()); } + static inline bool isConvertible(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType()); } + static inline PyObject* toPython(const T& cppobj) { return Converter::toPython(&cppobj); } + static inline T& toCpp(PyObject* pyobj) + { + T* t = Converter::toCpp(pyobj); + assert(t); + return *t; + } +}; + +// PyObject* specialization to avoid converting what doesn't need to be converted. +template<> +struct Converter : ObjectTypeConverter +{ + static inline PyObject* toCpp(PyObject* pyobj) { return pyobj; } +}; + +// Primitive Conversions ------------------------------------------------------ +template <> +struct Converter +{ + static inline bool checkType(PyObject* pyobj) { return PyBool_Check(pyobj); } + static inline bool isConvertible(PyObject* pyobj) { return PyInt_Check(pyobj); } + static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } + static inline PyObject* toPython(bool cppobj) { return PyBool_FromLong(cppobj); } + static inline bool toCpp(PyObject* pyobj) { return PyInt_AS_LONG(pyobj); } +}; + +/** + * Helper template for checking if a value overflows when casted to type T + */ +template::is_signed > +struct OverFlowChecker; + +template +struct OverFlowChecker +{ + static bool check(const PY_LONG_LONG& value) + { + return value < std::numeric_limits::min() || value > std::numeric_limits::max(); + } +}; + +template +struct OverFlowChecker +{ + static bool check(const PY_LONG_LONG& value) + { + return value < 0 || static_cast(value) > std::numeric_limits::max(); + } +}; + +template<> +struct OverFlowChecker +{ + static bool check(const PY_LONG_LONG &) + { + return false; + } +}; + +template<> +struct OverFlowChecker +{ + static bool check(const double &) + { + return false; + } +}; + +template<> +struct OverFlowChecker +{ + static bool check(const double& value) + { + return value < std::numeric_limits::min() || value > std::numeric_limits::max(); + } +}; + +template +struct Converter_PyInt +{ + static inline bool checkType(PyObject* pyobj) { return PyInt_Check(pyobj); } + static inline bool isConvertible(PyObject* pyobj) { return SbkNumber_Check(pyobj); } + static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } + static inline PyObject* toPython(const PyIntEquiv& cppobj) { return PyInt_FromLong((long) cppobj); } + static PyIntEquiv toCpp(PyObject* pyobj) + { + if (PyFloat_Check(pyobj)) { + double d_result = PyFloat_AS_DOUBLE(pyobj); + // If cast to long directly it could overflow silently + if (OverFlowChecker::check(d_result)) + PyErr_SetObject(PyExc_OverflowError, 0); + return static_cast(d_result); + } else { + PY_LONG_LONG result = PyLong_AsLongLong(pyobj); + if (OverFlowChecker::check(result)) + PyErr_SetObject(PyExc_OverflowError, 0); + return static_cast(result); + } + } +}; + +template +struct Converter_PyULongInt : Converter_PyInt +{ + static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } + static inline PyObject* toPython(const T& cppobj) { return PyLong_FromUnsignedLong(cppobj); } +}; + +/// Specialization to convert char and unsigned char, it accepts Python numbers and strings with just one character. +template +struct CharConverter +{ + static inline bool checkType(PyObject* pyobj) { return SbkChar_Check(pyobj); } + static inline bool isConvertible(PyObject* pyobj) { return SbkChar_Check(pyobj); } + static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } + static inline PyObject* toPython(const CharType& cppobj) { return PyInt_FromLong(cppobj); } + static CharType toCpp(PyObject* pyobj) + { + if (PyBytes_Check(pyobj)) { + assert(PyBytes_GET_SIZE(pyobj) == 1); // This check is made on SbkChar_Check + return PyBytes_AS_STRING(pyobj)[0]; + } else if (PyInt_Check(pyobj)) { + PY_LONG_LONG result = PyInt_AsUnsignedLongLongMask(pyobj); + if (OverFlowChecker::check(result)) + PyErr_SetObject(PyExc_OverflowError, 0); + return result; + } else if (Shiboken::String::check(pyobj)) { + return Shiboken::String::toCString(pyobj)[0]; + } else { + return 0; + } + } +}; + +template <> struct Converter : Converter_PyULongInt {}; +template <> struct Converter : Converter_PyULongInt {}; +template <> struct Converter : CharConverter +{ + // Should we really return a string? + using CharConverter::toPython; + using CharConverter::isConvertible; + using CharConverter::toCpp; + + + static inline bool isConvertible(PyObject* pyobj) { + return SbkChar_Check(pyobj); + } + + static inline PyObject* toPython(const char& cppObj) { + return Shiboken::String::fromFormat("%c", cppObj); + } + + static char toCpp(PyObject* pyobj) + { + if (PyBytes_Check(pyobj)) { + assert(PyBytes_GET_SIZE(pyobj) == 1); // This check is made on SbkChar_Check + return PyBytes_AS_STRING(pyobj)[0]; + } else if (PyInt_Check(pyobj)) { + PY_LONG_LONG result = PyInt_AsUnsignedLongLongMask(pyobj); + if (OverFlowChecker::check(result)) + PyErr_SetObject(PyExc_OverflowError, 0); + return char(result); + } else if (Shiboken::String::check(pyobj)) { + return Shiboken::String::toCString(pyobj)[0]; + } else { + return 0; + } + } +}; +template <> struct Converter : CharConverter {}; +template <> struct Converter : CharConverter {}; +template <> struct Converter : Converter_PyInt {}; +template <> struct Converter : Converter_PyInt {}; +template <> struct Converter : Converter_PyInt {}; +template <> struct Converter : Converter_PyInt {}; + +template <> +struct Converter +{ + static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } + static inline PyObject* toPython(PY_LONG_LONG cppobj) { return PyLong_FromLongLong(cppobj); } + static inline PY_LONG_LONG toCpp(PyObject* pyobj) { return (PY_LONG_LONG) PyLong_AsLongLong(pyobj); } +}; + +template <> +struct Converter +{ + static inline PyObject* toPython(void* cppobj) + { + return toPython(*reinterpret_cast(cppobj)); + } + static inline PyObject* toPython(unsigned PY_LONG_LONG cppobj) + { + return PyLong_FromUnsignedLongLong(cppobj); + } + static inline unsigned PY_LONG_LONG toCpp(PyObject* pyobj) + { +#if PY_MAJOR_VERSION >= 3 + if (!PyLong_Check(pyobj)) { + PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion"); + return 0; + } + + return PyLong_AsUnsignedLongLong(pyobj); +#else + if (PyInt_Check(pyobj)) { + long result = (unsigned PY_LONG_LONG) PyInt_AsLong(pyobj); + if (result < 0) { + PyErr_SetObject(PyExc_OverflowError, 0); + return 0; + } else + return (unsigned PY_LONG_LONG) result; + } else if (PyLong_Check(pyobj)) { + return (unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(pyobj); + } else { + PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion"); + return 0; + } +#endif // Python 2 + } +}; + +template +struct Converter_PyFloat +{ + static inline bool checkType(PyObject* obj) { return PyFloat_Check(obj); } + static inline bool isConvertible(PyObject* obj) { return SbkNumber_Check(obj); } + static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } + static inline PyObject* toPython(PyFloatEquiv cppobj) { return PyFloat_FromDouble((double) cppobj); } + static inline PyFloatEquiv toCpp(PyObject* pyobj) + { + if (PyInt_Check(pyobj) || PyLong_Check(pyobj)) + return (PyFloatEquiv) PyLong_AsLong(pyobj); + return (PyFloatEquiv) PyFloat_AsDouble(pyobj); + } +}; + +template <> struct Converter : Converter_PyFloat {}; +template <> struct Converter : Converter_PyFloat {}; + +// PyEnum Conversions --------------------------------------------------------- +template +struct EnumConverter +{ + static inline bool checkType(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType()); } + static inline bool isConvertible(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType()); } + static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } + static inline PyObject* toPython(CppEnum cppenum) + { + return Shiboken::Enum::newItem(Shiboken::SbkType(), (long) cppenum); + } + static inline CppEnum toCpp(PyObject* pyObj) + { + return (CppEnum) Shiboken::Enum::getValue(pyObj);; + } +}; + +// C Sting Types -------------------------------------------------------------- +template +struct Converter_CString +{ + // Note: 0 is also a const char* in C++, so None is accepted in checkType + static inline bool checkType(PyObject* pyObj) { + return Shiboken::String::check(pyObj); + } + static inline bool isConvertible(PyObject* pyObj) { + return Shiboken::String::isConvertible(pyObj); + } + static inline PyObject* toPython(void* cppobj) { return toPython(reinterpret_cast(cppobj)); } + static inline PyObject* toPython(CString cppobj) + { + if (!cppobj) + Py_RETURN_NONE; + return Shiboken::String::fromCString(cppobj); + } + static inline CString toCpp(PyObject* pyobj) { + if (pyobj == Py_None) + return 0; + return Shiboken::String::toCString(pyobj); + } +}; + +template <> struct Converter : Converter_CString {}; + +template <> struct Converter : Converter_CString +{ + static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } + static inline PyObject* toPython(std::string cppObj) + { + return Shiboken::String::fromCString(cppObj.c_str()); + } + + static inline std::string toCpp(PyObject* pyobj) + { + if (pyobj == Py_None) + return 0; + return std::string(Shiboken::String::toCString(pyobj)); + } +}; + +// C++ containers ------------------------------------------------------------- +// The following container converters are meant to be used for pairs, lists and maps +// that are similar to the STL containers of the same name. + +// For example to create a converter for a std::list the following code is enough: +// template struct Converter > : StdListConverter > {}; + +// And this for a std::map: +// template +// struct Converter > : StdMapConverter > {}; + +template +struct StdListConverter +{ + static inline bool checkType(PyObject* pyObj) + { + return isConvertible(pyObj); + } + + static inline bool isConvertible(PyObject* pyObj) + { + if (PyObject_TypeCheck(pyObj, SbkType())) + return true; + // Sequence conversion are made ONLY for python sequences, not for + // binded types implementing sequence protocol, otherwise this will + // cause a mess like QBitArray being accepted by someone expecting a + // QStringList. + if ((SbkType() && Object::checkType(pyObj)) || !PySequence_Check(pyObj)) + return false; + for (int i = 0, max = PySequence_Length(pyObj); i < max; ++i) { + AutoDecRef item(PySequence_GetItem(pyObj, i)); + if (!Converter::isConvertible(item)) + return false; + } + return true; + } + static PyObject* toPython(void* cppObj) { return toPython(*reinterpret_cast(cppObj)); } + static PyObject* toPython(const StdList& cppobj) + { + PyObject* result = PyList_New((int) cppobj.size()); + typename StdList::const_iterator it = cppobj.begin(); + for (int idx = 0; it != cppobj.end(); ++it, ++idx) { + typename StdList::value_type vh(*it); + PyList_SET_ITEM(result, idx, Converter::toPython(vh)); + } + return result; + } + static StdList toCpp(PyObject* pyobj) + { + if (PyObject_TypeCheck(pyobj, SbkType())) + return *reinterpret_cast(Object::cppPointer(reinterpret_cast(pyobj), SbkType())); + + StdList result; + for (int i = 0; i < PySequence_Size(pyobj); i++) { + AutoDecRef pyItem(PySequence_GetItem(pyobj, i)); + result.push_back(Converter::toCpp(pyItem)); + } + return result; + } +}; + +template +struct StdPairConverter +{ + static inline bool checkType(PyObject* pyObj) + { + return isConvertible(pyObj); + } + + static inline bool isConvertible(PyObject* pyObj) + { + if (PyObject_TypeCheck(pyObj, SbkType())) + return true; + if ((SbkType() && Object::checkType(pyObj)) || !PySequence_Check(pyObj) || PySequence_Length(pyObj) != 2) + return false; + + AutoDecRef item1(PySequence_GetItem(pyObj, 0)); + AutoDecRef item2(PySequence_GetItem(pyObj, 1)); + + if (!Converter::isConvertible(item1) + && !Converter::isConvertible(item2)) { + return false; + } + return true; + } + static PyObject* toPython(void* cppObj) { return toPython(*reinterpret_cast(cppObj)); } + static PyObject* toPython(const StdPair& cppobj) + { + typename StdPair::first_type first(cppobj.first); + typename StdPair::second_type second(cppobj.second); + PyObject* tuple = PyTuple_New(2); + PyTuple_SET_ITEM(tuple, 0, Converter::toPython(first)); + PyTuple_SET_ITEM(tuple, 1, Converter::toPython(second)); + return tuple; + } + static StdPair toCpp(PyObject* pyobj) + { + StdPair result; + AutoDecRef pyFirst(PySequence_GetItem(pyobj, 0)); + AutoDecRef pySecond(PySequence_GetItem(pyobj, 1)); + result.first = Converter::toCpp(pyFirst); + result.second = Converter::toCpp(pySecond); + return result; + } +}; + +template +struct StdMapConverter +{ + static inline bool checkType(PyObject* pyObj) + { + return isConvertible(pyObj); + } + + static inline bool isConvertible(PyObject* pyObj) + { + if (PyObject_TypeCheck(pyObj, SbkType())) + return true; + if ((SbkType() && Object::checkType(pyObj)) || !PyDict_Check(pyObj)) + return false; + + PyObject* key; + PyObject* value; + Py_ssize_t pos = 0; + + while (PyDict_Next(pyObj, &pos, &key, &value)) { + if (!Converter::isConvertible(key) + || !Converter::isConvertible(value)) { + return false; + } + } + return true; + } + + static PyObject* toPython(void* cppObj) { return toPython(*reinterpret_cast(cppObj)); } + static PyObject* toPython(const StdMap& cppobj) + { + PyObject* result = PyDict_New(); + typename StdMap::const_iterator it = cppobj.begin(); + + for (; it != cppobj.end(); ++it) { + PyDict_SetItem(result, + Converter::toPython(it->first), + Converter::toPython(it->second)); + } + + return result; + } + static StdMap toCpp(PyObject* pyobj) + { + StdMap result; + + PyObject* key; + PyObject* value; + Py_ssize_t pos = 0; + + while (PyDict_Next(pyobj, &pos, &key, &value)) { + result.insert(typename StdMap::value_type( + Converter::toCpp(key), + Converter::toCpp(value))); + } + return result; + } +}; + + +// class used to translate python objects to another type +template struct PythonConverter {}; + +} // namespace Shiboken + +#endif // CONVERSIONS_H + diff --git a/sources/shiboken2/libshiboken/debugfreehook.cpp b/sources/shiboken2/libshiboken/debugfreehook.cpp new file mode 100644 index 000000000..f5757a70f --- /dev/null +++ b/sources/shiboken2/libshiboken/debugfreehook.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "debugfreehook.h" +#include "bindingmanager.h" +#include "gilstate.h" + +#if defined(_WIN32) && defined(_DEBUG) +#include +#include +#endif + +#ifdef __GLIBC__ +#include +#endif + +#ifdef __APPLE__ +#include +#include +#include +#endif + +#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK +extern "C" { + +static int testPointerBeingFreed(void *ptr) +{ + // It is an error for a deleted pointer address to still be registered + // in the BindingManager + if (Shiboken::BindingManager::instance().hasWrapper(ptr)) { + Shiboken::GilState state; + + SbkObject *wrapper = Shiboken::BindingManager::instance().retrieveWrapper(ptr); + + fprintf(stderr, "SbkObject still in binding map when deleted: "); + PyObject_Print(reinterpret_cast(wrapper), stderr, 0); + fprintf(stderr, "\n"); + +#ifdef _WIN32 + DebugBreak(); +#else + assert(0); +#endif + return FALSE; + } + + return TRUE; +} + +#if defined(_WIN32) && defined(_DEBUG) +static _CRT_ALLOC_HOOK lastCrtAllocHook; +static int DebugAllocHook(int nAllocType, void *pvData, + size_t nSize, int nBlockUse, long lRequest, + const unsigned char * szFileName, int nLine) +{ + // It is an error for a deleted pointer address to still be registered + // in the BindingManager + if ( nAllocType == _HOOK_FREE) { + if ( !testPointerBeingFreed(pvData) ) { + return 0; + } + } + + if ( lastCrtAllocHook != NULL ) { + return lastCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, + szFileName, nLine); + } + + return 1; +} +#endif // _WIN32 && _DEBUG + +#ifdef __GLIBC__ +static void (*lastFreeHook)(void* ptr, const void* caller); +static void DebugFreeHook(void* ptr, const void* caller) +{ + testPointerBeingFreed(ptr); + + if ( lastFreeHook != NULL ) + lastFreeHook(ptr, caller); +} +#endif // __GLIBC__ + +#ifdef __APPLE__ +static malloc_zone_t lastMallocZone; +static void DebugFreeHook(malloc_zone_t *zone, void *ptr) +{ + testPointerBeingFreed(ptr); + + if ( lastMallocZone.free != NULL ) + lastMallocZone.free(zone, ptr); +} +static void DebugFreeDefiniteSizeHook(malloc_zone_t *zone, void *ptr, size_t size) +{ + testPointerBeingFreed(ptr); + + if ( lastMallocZone.free_definite_size != NULL ) + lastMallocZone.free_definite_size(zone, ptr, size); +} +#endif __APPLE__ + +void debugInstallFreeHook(void) +{ +#if defined(_WIN32) && defined(_DEBUG) + lastCrtAllocHook = _CrtSetAllocHook(DebugAllocHook); +#endif + +#ifdef __GLIBC__ + // __free_hook is not thread safe so it marked as deprecated. Use here + // is hopefully safe and should catch errors in a single threaded program + // and only miss some in a multithreaded program + lastFreeHook = __free_hook; + __free_hook = DebugFreeHook; +#endif + +#ifdef __APPLE__ + malloc_zone_t* zone = malloc_default_zone(); + assert(zone != NULL); + //remove the write protection from the zone struct + if (zone->version >= 8) { + vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ | VM_PROT_WRITE); + } + lastMallocZone = *zone; + zone->free = DebugFreeHook; + zone->free_definite_size = DebugFreeDefiniteSizeHook; + if (zone->version >= 8) { + vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ); + } +#endif +} + +void debugRemoveFreeHook(void) +{ +#if defined(_WIN32) && defined(_DEBUG) + _CrtSetAllocHook(lastCrtAllocHook); +#endif + +#ifdef __GLIBC__ + __free_hook = lastFreeHook; +#endif + +#ifdef __APPLE__ + malloc_zone_t* zone = malloc_default_zone(); + assert(zone != NULL); + //remove the write protection from the zone struct + if (zone->version >= 8) { + vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ | VM_PROT_WRITE); + } + zone->free = lastMallocZone.free; + zone->free_definite_size = lastMallocZone.free_definite_size; + if (zone->version >= 8) { + vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ); + } +#endif +} + +} // extern "C" +#endif // SHIBOKEN_INSTALL_DEBUG_FREE_HOOK diff --git a/sources/shiboken2/libshiboken/debugfreehook.h b/sources/shiboken2/libshiboken/debugfreehook.h new file mode 100644 index 000000000..743d56e4c --- /dev/null +++ b/sources/shiboken2/libshiboken/debugfreehook.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef DEBUGFREEHOOK_H +#define DEBUGFREEHOOK_H + +// These functions enable C library runtime hooks to try to catch cases where +// C++ object addresses remain in hash table of valid wrappers when the address +// is passed to free. The hooks are probably not thread safe and thus +// should only be enabled in single threaded environments + +// To enable the hook, uncomment the following define. +//#define SHIBOKEN_INSTALL_FREE_DEBUG_HOOK + +#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK +extern "C" { + +void debugInstallFreeHook(void); +void debugRemoveFreeHook(void); + +} // extern "C" + +#endif // SHIBOKEN_INSTALL_FREE_DEBUG_HOOK + +#endif // DEBUGFREEHOOK_H diff --git a/sources/shiboken2/libshiboken/gilstate.cpp b/sources/shiboken2/libshiboken/gilstate.cpp new file mode 100644 index 000000000..e7406fdd6 --- /dev/null +++ b/sources/shiboken2/libshiboken/gilstate.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "gilstate.h" + +namespace Shiboken +{ + +GilState::GilState() + : m_locked(false) +{ + if (Py_IsInitialized()) { + m_gstate = PyGILState_Ensure(); + m_locked = true; + } +} + +GilState::~GilState() +{ + release(); +} + +void GilState::release() +{ + if (m_locked && Py_IsInitialized()) { + PyGILState_Release(m_gstate); + m_locked = false; + } +} + +} // namespace Shiboken + diff --git a/sources/shiboken2/libshiboken/gilstate.h b/sources/shiboken2/libshiboken/gilstate.h new file mode 100644 index 000000000..e0f18a814 --- /dev/null +++ b/sources/shiboken2/libshiboken/gilstate.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef GILSTATE_H +#define GILSTATE_H + +#include +#include "sbkpython.h" + +namespace Shiboken +{ + +class LIBSHIBOKEN_API GilState +{ +public: + GilState(); + ~GilState(); + void release(); +private: + PyGILState_STATE m_gstate; + bool m_locked; +}; + +} // namespace Shiboken + +#endif // GILSTATE_H + diff --git a/sources/shiboken2/libshiboken/helper.cpp b/sources/shiboken2/libshiboken/helper.cpp new file mode 100644 index 000000000..9709d0776 --- /dev/null +++ b/sources/shiboken2/libshiboken/helper.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "helper.h" +#include + +namespace Shiboken +{ + +bool sequenceToArgcArgv(PyObject* argList, int* argc, char*** argv, const char* defaultAppName) +{ + if (!PySequence_Check(argList)) + return false; + + if (!defaultAppName) + defaultAppName = "PySideApplication"; + + // Check all items + Shiboken::AutoDecRef args(PySequence_Fast(argList, 0)); + int numArgs = PySequence_Fast_GET_SIZE(argList); + for (int i = 0; i < numArgs; ++i) { + PyObject* item = PySequence_Fast_GET_ITEM(args.object(), i); + if (!PyBytes_Check(item) && !PyUnicode_Check(item)) + return false; + } + + bool hasEmptyArgList = numArgs == 0; + if (hasEmptyArgList) + numArgs = 1; + + *argc = numArgs; + *argv = new char*[*argc]; + + if (hasEmptyArgList) { + // Try to get the script name + PyObject* globals = PyEval_GetGlobals(); + PyObject* appName = PyDict_GetItemString(globals, "__file__"); + (*argv)[0] = strdup(appName ? Shiboken::String::toCString(appName) : defaultAppName); + } else { + for (int i = 0; i < numArgs; ++i) { + PyObject* item = PySequence_Fast_GET_ITEM(args.object(), i); + char* string = 0; + if (Shiboken::String::check(item)) { + string = strdup(Shiboken::String::toCString(item)); + } + (*argv)[i] = string; + } + } + + return true; +} + +int* sequenceToIntArray(PyObject* obj, bool zeroTerminated) +{ + AutoDecRef seq(PySequence_Fast(obj, "Sequence of ints expected")); + if (seq.isNull()) + return 0; + + Py_ssize_t size = PySequence_Fast_GET_SIZE(seq.object()); + int* array = new int[size + (zeroTerminated ? 1 : 0)]; + + for (int i = 0; i < size; i++) { + PyObject* item = PySequence_Fast_GET_ITEM(seq.object(), i); + if (!PyInt_Check(item)) { + PyErr_SetString(PyExc_TypeError, "Sequence of ints expected"); + delete[] array; + return 0; + } else { + array[i] = PyInt_AsLong(item); + } + } + + if (zeroTerminated) + array[size] = 0; + + return array; +} + + +int warning(PyObject* category, int stacklevel, const char* format, ...) +{ + va_list args; + va_start(args, format); +#if _WIN32 + va_list args2 = args; +#else + va_list args2; + va_copy(args2, args); +#endif + + // check the necessary memory + int size = vsnprintf(NULL, 0, format, args) + 1; + char* message = new char[size]; + int result = 0; + if (message) { + // format the message + vsnprintf(message, size, format, args2); + result = PyErr_WarnEx(category, message, stacklevel); + delete [] message; + } + va_end(args2); + va_end(args); + return result; +} + +} // namespace Shiboken diff --git a/sources/shiboken2/libshiboken/helper.h b/sources/shiboken2/libshiboken/helper.h new file mode 100644 index 000000000..f2061b667 --- /dev/null +++ b/sources/shiboken2/libshiboken/helper.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef HELPER_H +#define HELPER_H + +#include "sbkpython.h" +#include "shibokenmacros.h" +#include "conversions.h" +#include "autodecref.h" + +#define SBK_UNUSED(x) (void)x; + +namespace Shiboken +{ + +template +inline PyObject* makeTuple(const A& a) +{ + return PyTuple_Pack(1, AutoDecRef(Converter::toPython(a)).object()); +} + +template +inline PyObject* makeTuple(const A& a, const B& b) +{ + return PyTuple_Pack(2, AutoDecRef(Converter::toPython(a)).object(), + AutoDecRef(Converter::toPython(b)).object()); +} + +template +inline PyObject* makeTuple(const A& a, const B& b, const C& c) +{ + return PyTuple_Pack(3, AutoDecRef(Converter::toPython(a)).object(), + AutoDecRef(Converter::toPython(b)).object(), + AutoDecRef(Converter::toPython(c)).object()); +} + +template +inline PyObject* makeTuple(const A& a, const B& b, const C& c, const D& d) +{ + return PyTuple_Pack(4, AutoDecRef(Converter::toPython(a)).object(), + AutoDecRef(Converter::toPython(b)).object(), + AutoDecRef(Converter::toPython(c)).object(), + AutoDecRef(Converter::toPython(d)).object()); +} + +template +inline PyObject* makeTuple(const A& a, const B& b, const C& c, const D& d, const E& e) +{ + return PyTuple_Pack(5, AutoDecRef(Converter::toPython(a)).object(), + AutoDecRef(Converter::toPython(b)).object(), + AutoDecRef(Converter::toPython(c)).object(), + AutoDecRef(Converter::toPython(d)).object(), + AutoDecRef(Converter::toPython(e)).object()); +} + +/** +* It transforms a python sequence into two C variables, argc and argv. +* This function tries to find the application (script) name and put it into argv[0], if +* the application name can't be guessed, defaultAppName will be used. +* +* No memory is allocated is an error occur. +* +* \note argc must be a valid address. +* \note The argv array is allocated using new operator and each item is allocated using malloc. +* \returns True on sucess, false otherwise. +*/ +LIBSHIBOKEN_API bool sequenceToArgcArgv(PyObject* argList, int* argc, char*** argv, const char* defaultAppName = 0); + +/** + * Convert a python sequence into a heap-allocated array of ints. + * + * \returns The newly allocated array or NULL in case of error or empty sequence. Check with PyErr_Occurred + * if it was successfull. + */ +LIBSHIBOKEN_API int* sequenceToIntArray(PyObject* obj, bool zeroTerminated = false); + +/** + * Creates and automatically deallocates C++ arrays. + */ +template +class AutoArrayPointer +{ + public: + AutoArrayPointer(int size) { data = new T[size]; } + T& operator[](int pos) { return data[pos]; } + operator T*() const { return data; } + ~AutoArrayPointer() { delete[] data; } + private: + T* data; +}; + +/** + * An utility function used to call PyErr_WarnEx with a formatted message. + */ +LIBSHIBOKEN_API int warning(PyObject* category, int stacklevel, const char* format, ...); + +} // namespace Shiboken + +#endif // HELPER_H diff --git a/sources/shiboken2/libshiboken/python25compat.h b/sources/shiboken2/libshiboken/python25compat.h new file mode 100644 index 000000000..71c88d86a --- /dev/null +++ b/sources/shiboken2/libshiboken/python25compat.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef PYTHON25COMPAT_H +#define PYTHON25COMPAT_H +#include +#include + +/* + *The #defines below were taken from Cython-generated code to allow shiboken to be used with python2.5. + * Maybe not all of these defines are useful to us, time will tell which ones are really needed or not. + */ + +#if PY_VERSION_HEX < 0x02060000 +#define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt) +#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) +#define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size) +#define PyVarObject_HEAD_INIT(type, size) \ + PyObject_HEAD_INIT(type) size, +#define PyType_Modified(t) + +typedef struct { + void *buf; + PyObject *obj; + Py_ssize_t len; + Py_ssize_t itemsize; + int readonly; + int ndim; + char *format; + Py_ssize_t *shape; + Py_ssize_t *strides; + Py_ssize_t *suboffsets; + void *internal; +} Py_buffer; + +#define PyBUF_SIMPLE 0 +#define PyBUF_WRITABLE 0x0001 +#define PyBUF_LOCK 0x0002 +#define PyBUF_FORMAT 0x0004 +#define PyBUF_ND 0x0008 +#define PyBUF_STRIDES (0x0010 | PyBUF_ND) +#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) +#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) +#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) +#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) + +#define PyBytes_Check PyString_Check +#define PyBytes_FromString PyString_FromString +#define PyBytes_FromFormat PyString_FromFormat +#define PyBytes_FromStringAndSize PyString_FromStringAndSize +#define PyBytes_GET_SIZE PyString_GET_SIZE +#define PyBytes_AS_STRING PyString_AS_STRING +#define PyBytes_AsString PyString_AsString +#define PyBytes_Concat PyString_Concat +#define PyBytes_Size PyString_Size + +inline PyObject* PyUnicode_FromString(const char* s) +{ + std::size_t len = std::strlen(s); + return PyUnicode_DecodeUTF8(s, len, 0); +} + +#define PyLong_FromSize_t _PyLong_FromSize_t +#define PyLong_AsSsize_t _PyLong_AsSsize_t + +#endif + +#endif diff --git a/sources/shiboken2/libshiboken/sbkconverter.cpp b/sources/shiboken2/libshiboken/sbkconverter.cpp new file mode 100644 index 000000000..b22b33705 --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkconverter.cpp @@ -0,0 +1,571 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "sbkconverter.h" +#include "sbkconverter_p.h" +#include "basewrapper_p.h" +#include "autodecref.h" +#include "sbkdbg.h" +#include "helper.h" + +#include + +static SbkConverter** PrimitiveTypeConverters; + +typedef std::unordered_map ConvertersMap; +static ConvertersMap converters; + +namespace Shiboken { +namespace Conversions { + +void init() +{ + static SbkConverter* primitiveTypeConverters[] = { + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter(), + Primitive::createConverter() + }; + PrimitiveTypeConverters = primitiveTypeConverters; + + assert(converters.empty()); + converters["PY_LONG_LONG"] = primitiveTypeConverters[SBK_PY_LONG_LONG_IDX]; + converters["bool"] = primitiveTypeConverters[SBK_BOOL_IDX_1]; + converters["char"] = primitiveTypeConverters[SBK_CHAR_IDX]; + converters["const char *"] = primitiveTypeConverters[SBK_CONSTCHARPTR_IDX]; + converters["double"] = primitiveTypeConverters[SBK_DOUBLE_IDX]; + converters["float"] = primitiveTypeConverters[SBK_FLOAT_IDX]; + converters["int"] = primitiveTypeConverters[SBK_INT_IDX]; + converters["long"] = primitiveTypeConverters[SBK_LONG_IDX]; + converters["short"] = primitiveTypeConverters[SBK_SHORT_IDX]; + converters["signed char"] = primitiveTypeConverters[SBK_SIGNEDCHAR_IDX]; + converters["std::string"] = primitiveTypeConverters[SBK_STD_STRING_IDX]; + converters["unsigned PY_LONG_LONG"] = primitiveTypeConverters[SBK_UNSIGNEDPY_LONG_LONG_IDX]; + converters["unsigned char"] = primitiveTypeConverters[SBK_UNSIGNEDCHAR_IDX]; + converters["unsigned int"] = primitiveTypeConverters[SBK_UNSIGNEDINT_IDX]; + converters["unsigned long"] = primitiveTypeConverters[SBK_UNSIGNEDLONG_IDX]; + converters["unsigned short"] = primitiveTypeConverters[SBK_UNSIGNEDSHORT_IDX]; + converters["void*"] = primitiveTypeConverters[SBK_VOIDPTR_IDX]; +} + +static SbkConverter* createConverterObject(PyTypeObject* type, + PythonToCppFunc toCppPointerConvFunc, + IsConvertibleToCppFunc toCppPointerCheckFunc, + CppToPythonFunc pointerToPythonFunc, + CppToPythonFunc copyToPythonFunc) +{ + SbkConverter* converter = new SbkConverter; + converter->pythonType = type; + + converter->pointerToPython = pointerToPythonFunc; + converter->copyToPython = copyToPythonFunc; + + if (toCppPointerCheckFunc && toCppPointerConvFunc) + converter->toCppPointerConversion = std::make_pair(toCppPointerCheckFunc, toCppPointerConvFunc); + converter->toCppConversions.clear(); + + return converter; +} + +SbkConverter* createConverter(SbkObjectType* type, + PythonToCppFunc toCppPointerConvFunc, + IsConvertibleToCppFunc toCppPointerCheckFunc, + CppToPythonFunc pointerToPythonFunc, + CppToPythonFunc copyToPythonFunc) +{ + SbkConverter *converter = + createConverterObject(reinterpret_cast(type), + toCppPointerConvFunc, toCppPointerCheckFunc, + pointerToPythonFunc, copyToPythonFunc); + type->d->converter = converter; + return converter; +} + +SbkConverter* createConverter(PyTypeObject* type, CppToPythonFunc toPythonFunc) +{ + return createConverterObject(type, 0, 0, 0, toPythonFunc); +} + +void deleteConverter(SbkConverter* converter) +{ + if (converter) { + converter->toCppConversions.clear(); + delete converter; + } +} + +void setCppPointerToPythonFunction(SbkConverter* converter, CppToPythonFunc pointerToPythonFunc) +{ + converter->pointerToPython = pointerToPythonFunc; +} + +void setPythonToCppPointerFunctions(SbkConverter* converter, + PythonToCppFunc toCppPointerConvFunc, + IsConvertibleToCppFunc toCppPointerCheckFunc) +{ + converter->toCppPointerConversion = std::make_pair(toCppPointerCheckFunc, toCppPointerConvFunc); +} + +void addPythonToCppValueConversion(SbkConverter* converter, + PythonToCppFunc pythonToCppFunc, + IsConvertibleToCppFunc isConvertibleToCppFunc) +{ + converter->toCppConversions.push_back(std::make_pair(isConvertibleToCppFunc, pythonToCppFunc)); +} +void addPythonToCppValueConversion(SbkObjectType* type, + PythonToCppFunc pythonToCppFunc, + IsConvertibleToCppFunc isConvertibleToCppFunc) +{ + addPythonToCppValueConversion(type->d->converter, pythonToCppFunc, isConvertibleToCppFunc); +} + +PyObject* pointerToPython(const SbkObjectType *type, const void *cppIn) +{ + return pointerToPython(type->d->converter, cppIn); +} + +PyObject* pointerToPython(const SbkConverter *converter, const void *cppIn) +{ + assert(converter); + if (!cppIn) + Py_RETURN_NONE; + if (!converter->pointerToPython) { + warning(PyExc_RuntimeWarning, 0, "pointerToPython(): SbkConverter::pointerToPython is null for \"%s\".", + converter->pythonType->tp_name); + Py_RETURN_NONE; + } + return converter->pointerToPython(cppIn); +} + +PyObject* referenceToPython(const SbkObjectType *type, const void *cppIn) +{ + return referenceToPython(type->d->converter, cppIn); +} + +PyObject* referenceToPython(const SbkConverter *converter, const void *cppIn) +{ + assert(cppIn); + + PyObject *pyOut = reinterpret_cast(BindingManager::instance().retrieveWrapper(cppIn)); + if (pyOut) { + Py_INCREF(pyOut); + return pyOut; + } + if (!converter->pointerToPython) { + warning(PyExc_RuntimeWarning, 0, "referenceToPython(): SbkConverter::pointerToPython is null for \"%s\".", + converter->pythonType->tp_name); + Py_RETURN_NONE; + } + return converter->pointerToPython(cppIn); +} + +static inline PyObject* CopyCppToPython(const SbkConverter *converter, const void *cppIn) +{ + if (!cppIn) + Py_RETURN_NONE; + if (!converter->copyToPython) { + warning(PyExc_RuntimeWarning, 0, "CopyCppToPython(): SbkConverter::copyToPython is null for \"%s\".", + converter->pythonType->tp_name); + Py_RETURN_NONE; + } + return converter->copyToPython(cppIn); +} +PyObject* copyToPython(const SbkObjectType *type, const void *cppIn) +{ + return CopyCppToPython(type->d->converter, cppIn); +} +PyObject* copyToPython(const SbkConverter *converter, const void *cppIn) +{ + return CopyCppToPython(converter, cppIn); +} + +PythonToCppFunc isPythonToCppPointerConvertible(const SbkObjectType *type, PyObject *pyIn) +{ + assert(pyIn); + return type->d->converter->toCppPointerConversion.first(pyIn); +} + +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))) + return toCppFunc; + } + return 0; +} +PythonToCppFunc isPythonToCppValueConvertible(const SbkObjectType *type, PyObject *pyIn) +{ + return IsPythonToCppConvertible(type->d->converter, pyIn); +} +PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn) +{ + return IsPythonToCppConvertible(converter, pyIn); +} + +PythonToCppFunc isPythonToCppReferenceConvertible(const SbkObjectType *type, PyObject *pyIn) +{ + if (pyIn != Py_None) { + PythonToCppFunc toCpp = isPythonToCppPointerConvertible(type, pyIn); + if (toCpp) + return toCpp; + } + return isPythonToCppValueConvertible(type, pyIn); +} + +void nonePythonToCppNullPtr(PyObject*, void* cppOut) +{ + assert(cppOut); + *((void**)cppOut) = 0; +} + +void* cppPointer(PyTypeObject* desiredType, SbkObject* pyIn) +{ + assert(pyIn); + if (!ObjectType::checkType(desiredType)) + return pyIn; + SbkObjectType *inType = reinterpret_cast(Py_TYPE(pyIn)); + if (ObjectType::hasCast(inType)) + return ObjectType::cast(inType, pyIn, desiredType); + return Object::cppPointer(pyIn, desiredType); +} + +void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut) +{ + assert(type); + assert(pyIn); + assert(cppOut); + *reinterpret_cast(cppOut) = pyIn == Py_None + ? 0 + : cppPointer(reinterpret_cast(type), reinterpret_cast(pyIn)); +} + +void pythonToCppPointer(const SbkConverter *converter, PyObject *pyIn, void *cppOut) +{ + assert(converter); + assert(pyIn); + assert(cppOut); + *reinterpret_cast(cppOut) = pyIn == Py_None + ? 0 + : cppPointer(reinterpret_cast(converter->pythonType), reinterpret_cast(pyIn)); +} + +static void _pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut) +{ + assert(converter); + assert(pyIn); + assert(cppOut); + PythonToCppFunc toCpp = IsPythonToCppConvertible(converter, pyIn); + if (toCpp) + toCpp(pyIn, cppOut); +} + +void pythonToCppCopy(const SbkObjectType *type, PyObject *pyIn, void *cppOut) +{ + assert(type); + _pythonToCppCopy(type->d->converter, pyIn, cppOut); +} + +void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut) +{ + _pythonToCppCopy(converter, pyIn, cppOut); +} + +bool isImplicitConversion(const SbkObjectType *type, PythonToCppFunc toCppFunc) +{ + // This is the Object Type or Value Type conversion that only + // retrieves the C++ pointer held in the Python wrapper. + if (toCppFunc == type->d->converter->toCppPointerConversion.second) + return false; + + // Object Types doesn't have any kind of value conversion, + // only C++ pointer retrieval. + if (type->d->converter->toCppConversions.empty()) + return false; + + // The first conversion of the non-pointer conversion list is + // a Value Type's copy to C++ function, which is not an implicit + // conversion. + // Otherwise it must be one of the implicit conversions. + // Note that we don't check if the Python to C++ conversion is in + // the list of the type's conversions, for it is expected that the + // caller knows what he's doing. + ToCppConversionList::iterator conv = type->d->converter->toCppConversions.begin(); + return toCppFunc != (*conv).second; +} + +void registerConverterName(SbkConverter* converter , const char* typeName) +{ + ConvertersMap::iterator iter = converters.find(typeName); + if (iter == converters.end()) + converters.insert(std::make_pair(typeName, converter)); +} + +SbkConverter* getConverter(const char* typeName) +{ + ConvertersMap::const_iterator it = converters.find(typeName); + if (it != converters.end()) + return it->second; + if (Py_VerboseFlag > 0) + SbkDbg() << "Can't find type resolver for type '" << typeName << "'."; + return 0; +} + +SbkConverter* primitiveTypeConverter(int index) +{ + return PrimitiveTypeConverters[index]; +} + +bool checkSequenceTypes(PyTypeObject* type, PyObject* pyIn) +{ + assert(type); + assert(pyIn); + if (!PySequence_Check(pyIn)) + return false; + const Py_ssize_t size = PySequence_Size(pyIn); + for (Py_ssize_t i = 0; i < size; ++i) { + if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, i)), type)) + return false; + } + return true; +} +bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn) +{ + assert(converter); + assert(pyIn); + if (!PySequence_Check(pyIn)) + return false; + const Py_ssize_t size = PySequence_Size(pyIn); + for (Py_ssize_t i = 0; i < size; ++i) { + if (!isPythonToCppConvertible(converter, AutoDecRef(PySequence_GetItem(pyIn, i)))) + return false; + } + return true; +} +bool convertibleSequenceTypes(const SbkObjectType *type, PyObject *pyIn) +{ + assert(type); + return convertibleSequenceTypes(type->d->converter, pyIn); +} + +bool checkPairTypes(PyTypeObject* firstType, PyTypeObject* secondType, PyObject* pyIn) +{ + assert(firstType); + assert(secondType); + assert(pyIn); + if (!PySequence_Check(pyIn)) + return false; + if (PySequence_Size(pyIn) != 2) + return false; + if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, 0)), firstType)) + return false; + if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, 1)), secondType)) + return false; + return true; +} +bool convertiblePairTypes(const SbkConverter *firstConverter, bool firstCheckExact, + const SbkConverter *secondConverter, bool secondCheckExact, + PyObject *pyIn) +{ + assert(firstConverter); + assert(secondConverter); + assert(pyIn); + if (!PySequence_Check(pyIn)) + return false; + if (PySequence_Size(pyIn) != 2) + return false; + AutoDecRef firstItem(PySequence_GetItem(pyIn, 0)); + if (firstCheckExact) { + if (!PyObject_TypeCheck(firstItem, firstConverter->pythonType)) + return false; + } else if (!isPythonToCppConvertible(firstConverter, firstItem)) { + return false; + } + AutoDecRef secondItem(PySequence_GetItem(pyIn, 1)); + if (secondCheckExact) { + if (!PyObject_TypeCheck(secondItem, secondConverter->pythonType)) + return false; + } else if (!isPythonToCppConvertible(secondConverter, secondItem)) { + return false; + } + + return true; +} + +bool checkDictTypes(PyTypeObject* keyType, PyTypeObject* valueType, PyObject* pyIn) +{ + assert(keyType); + assert(valueType); + assert(pyIn); + if (!PyDict_Check(pyIn)) + return false; + + PyObject* key; + PyObject* value; + Py_ssize_t pos = 0; + while (PyDict_Next(pyIn, &pos, &key, &value)) { + if (!PyObject_TypeCheck(key, keyType)) + return false; + if (!PyObject_TypeCheck(value, valueType)) + return false; + } + return true; +} + +bool convertibleDictTypes(const SbkConverter * keyConverter, bool keyCheckExact, const SbkConverter *valueConverter, + bool valueCheckExact, PyObject *pyIn) +{ + assert(keyConverter); + assert(valueConverter); + assert(pyIn); + if (!PyDict_Check(pyIn)) + return false; + PyObject* key; + PyObject* value; + Py_ssize_t pos = 0; + while (PyDict_Next(pyIn, &pos, &key, &value)) { + if (keyCheckExact) { + if (!PyObject_TypeCheck(key, keyConverter->pythonType)) + return false; + } else if (!isPythonToCppConvertible(keyConverter, key)) { + return false; + } + if (valueCheckExact) { + if (!PyObject_TypeCheck(value, valueConverter->pythonType)) + return false; + } else if (!isPythonToCppConvertible(valueConverter, value)) { + return false; + } + } + return true; +} + +PyTypeObject* getPythonTypeObject(const SbkConverter *converter) +{ + if (converter) + return converter->pythonType; + return 0; +} + +PyTypeObject* getPythonTypeObject(const char* typeName) +{ + return getPythonTypeObject(getConverter(typeName)); +} + +bool pythonTypeIsValueType(const SbkConverter *converter) +{ + assert(converter); + return converter->pointerToPython && converter->copyToPython; +} + +bool pythonTypeIsObjectType(const SbkConverter *converter) +{ + return converter->pointerToPython && !converter->copyToPython; +} + +bool pythonTypeIsWrapperType(const SbkConverter *converter) +{ + return converter->pointerToPython; +} + +SpecificConverter::SpecificConverter(const char* typeName) + : m_type(InvalidConversion) +{ + m_converter = getConverter(typeName); + if (!m_converter) + return; + const Py_ssize_t len = strlen(typeName); + char lastChar = typeName[len -1]; + if (lastChar == '&') { + m_type = ReferenceConversion; + } else if (lastChar == '*' || pythonTypeIsObjectType(m_converter)) { + m_type = PointerConversion; + } else { + m_type = CopyConversion; + } +} + +PyObject* SpecificConverter::toPython(const void* cppIn) +{ + switch (m_type) { + case CopyConversion: + return copyToPython(m_converter, cppIn); + case PointerConversion: + return pointerToPython(m_converter, *((const void**)cppIn)); + case ReferenceConversion: + return referenceToPython(m_converter, cppIn); + default: + PyErr_SetString(PyExc_RuntimeError, "tried to use invalid converter in 'C++ to Python' conversion"); + } + return 0; +} + +void SpecificConverter::toCpp(PyObject* pyIn, void* cppOut) +{ + switch (m_type) { + case CopyConversion: + pythonToCppCopy(m_converter, pyIn, cppOut); + break; + case PointerConversion: + pythonToCppPointer(m_converter, pyIn, cppOut); + break; + case ReferenceConversion: + pythonToCppPointer(m_converter, pyIn, &cppOut); + break; + default: + PyErr_SetString(PyExc_RuntimeError, "tried to use invalid converter in 'Python to C++' conversion"); + } +} + +} } // namespace Shiboken::Conversions diff --git a/sources/shiboken2/libshiboken/sbkconverter.h b/sources/shiboken2/libshiboken/sbkconverter.h new file mode 100644 index 000000000..7489b930d --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkconverter.h @@ -0,0 +1,367 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SBK_CONVERTER_H +#define SBK_CONVERTER_H + +#include "sbkpython.h" +#include "shibokenmacros.h" + +#include +#include + +struct SbkObject; +struct SbkObjectType; + +/** + * This is a convenience macro identical to Python's PyObject_TypeCheck, + * except that the arguments have swapped places, for the great convenience + * of generator. + */ +#define SbkObject_TypeCheck(tp, ob) \ + (Py_TYPE(ob) == (tp) || PyType_IsSubtype(Py_TYPE(ob), (tp))) + +extern "C" +{ + +/** + * SbkConverter is used to perform type conversions from C++ + * to Python and vice-versa;.and it is also used for type checking. + * SbkConverter is a private structure that must be accessed + * using the functions provided by the converter API. + */ +struct SbkConverter; + +/** + * Given a void pointer to a C++ object, this function must return + * the proper Python object. It may be either an existing wrapper + * for the C++ object, or a newly create one. Or even the Python + * equivalent of the C++ value passed in the argument. + * + * C++ -> Python + */ +typedef PyObject* (*CppToPythonFunc)(const void*); + +/** + * This function converts a Python object to a C++ value, it may be + * a pointer, value, class, container or primitive type, passed via + * a void pointer, that will be cast properly inside the function. + * This function is usually returned by an IsConvertibleToCppFunc + * function, or obtained knowing the type of the Python object input, + * thus it will not check the Python object type, and will expect + * the void pointer to be pointing to a proper variable. + * + * Python -> C++ + */ +typedef void (*PythonToCppFunc)(PyObject*,void*); + +/** + * Checks if the Python object passed in the argument is convertible to a + * C++ type defined inside the function, it returns the converter function + * that will transform a Python argument into a C++ value. + * It returns NULL if the Python object is not convertible to the C++ type + * that the function represents. + * + * Python -> C++ ? + */ +typedef PythonToCppFunc (*IsConvertibleToCppFunc)(PyObject*); + +} // extern "C" + +namespace Shiboken { +namespace Conversions { + + +class LIBSHIBOKEN_API SpecificConverter +{ +public: + enum Type + { + InvalidConversion, + CopyConversion, + PointerConversion, + ReferenceConversion + }; + + explicit SpecificConverter(const char* typeName); + + inline SbkConverter* converter() { return m_converter; } + inline operator SbkConverter*() const { return m_converter; } + + inline bool isValid() { return m_type != InvalidConversion; } + inline operator bool() const { return m_type != InvalidConversion; } + + inline Type conversionType() { return m_type; } + + PyObject* toPython(const void* cppIn); + void toCpp(PyObject* pyIn, void* cppOut); +private: + SbkConverter* m_converter; + Type m_type; +}; + + +/** + * Creates a converter for a wrapper type. + * \param type A Shiboken.ObjectType that will receive the new converter. + * \param toCppPointerConvFunc Function to retrieve the C++ pointer held by a Python wrapper. + * \param toCppPointerCheckFunc Check and return the retriever function of the C++ pointer held by a Python wrapper. + * \param pointerToPythonFunc Function to convert a C++ object to a Python \p type wrapper, keeping their identity. + * \param copyToPythonFunc Function to convert a C++ object to a Python \p type, copying the object. + * \returns The new converter referred by the wrapper \p type. + */ +LIBSHIBOKEN_API SbkConverter* createConverter(SbkObjectType* type, + PythonToCppFunc toCppPointerConvFunc, + IsConvertibleToCppFunc toCppPointerCheckFunc, + CppToPythonFunc pointerToPythonFunc, + CppToPythonFunc copyToPythonFunc = 0); + +/** + * Creates a converter for a non wrapper type (primitive or container type). + * \param type Python type representing to the new converter. + * \param toPythonFunc Function to convert a C++ object to a Python \p type. + * \returns A new type converter. + */ +LIBSHIBOKEN_API SbkConverter* createConverter(PyTypeObject* type, CppToPythonFunc toPythonFunc); + +LIBSHIBOKEN_API void deleteConverter(SbkConverter* converter); + +/// Sets the Python object to C++ pointer conversion function. +LIBSHIBOKEN_API void setCppPointerToPythonFunction(SbkConverter* converter, CppToPythonFunc pointerToPythonFunc); + +/// Sets the C++ pointer to Python object conversion functions. +LIBSHIBOKEN_API void setPythonToCppPointerFunctions(SbkConverter* converter, + PythonToCppFunc toCppPointerConvFunc, + IsConvertibleToCppFunc toCppPointerCheckFunc); + +/** + * Adds a new conversion of a Python object to a C++ value. + * This is used in copy and implicit conversions. + */ +LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkConverter* converter, + PythonToCppFunc pythonToCppFunc, + IsConvertibleToCppFunc isConvertibleToCppFunc); +LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkObjectType* type, + PythonToCppFunc pythonToCppFunc, + IsConvertibleToCppFunc isConvertibleToCppFunc); + +// C++ -> Python --------------------------------------------------------------------------- + +/** + * Retrieves the Python wrapper object for the given \p cppIn C++ pointer object. + * This function is used only for Value and Object Types. + * Example usage: + * TYPE* var; + * PyObject* pyVar = pointerToPython(SBKTYPE, &var); + */ +LIBSHIBOKEN_API PyObject* pointerToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* pointerToPython(const SbkConverter *converter, const void *cppIn); + +/** + * For the given \p cppIn C++ reference it returns the Python wrapper object, + * always for Object Types, and when they already exist for reference types; + * for when the latter doesn't have an existing wrapper type, the C++ object + * is copied to Python. + * Example usage: + * TYPE& var = SOMETHING; + * PyObject* pyVar = referenceToPython(SBKTYPE, &var); + */ +LIBSHIBOKEN_API PyObject* referenceToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* referenceToPython(const SbkConverter *converter, const void *cppIn); + +/** + * Retrieves the Python wrapper object for the given C++ value pointed by \p cppIn. + * This function is used only for Value Types. + * Example usage: + * TYPE var; + * PyObject* pyVar = copyToPython(SBKTYPE, &var); + */ +LIBSHIBOKEN_API PyObject* copyToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* copyToPython(const SbkConverter *converter, const void *cppIn); + +// Python -> C++ --------------------------------------------------------------------------- + +/** + * Returns a Python to C++ conversion function if the Python object is convertible to a C++ pointer. + * It returns NULL if the Python object is not convertible to \p type. + */ +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(const SbkObjectType *type, PyObject *pyIn); + +/** + * Returns a Python to C++ conversion function if the Python object is convertible to a C++ value. + * The resulting converter function will create a copy of the Python object in C++, or implicitly + * convert the object to the expected \p type. + * It returns NULL if the Python object is not convertible to \p type. + */ +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(const SbkObjectType *type, PyObject *pyIn); + +/** + * Returns a Python to C++ conversion function if the Python object is convertible to a C++ reference. + * The resulting converter function will return the underlying C++ object held by the Python wrapper, + * or a new C++ value if it must be a implicit conversion. + * It returns NULL if the Python object is not convertible to \p type. + */ +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(const SbkObjectType *type, PyObject *pyIn); + +/// This is the same as isPythonToCppValueConvertible function. +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn); + +/** + * Returns the C++ pointer for the \p pyIn object cast to the type passed via \p desiredType. + * It differs from Shiboken::Object::cppPointer because it casts the pointer to a proper + * memory offset depending on the desired type. + */ +LIBSHIBOKEN_API void* cppPointer(PyTypeObject* desiredType, SbkObject* pyIn); + +/// Converts a Python object \p pyIn to C++ and stores the result in the C++ pointer passed in \p cppOut. +LIBSHIBOKEN_API void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut); +LIBSHIBOKEN_API void pythonToCppPointer(const SbkConverter *converter, PyObject *pyIn, void *cppOut); + +/// Converts a Python object \p pyIn to C++, and copies the result in the C++ variable passed in \p cppOut. +LIBSHIBOKEN_API void pythonToCppCopy(const SbkObjectType *type, PyObject *pyIn, void *cppOut); +LIBSHIBOKEN_API void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut); + +/** + * Helper function returned by generated convertible checking functions + * that returns a C++ NULL when the input Python object is None. + */ +LIBSHIBOKEN_API void nonePythonToCppNullPtr(PyObject*, void* cppOut); + +/** + * Returns true if the \p toCpp function passed is an implicit conversion of Python \p type. + * It is used when C++ expects a reference argument, so it may be the same object received + * from Python, or another created through implicit conversion. + */ +LIBSHIBOKEN_API bool isImplicitConversion(const SbkObjectType *type, PythonToCppFunc toCpp); + +/// Registers a converter with a type name that may be used to retrieve the converter. +LIBSHIBOKEN_API void registerConverterName(SbkConverter* converter, const char* typeName); + +/// Returns the converter for a given type name, or NULL if it wasn't registered before. +LIBSHIBOKEN_API SbkConverter* getConverter(const char* typeName); + +/// Returns the converter for a primitive type. +LIBSHIBOKEN_API SbkConverter* primitiveTypeConverter(int index); + +/// Returns true if a Python sequence is comprised of objects of the given \p type. +LIBSHIBOKEN_API bool checkSequenceTypes(PyTypeObject* type, PyObject* pyIn); + +/// Returns true if a Python sequence is comprised of objects of a type convertible to the one represented by the given \p converter. +LIBSHIBOKEN_API bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn); + +/// Returns true if a Python sequence is comprised of objects of a type convertible to \p type. +LIBSHIBOKEN_API bool convertibleSequenceTypes(const SbkObjectType *type, PyObject *pyIn); + +/// Returns true if a Python sequence can be converted to a C++ pair. +LIBSHIBOKEN_API bool checkPairTypes(PyTypeObject* firstType, PyTypeObject* secondType, PyObject* pyIn); + +/// Returns true if a Python sequence can be converted to a C++ pair. +LIBSHIBOKEN_API bool convertiblePairTypes(const SbkConverter *firstConverter, bool firstCheckExact, + const SbkConverter *secondConverter, bool secondCheckExact, + PyObject *pyIn); + +/// Returns true if a Python dictionary can be converted to a C++ hash or map. +LIBSHIBOKEN_API bool checkDictTypes(PyTypeObject* keyType, PyTypeObject* valueType, PyObject* pyIn); + +/// Returns true if a Python dictionary can be converted to a C++ hash or map. +LIBSHIBOKEN_API bool convertibleDictTypes(const SbkConverter *keyConverter, bool keyCheckExact, + const SbkConverter *valueConverter, bool valueCheckExact, + PyObject *pyIn); + +/// Returns the Python type object associated with the given \p converter. +LIBSHIBOKEN_API PyTypeObject* getPythonTypeObject(const SbkConverter *converter); + +/// Returns the Python type object for the given \p typeName. +LIBSHIBOKEN_API PyTypeObject* getPythonTypeObject(const char* typeName); + +/// Returns true if the Python type associated with the converter is a value type. +LIBSHIBOKEN_API bool pythonTypeIsValueType(const SbkConverter *converter); + +/// Returns true if the Python type associated with the converter is an object type. +LIBSHIBOKEN_API bool pythonTypeIsObjectType(const SbkConverter *converter); + +/// Returns true if the Python type associated with the converter is a wrapper type. +LIBSHIBOKEN_API bool pythonTypeIsWrapperType(const SbkConverter *converter); + +#define SBK_PY_LONG_LONG_IDX 0 +// Qt5: name collision in QtCore after QBool is replaced by bool +#define SBK_BOOL_IDX_1 1 +#define SBK_CHAR_IDX 2 +#define SBK_CONSTCHARPTR_IDX 3 +#define SBK_DOUBLE_IDX 4 +#define SBK_FLOAT_IDX 5 +#define SBK_INT_IDX 6 +#define SBK_SIGNEDINT_IDX 6 +#define SBK_LONG_IDX 7 +#define SBK_SHORT_IDX 8 +#define SBK_SIGNEDCHAR_IDX 9 +#define SBK_STD_STRING_IDX 10 +#define SBK_UNSIGNEDPY_LONG_LONG_IDX 11 +#define SBK_UNSIGNEDCHAR_IDX 12 +#define SBK_UNSIGNEDINT_IDX 13 +#define SBK_UNSIGNEDLONG_IDX 14 +#define SBK_UNSIGNEDSHORT_IDX 15 +#define SBK_VOIDPTR_IDX 16 + +template SbkConverter* PrimitiveTypeConverter() { return 0; } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_PY_LONG_LONG_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_BOOL_IDX_1); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_CHAR_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_CONSTCHARPTR_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_DOUBLE_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_FLOAT_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_INT_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_LONG_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_SHORT_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_SIGNEDCHAR_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_STD_STRING_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_UNSIGNEDPY_LONG_LONG_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_UNSIGNEDCHAR_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_UNSIGNEDINT_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_UNSIGNEDLONG_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_UNSIGNEDSHORT_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter() { return primitiveTypeConverter(SBK_VOIDPTR_IDX); } + +} } // namespace Shiboken::Conversions + +struct _SbkGenericType { PyHeapTypeObject super; SbkConverter** converter; }; +#define SBK_CONVERTER(pyType) (*reinterpret_cast<_SbkGenericType*>(pyType)->converter) + + +#endif // SBK_CONVERTER_H diff --git a/sources/shiboken2/libshiboken/sbkconverter_p.h b/sources/shiboken2/libshiboken/sbkconverter_p.h new file mode 100644 index 000000000..b38561780 --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkconverter_p.h @@ -0,0 +1,574 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SBK_CONVERTER_P_H +#define SBK_CONVERTER_P_H + +#include "sbkpython.h" +#include "sbkconverter.h" +#include "sbkstring.h" +#include +#include +#include +#include +#include + +#include "sbkdbg.h" + +extern "C" +{ + +typedef std::pair ToCppConversion; +typedef std::list ToCppConversionList; + +/** + * \internal + * Private structure of SbkConverter. + */ +struct SbkConverter +{ + /** + * Python type associated with this converter. If the type is a Shiboken + * wrapper, then it must be a SbkObjectType; otherwise it will be the + * Python type to which the C++ value will be converted (note that the + * C++ type could be produced from various Python types). + */ + PyTypeObject* pythonType; + /** + * This function converts a C++ object to a Python object of the type + * indicated in pythonType. The identity of the C++ object is kept, + * because it looks for an already existing Python wrapper associated + * with the C++ instance. + * It is used to convert C++ pointers and references to Python objects. + */ + CppToPythonFunc pointerToPython; + /** + * This function converts a C++ object to a Python object of the type + * indicated in pythonType. The identity of the object is not kept, + * because a new instance of the C++ object is created. + * It is used to convert objects passed by value, or reference, if said + * reference can't be traced to an object that already has a Python + * wrapper assigned for it. + */ + CppToPythonFunc copyToPython; + /** + * This is a special case of a Python to C++ conversion. It returns + * the underlying C++ pointer of a Python wrapper passed as parameter + * or NULL if the Python object is a None value. + * It comes separated from the other toCppConversions because if you + * have a Python object representing a Value Type the type checking + * for both ValueType and ValueType* would be the same, thus the first + * check would be true and the second would never be reached. + */ + ToCppConversion toCppPointerConversion; + /** + * This is a list of type checking functions that return the + * proper Python to C++ conversion function, for the given Python + * object. + * For Object Types, that never have implicit conversions, this + * list is always empty. + */ + ToCppConversionList toCppConversions; +}; + +} // extern "C" + +template +struct OverFlowCheckerBase { + static void formatOverFlowMessage(const MaxLimitType& value, + const std::string *valueAsString = 0) + { + std::ostringstream str; + str << "libshiboken: Overflow: Value "; + if (valueAsString != 0 && !valueAsString->empty()) + str << *valueAsString; + else + str << value; + str << " exceeds limits of type " + << " [" << (isSigned ? "signed" : "unsigned") + << "] \"" << typeid(T).name() + << "\" (" << sizeof(T) << "bytes)."; + const std::string message = str.str(); + PyErr_WarnEx(PyExc_RuntimeWarning, message.c_str(), 0); + } + + // Checks if an overflow occurred inside Python code. + // Precondition: use after calls like PyLong_AsLongLong or PyLong_AsUnsignedLongLong. + // Postcondition: if error ocurred, sets the string reference to the string representation of + // the passed value. + static bool checkForInternalPyOverflow(PyObject *pyIn, std::string &valueAsString) + { + if (PyErr_Occurred()) { + PyErr_Print(); + PyObject *stringRepresentation = PyObject_Str(pyIn); + const char *cString = Shiboken::String::toCString(stringRepresentation); + valueAsString.assign(cString); + Py_DECREF(stringRepresentation); + return true; + } + return false; + } +}; + +// Helper template for checking if a value overflows when cast to type T. +// The MaxLimitType size is usually >= than type T size, so that it can still represent values that +// can't be stored in T (unless the types are of course the same). +// TLDR: MaxLimitType is either long long or unsigned long long. +template::is_signed > +struct OverFlowChecker; + +template +struct OverFlowChecker : + public OverFlowCheckerBase { + static bool check(const MaxLimitType& value, PyObject *pyIn) + { + std::string valueAsString; + const bool isOverflow = + OverFlowChecker::checkForInternalPyOverflow(pyIn, valueAsString) + || value < std::numeric_limits::min() + || value > std::numeric_limits::max(); + if (isOverflow) + OverFlowChecker::formatOverFlowMessage(value, &valueAsString); + return isOverflow; + } +}; + +template +struct OverFlowChecker + : public OverFlowCheckerBase { + static bool check(const MaxLimitType& value, PyObject *pyIn) + { + std::string valueAsString; + const bool isOverflow = + OverFlowChecker::checkForInternalPyOverflow(pyIn, valueAsString) + || value < 0 + || static_cast(value) > std::numeric_limits::max(); + if (isOverflow) + OverFlowChecker::formatOverFlowMessage(value, &valueAsString); + return isOverflow; + } +}; +template<> +struct OverFlowChecker : + public OverFlowCheckerBase { + static bool check(const PY_LONG_LONG &value, PyObject *pyIn) { + std::string valueAsString; + const bool isOverflow = checkForInternalPyOverflow(pyIn, valueAsString); + if (isOverflow) + OverFlowChecker::formatOverFlowMessage(value, &valueAsString); + return isOverflow; + + } +}; +template<> +struct OverFlowChecker { + static bool check(const double &, PyObject *) { return false; } +}; +template<> +struct OverFlowChecker : + public OverFlowCheckerBase { + static bool check(const double& value, PyObject *) + { + const bool result = value < std::numeric_limits::min() + || value > std::numeric_limits::max(); + if (result) + formatOverFlowMessage(value); + return result; + } +}; + +// Basic primitive type converters --------------------------------------------------------- +template PyTypeObject* SbkType() { return 0; } +template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType() { return &PyBool_Type; } +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType() { return &PyString_Type; } +template<> inline PyTypeObject* SbkType() { return &PyFloat_Type; } +template<> inline PyTypeObject* SbkType() { return &PyFloat_Type; } +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } + +template struct Primitive {}; + +template +struct OnePrimitive +{ + static PyObject* toPython(const void*) { return 0; } + static PythonToCppFunc isConvertible(PyObject*) { return 0; } + static void toCpp(PyObject*, void*) {} + static SbkConverter* createConverter() + { + SbkConverter* converter = Shiboken::Conversions::createConverter(SbkType(), Primitive::toPython); + Shiboken::Conversions::addPythonToCppValueConversion(converter, Primitive::toCpp, Primitive::isConvertible); + return converter; + } +}; +template +struct TwoPrimitive : OnePrimitive +{ + static PythonToCppFunc isOtherConvertible(PyObject*) { return 0; } + static void otherToCpp(PyObject*, void*) {} + static SbkConverter* createConverter() + { + SbkConverter* converter = OnePrimitive::createConverter(); + Shiboken::Conversions::addPythonToCppValueConversion(converter, Primitive::otherToCpp, Primitive::isOtherConvertible); + return converter; + } +}; + +// Integers -------------------------------------------------------------------------------- + +template +struct IntPrimitive : TwoPrimitive +{ + static PyObject* toPython(const void* cppIn) + { + return PyInt_FromLong(*reinterpret_cast(cppIn)); + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + double result = PyFloat_AS_DOUBLE(pyIn); + // If cast to long directly it could overflow silently. + if (OverFlowChecker::check(result, pyIn)) + PyErr_SetObject(PyExc_OverflowError, 0); + *reinterpret_cast(cppOut) = static_cast(result); + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (PyFloat_Check(pyIn)) + return toCpp; + return 0; + } + static void otherToCpp(PyObject* pyIn, void* cppOut) + { + PY_LONG_LONG result = PyLong_AsLongLong(pyIn); + if (OverFlowChecker::check(result, pyIn)) + PyErr_SetObject(PyExc_OverflowError, 0); + *reinterpret_cast(cppOut) = static_cast(result); + } + static PythonToCppFunc isOtherConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return otherToCpp; + return 0; + } +}; +template <> struct Primitive : IntPrimitive {}; +template <> struct Primitive : IntPrimitive {}; +template <> struct Primitive : IntPrimitive {}; +template <> struct Primitive : IntPrimitive {}; + +// Unsigned Long Integers ------------------------------------------------------------------ + +template +struct UnsignedLongPrimitive : IntPrimitive +{ + static PyObject* toPython(const void* cppIn) + { + return PyLong_FromUnsignedLong(*reinterpret_cast(cppIn)); + } +}; +template <> struct Primitive : UnsignedLongPrimitive {}; +template <> struct Primitive : UnsignedLongPrimitive {}; + +// Big integers ---------------------------------------------------------------------------- + +template <> +struct Primitive : OnePrimitive +{ + static PyObject* toPython(const void* cppIn) + { + return PyLong_FromLongLong(*((PY_LONG_LONG*)cppIn)); + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + PY_LONG_LONG result = PyLong_AsLongLong(pyIn); + if (OverFlowChecker::check(result, pyIn)) + PyErr_SetObject(PyExc_OverflowError, 0); + *reinterpret_cast(cppOut) = result; + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return toCpp; + return 0; + } +}; + +template <> +struct Primitive : OnePrimitive +{ + static PyObject* toPython(const void* cppIn) + { + return PyLong_FromUnsignedLongLong(*((unsigned PY_LONG_LONG*)cppIn)); + } + static void toCpp(PyObject* pyIn, void* cppOut) + { +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(pyIn)) { + unsigned PY_LONG_LONG result = PyLong_AsUnsignedLongLong(pyIn); + if (OverFlowChecker::check(result, pyIn)) + PyErr_SetObject(PyExc_OverflowError, 0); + *reinterpret_cast(cppOut) = result; + } + else { + PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion"); + } +#else + if (PyInt_Check(pyIn)) { + long result = PyInt_AsLong(pyIn); + if (OverFlowChecker::check(result, pyIn)) + PyErr_SetObject(PyExc_OverflowError, 0); + *reinterpret_cast(cppOut) = + static_cast(result); + } else if (PyLong_Check(pyIn)) { + unsigned PY_LONG_LONG result = PyLong_AsUnsignedLongLong(pyIn); + if (OverFlowChecker::check(result, pyIn)) + PyErr_SetObject(PyExc_OverflowError, 0); + *reinterpret_cast(cppOut) = result; + } else { + PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion"); + } +#endif // Python 2 + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return toCpp; + return 0; + } +}; + +// Floating point -------------------------------------------------------------------------- + +template +struct FloatPrimitive : TwoPrimitive +{ + static PyObject* toPython(const void* cppIn) + { + return PyFloat_FromDouble(*reinterpret_cast(cppIn)); + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + *reinterpret_cast(cppOut) = FLOAT(PyLong_AsLong(pyIn)); + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (PyInt_Check(pyIn) || PyLong_Check(pyIn)) + return toCpp; + return 0; + } + static void otherToCpp(PyObject* pyIn, void* cppOut) + { + *reinterpret_cast(cppOut) = FLOAT(PyFloat_AsDouble(pyIn)); + } + static PythonToCppFunc isOtherConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return otherToCpp; + return 0; + } +}; +template <> struct Primitive : FloatPrimitive {}; +template <> struct Primitive : FloatPrimitive {}; + +// Boolean --------------------------------------------------------------------------------- + +template <> +struct Primitive : OnePrimitive +{ + static PyObject* toPython(const void* cppIn) + { + return PyBool_FromLong(*reinterpret_cast(cppIn)); + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return toCpp; + return 0; + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + *reinterpret_cast(cppOut) = PyInt_AS_LONG(pyIn) != 0; + } +}; + +// Characters ------------------------------------------------------------------------------ + +template +struct CharPrimitive : IntPrimitive +{ + static void toCpp(PyObject* pyIn, void* cppOut) + { + *reinterpret_cast(cppOut) = CHAR(Shiboken::String::toCString(pyIn)[0]); + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (Shiboken::String::checkChar(pyIn)) + return toCpp; + return 0; + } + static void otherToCpp(PyObject* pyIn, void* cppOut) + { + PY_LONG_LONG result = PyLong_AsLongLong(pyIn); + if (OverFlowChecker::check(result, pyIn)) + PyErr_SetObject(PyExc_OverflowError, 0); + *reinterpret_cast(cppOut) = CHAR(result); + } + static PythonToCppFunc isOtherConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return otherToCpp; + return 0; + } + static SbkConverter* createConverter() + { + SbkConverter* converter = IntPrimitive::createConverter(); + Shiboken::Conversions::addPythonToCppValueConversion(converter, CharPrimitive::otherToCpp, CharPrimitive::isOtherConvertible); + return converter; + } + +}; +template <> struct Primitive : CharPrimitive {}; +template <> struct Primitive : CharPrimitive {}; +template <> struct Primitive : CharPrimitive { + using CharPrimitive::toPython; + static PyObject* toPython(const void* cppIn) { + return Shiboken::String::fromCString((const char*)cppIn, 1); + } +}; + + + +// Strings --------------------------------------------------------------------------------- + +template <> +struct Primitive : TwoPrimitive +{ + static PyObject* toPython(const void* cppIn) + { + if (!cppIn) + Py_RETURN_NONE; + return Shiboken::String::fromCString((const char*)cppIn); + } + static void toCpp(PyObject *, void *cppOut) + { + *((const char**)cppOut) = 0; + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (pyIn == Py_None) + return toCpp; + return 0; + } + static void otherToCpp(PyObject* pyIn, void* cppOut) + { + *((const char**)cppOut) = (const char*) Shiboken::String::toCString(pyIn); + } + static PythonToCppFunc isOtherConvertible(PyObject* pyIn) + { + if (Shiboken::String::check(pyIn)) + return otherToCpp; + return 0; + } +}; + +template <> +struct Primitive : TwoPrimitive +{ + static PyObject* toPython(const void* cppIn) + { + return Shiboken::String::fromCString(((std::string*)cppIn)->c_str()); + } + static void toCpp(PyObject *, void *cppOut) + { + *((std::string*)cppOut) = std::string(); + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (pyIn == Py_None) + return toCpp; + return 0; + } + static void otherToCpp(PyObject* pyIn, void* cppOut) + { + *((std::string*)cppOut) = Shiboken::String::toCString(pyIn); + } + static PythonToCppFunc isOtherConvertible(PyObject* pyIn) + { + if (Shiboken::String::check(pyIn)) + return otherToCpp; + return 0; + } +}; + +// Void pointer ---------------------------------------------------------------------------- + +template <> +struct Primitive : OnePrimitive +{ + static PyObject* toPython(const void* cppIn) + { + SbkDbg() << cppIn; + if (!cppIn) + Py_RETURN_NONE; + PyObject *result = reinterpret_cast(const_cast(cppIn)); + Py_INCREF(result); + return result; + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + SbkDbg() << pyIn; + *reinterpret_cast(cppOut) = pyIn; + } + static PythonToCppFunc isConvertible(PyObject *) + { + return toCpp; + } +}; + +#endif // SBK_CONVERTER_P_H diff --git a/sources/shiboken2/libshiboken/sbkdbg.h b/sources/shiboken2/libshiboken/sbkdbg.h new file mode 100644 index 000000000..937153adf --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkdbg.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SBKDBG_H +#define SBKDBG_H + +#include "sbkpython.h" +#include "basewrapper.h" +#include + +#ifndef NOCOLOR + #define COLOR_END "\033[0m" + #define COLOR_WHITE "\033[1;37m" + #define COLOR_YELLOW "\033[1;33m" + #define COLOR_GREEN "\033[0;32m" + #define COLOR_RED "\033[0;31m" +#else + #define COLOR_END "" + #define COLOR_WHITE "" + #define COLOR_YELLOW "" + #define COLOR_GREEN "" + #define COLOR_RED "" +#endif + +#ifndef NDEBUG + +class BaseLogger +{ +public: + BaseLogger(std::ostream& output, const char* function, const char* context) + : m_stream(output), m_function(function), m_context(context) {} + ~BaseLogger() + { + m_stream << std::endl; + } + std::ostream& operator()() { return m_stream; }; + template + std::ostream& operator<<(const T& t) + { + m_stream << '['; + if (m_context[0]) + m_stream << COLOR_GREEN << m_context << COLOR_END << "|"; + return m_stream << COLOR_WHITE << m_function << COLOR_END << "] " << t; + } +private: + std::ostream& m_stream; + const char* m_function; + const char* m_context; +}; + +inline std::ostream& operator<<(std::ostream& out, PyObject* obj) +{ + PyObject* repr = Shiboken::Object::isValid(obj, false) ? PyObject_Repr(obj) : 0; + if (repr) { +#ifdef IS_PY3K + PyObject* str = PyUnicode_AsUTF8String(repr); + Py_DECREF(repr); + repr = str; +#endif + out << PyBytes_AS_STRING(repr); + Py_DECREF(repr); + } else { + out << reinterpret_cast(obj); + } + return out; +} + +class _SbkDbg : public BaseLogger +{ +public: + _SbkDbg(const char* function, const char* context = "") : BaseLogger(std::cout, function, context) {} +}; + +#ifdef __GNUG__ +#define SbkDbg(X) _SbkDbg(__PRETTY_FUNCTION__, X"") +#else +#define SbkDbg(X) _SbkDbg(__FUNCTION__, X"") +#endif + +#else + +struct SbkDbg { + template + SbkDbg& operator<<(const T&) { return *this; } +}; + +#endif +#endif // LOGGER_H diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp new file mode 100644 index 000000000..0902077ed --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkenum.cpp @@ -0,0 +1,618 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "sbkenum.h" +#include "sbkstring.h" +#include "sbkconverter.h" +#include "basewrapper.h" +#include "sbkdbg.h" +#include "autodecref.h" +#include "typeresolver.h" +#include "sbkpython.h" + +#include +#include +#include + +#define SBK_ENUM(ENUM) reinterpret_cast(ENUM) + +extern "C" +{ + +struct SbkEnumType +{ + PyHeapTypeObject super; + SbkConverter** converterPtr; + SbkConverter* converter; + const char* cppName; +}; + +struct SbkEnumObject +{ + PyObject_HEAD + long ob_value; + PyObject* ob_name; +}; + +static PyObject* SbkEnumObject_repr(PyObject* self) +{ + const SbkEnumObject *enumObj = reinterpret_cast(self); + if (enumObj->ob_name) + return Shiboken::String::fromFormat("%s.%s", self->ob_type->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); + else + return Shiboken::String::fromFormat("%s(%ld)", self->ob_type->tp_name, enumObj->ob_value); +} + +static int SbkEnumObject_print(PyObject* self, FILE* fp, int) +{ + Py_BEGIN_ALLOW_THREADS + const SbkEnumObject *enumObj = reinterpret_cast(self); + if (enumObj->ob_name) + fprintf(fp, "%s.%s", self->ob_type->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); + else + fprintf(fp, "%s(%ld)", self->ob_type->tp_name, enumObj->ob_value); + Py_END_ALLOW_THREADS + return 0; +} + +static PyObject* SbkEnumObject_name(PyObject* self, void*) +{ + SbkEnumObject *enum_self = reinterpret_cast(self); + + if (enum_self->ob_name == NULL) + Py_RETURN_NONE; + + Py_INCREF(enum_self->ob_name); + return enum_self->ob_name; +} + +static PyObject* SbkEnum_tp_new(PyTypeObject *type, PyObject *args, PyObject *) +{ + long itemValue = 0; + if (!PyArg_ParseTuple(args, "|l:__new__", &itemValue)) + return 0; + + SbkEnumObject* self = PyObject_New(SbkEnumObject, type); + if (!self) + return 0; + self->ob_value = itemValue; + PyObject* item = Shiboken::Enum::getEnumItemFromValue(type, itemValue); + if (item) { + self->ob_name = SbkEnumObject_name(item, 0); + Py_XDECREF(item); + } else { + self->ob_name = 0; + } + return reinterpret_cast(self); +} + +/* Notes: + * On Py3k land we use long type when using integer numbers. However, on older + * versions of Python (version 2) we need to convert it to int type, + * respectively. + * + * Thus calling PyInt_FromLong() will result in calling PyLong_FromLong in + * Py3k. + */ +static PyObject* enum_int(PyObject* v) +{ + return PyInt_FromLong(SBK_ENUM(v)->ob_value); +} + +static long getNumberValue(PyObject* v) +{ + PyObject* number = PyNumber_Long(v); + long result = PyLong_AsLong(number); + Py_XDECREF(number); + return result; +} + +static PyObject* enum_and(PyObject* self, PyObject* b) +{ + if (!PyNumber_Check(b)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + long valA = SBK_ENUM(self)->ob_value; + long valB = getNumberValue(b); + return PyInt_FromLong(valA & valB); +} + +static PyObject* enum_or(PyObject* self, PyObject* b) +{ + if (!PyNumber_Check(b)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + long valA = SBK_ENUM(self)->ob_value; + long valB = getNumberValue(b); + return PyInt_FromLong(valA | valB); +} + +static PyObject* enum_xor(PyObject* self, PyObject* b) +{ + if (!PyNumber_Check(b)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + long valA = SBK_ENUM(self)->ob_value; + long valB = getNumberValue(b); + return PyInt_FromLong(valA ^ valB); +} + +static int enum_bool(PyObject* v) +{ + return (SBK_ENUM(v)->ob_value > 0); +} + +static PyObject* enum_add(PyObject* self, PyObject* v) +{ + long valA = SBK_ENUM(self)->ob_value; + long valB = getNumberValue(v); + return PyInt_FromLong(valA + valB); +} + +static PyObject* enum_subtract(PyObject* self, PyObject* v) +{ + long valA = SBK_ENUM(self)->ob_value; + long valB = getNumberValue(v); + return PyInt_FromLong(valA - valB); +} + +static PyObject* enum_multiply(PyObject* self, PyObject* v) +{ + long valA = SBK_ENUM(self)->ob_value; + long valB = getNumberValue(v); + return PyInt_FromLong(valA * valB); +} + +#ifndef IS_PY3K +static PyObject* enum_divide(PyObject* self, PyObject* v) +{ + long valA = SBK_ENUM(self)->ob_value; + long valB = getNumberValue(v); + return PyLong_FromLong(valA / valB); +} +#endif + +static PyObject* enum_richcompare(PyObject* self, PyObject* other, int op) +{ + int result = 0; + if (!PyNumber_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + long valA = SBK_ENUM(self)->ob_value; + long valB = getNumberValue(other); + + switch (op) { + case Py_EQ: + result = (valA == valB); + break; + case Py_NE: + result = (valA != valB); + break; + case Py_LE: + result = (valA <= valB); + break; + case Py_GE: + result = (valA >= valB); + break; + case Py_LT: + result = (valA < valB); + break; + case Py_GT: + result = (valA > valB); + break; + default: + PyErr_BadArgument(); + return NULL; + } + if (result) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static Py_hash_t enum_hash(PyObject* pyObj) +{ + Py_hash_t val = reinterpret_cast(pyObj)->ob_value; + if (val == -1) + val = -2; + return val; +} + +static PyGetSetDef SbkEnumGetSetList[] = { + {const_cast("name"), &SbkEnumObject_name, 0, 0, 0}, + {0, 0, 0, 0, 0} // Sentinel +}; + +static PyNumberMethods enum_as_number = { + /* nb_add */ enum_add, + /* nb_subtract */ enum_subtract, + /* nb_multiply */ enum_multiply, +#ifndef IS_PY3K + /* nb_divide */ enum_divide, +#endif + /* nb_remainder */ 0, + /* nb_divmod */ 0, + /* nb_power */ 0, + /* nb_negative */ 0, + /* nb_positive */ enum_int, + /* nb_absolute */ 0, + /* nb_bool/nb_nonzero */ enum_bool, + /* nb_invert */ 0, + /* nb_lshift */ 0, + /* nb_rshift */ 0, + /* nb_and */ enum_and, + /* nb_xor */ enum_xor, + /* nb_or */ enum_or, +#ifndef IS_PY3K + /* nb_coerce */ 0, +#endif + /* nb_int */ enum_int, +#ifdef IS_PY3K + /* nb_reserved */ 0, + /* nb_float */ 0, +#else + /* nb_long */ enum_int, + /* nb_float */ 0, + /* nb_oct */ 0, + /* nb_hex */ 0, +#endif + + /* nb_inplace_add */ 0, + /* nb_inplace_subtract */ 0, + /* nb_inplace_multiply */ 0, +#ifndef IS_PY3K + /* nb_inplace_div */ 0, +#endif + /* nb_inplace_remainder */ 0, + /* nb_inplace_power */ 0, + /* nb_inplace_lshift */ 0, + /* nb_inplace_rshift */ 0, + /* nb_inplace_and */ 0, + /* nb_inplace_xor */ 0, + /* nb_inplace_or */ 0, + + /* nb_floor_divide */ 0, + /* nb_true_divide */ 0, + /* nb_inplace_floor_divide */ 0, + /* nb_inplace_true_divide */ 0, + + /* nb_index */ enum_int +}; + +static void SbkEnumTypeDealloc(PyObject* pyObj); +static PyObject* SbkEnumTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); + +PyTypeObject SbkEnumType_Type = { + PyVarObject_HEAD_INIT(0, 0) + /*tp_name*/ "Shiboken.EnumType", + /*tp_basicsize*/ sizeof(SbkEnumType), + /*tp_itemsize*/ 0, + /*tp_dealloc*/ SbkEnumTypeDealloc, + /*tp_print*/ 0, + /*tp_getattr*/ 0, + /*tp_setattr*/ 0, + /*tp_compare*/ 0, + /*tp_repr*/ 0, + /*tp_as_number*/ &enum_as_number, + /*tp_as_sequence*/ 0, + /*tp_as_mapping*/ 0, + /*tp_hash*/ 0, + /*tp_call*/ 0, + /*tp_str*/ 0, + /*tp_getattro*/ 0, + /*tp_setattro*/ 0, + /*tp_as_buffer*/ 0, + /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, + /*tp_doc*/ 0, + /*tp_traverse*/ 0, + /*tp_clear*/ 0, + /*tp_richcompare*/ 0, + /*tp_weaklistoffset*/ 0, + /*tp_iter*/ 0, + /*tp_iternext*/ 0, + /*tp_methods*/ 0, + /*tp_members*/ 0, + /*tp_getset*/ 0, + /*tp_base*/ &PyType_Type, + /*tp_dict*/ 0, + /*tp_descr_get*/ 0, + /*tp_descr_set*/ 0, + /*tp_dictoffset*/ 0, + /*tp_init*/ 0, + /*tp_alloc*/ PyType_GenericAlloc, + /*tp_new*/ SbkEnumTypeTpNew, + /*tp_free*/ PyObject_GC_Del, + /*tp_is_gc*/ 0, + /*tp_bases*/ 0, + /*tp_mro*/ 0, + /*tp_cache*/ 0, + /*tp_subclasses*/ 0, + /*tp_weaklist*/ 0, + /*tp_del*/ 0, + /*tp_version_tag*/ 0 +}; + +void SbkEnumTypeDealloc(PyObject* pyObj) +{ + SbkEnumType* sbkType = reinterpret_cast(pyObj); + + PyObject_GC_UnTrack(pyObj); + Py_TRASHCAN_SAFE_BEGIN(pyObj); + if (sbkType->converter) { + Shiboken::Conversions::deleteConverter(sbkType->converter); + } + Py_TRASHCAN_SAFE_END(pyObj); +} + +PyObject* SbkEnumTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds) +{ + SbkEnumType* newType = reinterpret_cast(PyType_Type.tp_new(metatype, args, kwds)); + if (!newType) + return 0; + return reinterpret_cast(newType); +} + +} // extern "C" + +namespace Shiboken { + +class DeclaredEnumTypes +{ +public: + DeclaredEnumTypes(); + ~DeclaredEnumTypes(); + static DeclaredEnumTypes& instance(); + void addEnumType(PyTypeObject* type); + +private: + DeclaredEnumTypes(const DeclaredEnumTypes&); + DeclaredEnumTypes& operator=(const DeclaredEnumTypes&); + std::list m_enumTypes; +}; + +namespace Enum { + +bool check(PyObject* pyObj) +{ + return Py_TYPE(pyObj->ob_type) == &SbkEnumType_Type; +} + +PyObject* getEnumItemFromValue(PyTypeObject* enumType, long itemValue) +{ + PyObject *key, *value; + Py_ssize_t pos = 0; + PyObject* values = PyDict_GetItemString(enumType->tp_dict, const_cast("values")); + + while (PyDict_Next(values, &pos, &key, &value)) { + SbkEnumObject *obj = reinterpret_cast(value); + if (obj->ob_value == itemValue) { + Py_INCREF(obj); + return value; + } + } + return 0; +} + +static PyTypeObject* createEnum(const char* fullName, const char* cppName, const char* shortName, PyTypeObject* flagsType) +{ + PyTypeObject* enumType = newTypeWithName(fullName, cppName); + if (flagsType) + enumType->tp_as_number = flagsType->tp_as_number; + if (PyType_Ready(enumType) < 0) + return 0; + Shiboken::TypeResolver::createValueTypeResolver(cppName); + if (shortName) + Shiboken::TypeResolver::createValueTypeResolver(shortName); + return enumType; +} + +PyTypeObject* createGlobalEnum(PyObject* module, const char* name, const char* fullName, const char* cppName, PyTypeObject* flagsType) +{ + PyTypeObject* enumType = createEnum(fullName, cppName, name, flagsType); + Shiboken::TypeResolver::createValueTypeResolver("Qt::WindowType"); + Shiboken::TypeResolver::createValueTypeResolver("WindowType"); + if (enumType && PyModule_AddObject(module, name, reinterpret_cast(enumType)) < 0) + return 0; + if (flagsType && PyModule_AddObject(module, flagsType->tp_name, reinterpret_cast(flagsType)) < 0) + return 0; + return enumType; +} + +PyTypeObject* createScopedEnum(SbkObjectType* scope, const char* name, const char* fullName, const char* cppName, PyTypeObject* flagsType) +{ + PyTypeObject* enumType = createEnum(fullName, cppName, name, flagsType); + if (enumType && PyDict_SetItemString(scope->super.ht_type.tp_dict, name, reinterpret_cast(enumType)) < 0) + return 0; + if (flagsType && PyDict_SetItemString(scope->super.ht_type.tp_dict, flagsType->tp_name, reinterpret_cast(flagsType)) < 0) + return 0; + return enumType; +} + +static PyObject* createEnumItem(PyTypeObject* enumType, const char* itemName, long itemValue) +{ + PyObject* enumItem = newItem(enumType, itemValue, itemName); + if (PyDict_SetItemString(enumType->tp_dict, itemName, enumItem) < 0) + return 0; + Py_DECREF(enumItem); + return enumItem; +} + +bool createGlobalEnumItem(PyTypeObject* enumType, PyObject* module, const char* itemName, long itemValue) +{ + PyObject* enumItem = createEnumItem(enumType, itemName, itemValue); + if (enumItem) { + if (PyModule_AddObject(module, itemName, enumItem) < 0) + return false; + Py_DECREF(enumItem); + return true; + } + return false; +} + +bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const char* itemName, long itemValue) +{ + PyObject* enumItem = createEnumItem(enumType, itemName, itemValue); + if (enumItem) { + if (PyDict_SetItemString(scope->super.ht_type.tp_dict, itemName, enumItem) < 0) + return false; + Py_DECREF(enumItem); + return true; + } + return false; +} + +PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) +{ + bool newValue = true; + SbkEnumObject* enumObj; + if (!itemName) { + enumObj = reinterpret_cast(getEnumItemFromValue(enumType, itemValue)); + if (enumObj) + return reinterpret_cast(enumObj); + + newValue = false; + } + + enumObj = PyObject_New(SbkEnumObject, enumType); + if (!enumObj) + return 0; + + enumObj->ob_name = itemName ? PyBytes_FromString(itemName) : 0; + enumObj->ob_value = itemValue; + + if (newValue) { + PyObject* values = PyDict_GetItemString(enumType->tp_dict, const_cast("values")); + if (!values) { + values = PyDict_New(); + PyDict_SetItemString(enumType->tp_dict, const_cast("values"), values); + Py_DECREF(values); // ^ values still alive, because setitemstring incref it + } + PyDict_SetItemString(values, itemName, reinterpret_cast(enumObj)); + } + + return reinterpret_cast(enumObj); +} + +PyTypeObject* newType(const char* name) +{ + return newTypeWithName(name, ""); +} + +PyTypeObject* newTypeWithName(const char* name, const char* cppName) +{ + PyTypeObject* type = reinterpret_cast(new SbkEnumType); + ::memset(type, 0, sizeof(SbkEnumType)); + Py_TYPE(type) = &SbkEnumType_Type; + type->tp_basicsize = sizeof(SbkEnumObject); + type->tp_print = &SbkEnumObject_print; + type->tp_repr = &SbkEnumObject_repr; + type->tp_str = &SbkEnumObject_repr; + type->tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES; + type->tp_name = name; + type->tp_getset = SbkEnumGetSetList; + type->tp_new = SbkEnum_tp_new; + type->tp_as_number = &enum_as_number; + type->tp_richcompare = &enum_richcompare; + type->tp_hash = &enum_hash; + + SbkEnumType* enumType = reinterpret_cast(type); + enumType->cppName = cppName; + enumType->converterPtr = &enumType->converter; + DeclaredEnumTypes::instance().addEnumType(type); + return type; +} + +const char* getCppName(PyTypeObject* enumType) +{ + assert(Py_TYPE(enumType) == &SbkEnumType_Type); + return reinterpret_cast(enumType)->cppName;; +} + +long int getValue(PyObject* enumItem) +{ + assert(Shiboken::Enum::check(enumItem)); + return reinterpret_cast(enumItem)->ob_value; +} + +void setTypeConverter(PyTypeObject* enumType, SbkConverter* converter) +{ + //reinterpret_cast(enumType)->converter = converter; + SBK_CONVERTER(enumType) = converter; +} + +SbkConverter* getTypeConverter(PyTypeObject* enumType) +{ + //return reinterpret_cast(enumType)->converter; + return SBK_CONVERTER(enumType); +} + +} // namespace Enum + +DeclaredEnumTypes& DeclaredEnumTypes::instance() +{ + static DeclaredEnumTypes me; + return me; +} + +DeclaredEnumTypes::DeclaredEnumTypes() +{ +} + +DeclaredEnumTypes::~DeclaredEnumTypes() +{ + std::list::const_iterator it = m_enumTypes.begin(); + for (; it != m_enumTypes.end(); ++it) + delete *it; + m_enumTypes.clear(); +} + +void DeclaredEnumTypes::addEnumType(PyTypeObject* type) +{ + m_enumTypes.push_back(type); +} + +} diff --git a/sources/shiboken2/libshiboken/sbkenum.h b/sources/shiboken2/libshiboken/sbkenum.h new file mode 100644 index 000000000..4b572dbcc --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkenum.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SBKENUM_H +#define SBKENUM_H + +#include "sbkpython.h" +#include "shibokenmacros.h" + +extern "C" +{ + +extern LIBSHIBOKEN_API PyTypeObject SbkEnumType_Type; +struct SbkObjectType; +struct SbkConverter; + +} // extern "C" + +namespace Shiboken +{ + +inline bool isShibokenEnum(PyObject* pyObj) +{ + return Py_TYPE(pyObj->ob_type) == &SbkEnumType_Type; +} + +namespace Enum +{ + LIBSHIBOKEN_API bool check(PyObject* obj); + /** + * Creates a new enum type (and its flags type, if any is given) + * and registers it to Python and adds it to \p module. + * \param module Module to where the new enum type will be added. + * \param name Name of the enum. + * \param fullName Name of the enum that includes all scope information (e.g.: "module.Enum"). + * \param cppName Full qualified C++ name of the enum. + * \param flagsType Optional Python type for the flags associated with the enum. + * \return The new enum type or NULL if it fails. + */ + LIBSHIBOKEN_API PyTypeObject* createGlobalEnum(PyObject* module, + const char* name, + const char* fullName, + const char* cppName, + PyTypeObject* flagsType = 0); + /// This function does the same as createGlobalEnum, but adds the enum to a Shiboken type or namespace. + LIBSHIBOKEN_API PyTypeObject* createScopedEnum(SbkObjectType* scope, + const char* name, + const char* fullName, + const char* cppName, + PyTypeObject* flagsType = 0); + + /** + * Creates a new enum item for a given enum type and adds it to \p module. + * \param enumType Enum type to where the new enum item will be added. + * \param module Module to where the enum type of the new enum item belongs. + * \param itemName Name of the enum item. + * \param itemValue Numerical value of the enum item. + * \return true if everything goes fine, false if it fails. + */ + LIBSHIBOKEN_API bool createGlobalEnumItem(PyTypeObject* enumType, PyObject* module, const char* itemName, long itemValue); + /// This function does the same as createGlobalEnumItem, but adds the enum to a Shiboken type or namespace. + LIBSHIBOKEN_API bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const char* itemName, long itemValue); + + LIBSHIBOKEN_API PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName = 0); + + /// \deprecated Use 'newTypeWithName' + SBK_DEPRECATED(LIBSHIBOKEN_API PyTypeObject* newType(const char* name)); + LIBSHIBOKEN_API PyTypeObject* newTypeWithName(const char* name, const char* cppName); + LIBSHIBOKEN_API const char* getCppName(PyTypeObject* type); + + LIBSHIBOKEN_API long getValue(PyObject* enumItem); + LIBSHIBOKEN_API PyObject* getEnumItemFromValue(PyTypeObject* enumType, long itemValue); + + /// Sets the enum's type converter. + LIBSHIBOKEN_API void setTypeConverter(PyTypeObject* enumType, SbkConverter* converter); + /// Returns the converter assigned to the enum \p type. + LIBSHIBOKEN_API SbkConverter* getTypeConverter(PyTypeObject* enumType); +} + +} // namespace Shiboken + +#endif // SKB_PYENUM_H diff --git a/sources/shiboken2/libshiboken/sbkmodule.cpp b/sources/shiboken2/libshiboken/sbkmodule.cpp new file mode 100644 index 000000000..2ea9d56ac --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkmodule.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "sbkmodule.h" +#include "basewrapper.h" +#include "bindingmanager.h" +#include + +/// This hash maps module objects to arrays of Python types. +typedef std::unordered_map ModuleTypesMap; + +/// This hash maps module objects to arrays of converters. +typedef std::unordered_map ModuleConvertersMap; + +/// All types produced in imported modules are mapped here. +static ModuleTypesMap moduleTypes; +static ModuleConvertersMap moduleConverters; + +namespace Shiboken +{ +namespace Module +{ + +PyObject* import(const char* moduleName) +{ + PyObject* sysModules = PyImport_GetModuleDict(); + PyObject* module = PyDict_GetItemString(sysModules, moduleName); + if (module) + Py_INCREF(module); + else + module = PyImport_ImportModule(moduleName); + + if (!module) + PyErr_Format(PyExc_ImportError,"could not import module '%s'", moduleName); + + return module; +} + +PyObject* create(const char* moduleName, void* moduleData) +{ + Shiboken::init(); +#ifndef IS_PY3K + return Py_InitModule(moduleName, reinterpret_cast(moduleData)); +#else + return PyModule_Create(reinterpret_cast(moduleData)); +#endif +} + +void registerTypes(PyObject* module, PyTypeObject** types) +{ + ModuleTypesMap::iterator iter = moduleTypes.find(module); + if (iter == moduleTypes.end()) + moduleTypes.insert(std::make_pair(module, types)); +} + +PyTypeObject** getTypes(PyObject* module) +{ + ModuleTypesMap::iterator iter = moduleTypes.find(module); + return (iter == moduleTypes.end()) ? 0 : iter->second; +} + +void registerTypeConverters(PyObject* module, SbkConverter** converters) +{ + ModuleConvertersMap::iterator iter = moduleConverters.find(module); + if (iter == moduleConverters.end()) + moduleConverters.insert(std::make_pair(module, converters)); +} + +SbkConverter** getTypeConverters(PyObject* module) +{ + ModuleConvertersMap::iterator iter = moduleConverters.find(module); + return (iter == moduleConverters.end()) ? 0 : iter->second; +} + +} } // namespace Shiboken::Module diff --git a/sources/shiboken2/libshiboken/sbkmodule.h b/sources/shiboken2/libshiboken/sbkmodule.h new file mode 100644 index 000000000..e1ec7a860 --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkmodule.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SBK_MODULE_H +#define SBK_MODULE_H + +#include "sbkpython.h" +#include "shibokenmacros.h" + +#if PY_MAJOR_VERSION >= 3 + #define SBK_MODULE_INIT_ERROR 0 + #define SBK_MODULE_INIT_FUNCTION_BEGIN(ModuleName) \ + extern "C" SBK_EXPORT_MODULE PyObject* PyInit_##ModuleName() { + + #define SBK_MODULE_INIT_FUNCTION_END \ + return module; } +#else + #define SBK_MODULE_INIT_ERROR + #define SBK_MODULE_INIT_FUNCTION_BEGIN(ModuleName) \ + extern "C" SBK_EXPORT_MODULE void init##ModuleName() { + + #define SBK_MODULE_INIT_FUNCTION_END \ + } +#endif + +extern "C" +{ +struct SbkConverter; +} + +namespace Shiboken { +namespace Module { + +/** + * Imports and returns the module named \p moduleName, or a NULL pointer in case of failure. + * If the module is already imported, it increments its reference count before returning it. + * \returns the module specified in \p moduleName or NULL if an error occurs. + */ +LIBSHIBOKEN_API PyObject* import(const char* moduleName); + +/** + * Creates a new Python module named \p moduleName using the information passed in \p moduleData. + * In fact, \p moduleData expects a "PyMethodDef*" object, but that's for Python 2. A void* + * was preferred to make this work with future Python 3 support. + * \returns a newly created module. + */ +LIBSHIBOKEN_API PyObject* create(const char* moduleName, void* moduleData); + +/** + * Registers the list of types created by \p module. + * \param module Module where the types were created. + * \param types Array of PyTypeObject* objects representing the types created on \p module. + */ +LIBSHIBOKEN_API void registerTypes(PyObject* module, PyTypeObject** types); + +/** + * Retrieves the array of types. + * \param module Module where the types were created. + * \returns A pointer to the PyTypeObject* array of types. + */ +LIBSHIBOKEN_API PyTypeObject** getTypes(PyObject* module); + +/** + * Registers the list of converters created by \p module for non-wrapper types. + * \param module Module where the converters were created. + * \param converters Array of SbkConverter* objects representing the converters created on \p module. + */ +LIBSHIBOKEN_API void registerTypeConverters(PyObject* module, SbkConverter** converters); + +/** + * Retrieves the array of converters. + * \param module Module where the converters were created. + * \returns A pointer to the SbkConverter* array of converters. + */ +LIBSHIBOKEN_API SbkConverter** getTypeConverters(PyObject* module); + +} } // namespace Shiboken::Module + +#endif // SBK_MODULE_H diff --git a/sources/shiboken2/libshiboken/sbkpython.h b/sources/shiboken2/libshiboken/sbkpython.h new file mode 100644 index 000000000..208618d50 --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkpython.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SBKPYTHON_H +#define SBKPYTHON_H + +#include "Python.h" +#include "python25compat.h" + +#if PY_MAJOR_VERSION >= 3 + #define IS_PY3K + + #define PyInt_Type PyLong_Type + #define PyInt_Check PyLong_Check + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsUnsignedLongLongMask PyLong_AsLongLong + #define PyInt_FromLong PyLong_FromLong + #define PyInt_AsLong PyLong_AsLong + #define SbkNumber_Check PyNumber_Check + #define Py_TPFLAGS_CHECKTYPES 0 + + #define SBK_NB_BOOL(x) (x).nb_bool + #define SBK_PyMethod_New PyMethod_New + #define PyInt_AsSsize_t(x) PyLong_AsSsize_t(x) + #define PyString_Type PyUnicode_Type + +#else + // Note: if there wasn't for the old-style classes, only a PyNumber_Check would suffice. + #define SbkNumber_Check(X) \ + (PyNumber_Check(X) && (!PyInstance_Check(X) || PyObject_HasAttrString(X, "__trunc__"))) + #define SBK_NB_BOOL(x) (x).nb_nonzero + #define SBK_STR_NAME "str" + #define SBK_PyMethod_New(X, Y) PyMethod_New(X, Y, reinterpret_cast(Py_TYPE(Y))) + + #define Py_hash_t long +#endif + +#endif diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp new file mode 100644 index 000000000..598bccc46 --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkstring.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "sbkstring.h" +#include "autodecref.h" + +namespace Shiboken +{ + +namespace String +{ + +bool checkType(PyTypeObject* type) +{ + return type == &PyUnicode_Type +#if PY_MAJOR_VERSION < 3 + || type == &PyString_Type +#endif + ; +} + +bool check(PyObject* obj) +{ + return obj == Py_None || +#if PY_MAJOR_VERSION < 3 + PyString_Check(obj) || +#endif + PyUnicode_Check(obj); +} + +bool checkChar(PyObject* pyobj) +{ + if (check(pyobj) && (len(pyobj) == 1)) + return true; + + return false; +} + +bool isConvertible(PyObject* obj) +{ + return check(obj); +} + +PyObject* fromCString(const char* value) +{ +#ifdef IS_PY3K + return PyUnicode_FromString(value); +#else + return PyBytes_FromString(value); +#endif +} + +PyObject* fromCString(const char* value, int len) +{ +#ifdef IS_PY3K + return PyUnicode_FromStringAndSize(value, len); +#else + return PyBytes_FromStringAndSize(value, len); +#endif +} + +const char* toCString(PyObject* str, Py_ssize_t* len) +{ + if (str == Py_None) + return NULL; +#ifdef IS_PY3K + if (PyUnicode_Check(str)) { + if (len) { + // We need to encode the unicode string into utf8 to know the size of returned char*. + Shiboken::AutoDecRef uniStr(PyUnicode_AsUTF8String(str)); + *len = PyBytes_GET_SIZE(uniStr.object()); + } + // Return unicode from str instead of uniStr, because the lifetime of the returned pointer + // depends on the lifetime of str. + return _PyUnicode_AsString(str); + } +#endif + if (PyBytes_Check(str)) { + if (len) + *len = PyBytes_GET_SIZE(str); + return PyBytes_AS_STRING(str); + } + return 0; +} + +bool concat(PyObject** val1, PyObject* val2) +{ + if (PyUnicode_Check(*val1) && PyUnicode_Check(val2)) { + PyObject* result = PyUnicode_Concat(*val1, val2); + Py_DECREF(*val1); + *val1 = result; + return true; + } + + if (PyBytes_Check(*val1) && PyBytes_Check(val2)) { + PyBytes_Concat(val1, val2); + return true; + } + +#if PY_MAJOR_VERSION < 3 + if (PyString_Check(*val1) && PyString_Check(val2)) { + PyString_Concat(val1, val2); + return true; + } +#endif + return false; +} + +PyObject* fromFormat(const char* format, ...) +{ + va_list argp; + va_start(argp, format); + PyObject* result = 0; +#ifdef IS_PY3K + result = PyUnicode_FromFormatV(format, argp); +#else + result = PyString_FromFormatV(format, argp); +#endif + va_end(argp); + return result; +} + +PyObject* fromStringAndSize(const char* str, Py_ssize_t size) +{ +#ifdef IS_PY3K + return PyUnicode_FromStringAndSize(str, size); +#else + return PyString_FromStringAndSize(str, size); +#endif +} + +int compare(PyObject* val1, const char* val2) +{ + if (PyUnicode_Check(val1)) +#ifdef IS_PY3K + return PyUnicode_CompareWithASCIIString(val1, val2); +#else + { + PyObject* uVal2 = PyUnicode_FromString(val2); + bool result = PyUnicode_Compare(val1, uVal2); + Py_XDECREF(uVal2); + return result; + } + if (PyString_Check(val1)) + return strcmp(PyString_AS_STRING(val1), val2); +#endif + return 0; + +} + +Py_ssize_t len(PyObject* str) +{ + if (str == Py_None) + return 0; + + if (PyUnicode_Check(str)) + return PyUnicode_GET_SIZE(str); + + if (PyBytes_Check(str)) + return PyBytes_GET_SIZE(str); + return 0; +} + +} // namespace String + +} // namespace Shiboken diff --git a/sources/shiboken2/libshiboken/sbkstring.h b/sources/shiboken2/libshiboken/sbkstring.h new file mode 100644 index 000000000..0d498da6d --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkstring.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SBKSTRING_H +#define SBKSTRING_H + +#include "sbkpython.h" +#include "shibokenmacros.h" + +#if PY_MAJOR_VERSION >= 3 + #define SBK_STR_NAME "unicode" +#else + #define SBK_STR_NAME "str" +#endif + +namespace Shiboken +{ +namespace String +{ + LIBSHIBOKEN_API bool check(PyObject* obj); + LIBSHIBOKEN_API bool checkType(PyTypeObject* obj); + LIBSHIBOKEN_API bool checkChar(PyObject* obj); + LIBSHIBOKEN_API bool isConvertible(PyObject* obj); + LIBSHIBOKEN_API PyObject* fromCString(const char* value); + LIBSHIBOKEN_API PyObject* fromCString(const char* value, int len); + LIBSHIBOKEN_API const char* toCString(PyObject* str, Py_ssize_t* len = 0); + LIBSHIBOKEN_API bool concat(PyObject** val1, PyObject* val2); + LIBSHIBOKEN_API PyObject* fromFormat(const char* format, ...); + LIBSHIBOKEN_API PyObject* fromStringAndSize(const char* str, Py_ssize_t size); + LIBSHIBOKEN_API int compare(PyObject* val1, const char* val2); + LIBSHIBOKEN_API Py_ssize_t len(PyObject* str); + +} // namespace String +} // namespace Shiboken + + +#endif + + diff --git a/sources/shiboken2/libshiboken/sbkversion.h.in b/sources/shiboken2/libshiboken/sbkversion.h.in new file mode 100644 index 000000000..589c5ac26 --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkversion.h.in @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SBKVERSION_H +#define SBKVERSION_H + +#define SHIBOKEN_VERSION "@shiboken_MAJOR_VERSION@.@shiboken_MINOR_VERSION@.@shiboken_MICRO_VERSION@" +#define SHIBOKEN_MAJOR_VERSION @shiboken_MAJOR_VERSION@ +#define SHIBOKEN_MINOR_VERSION @shiboken_MINOR_VERSION@ +#define SHIBOKEN_MICRO_VERSION @shiboken_MICRO_VERSION@ +#define SHIBOKEN_RELEASE_LEVEL "final" +#define SHIBOKEN_SERIAL 0 + +#endif diff --git a/sources/shiboken2/libshiboken/shiboken.h b/sources/shiboken2/libshiboken/shiboken.h new file mode 100644 index 000000000..2738bf51f --- /dev/null +++ b/sources/shiboken2/libshiboken/shiboken.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SHIBOKEN_H +#define SHIBOKEN_H + +#include "sbkpython.h" +#include "autodecref.h" +#include "basewrapper.h" +#include "bindingmanager.h" +#include "conversions.h" +#include "gilstate.h" +#include "threadstatesaver.h" +#include "helper.h" +#include "sbkconverter.h" +#include "sbkenum.h" +#include "sbkmodule.h" +#include "sbkstring.h" +#include "shibokenmacros.h" +#include "typeresolver.h" +#include "shibokenbuffer.h" + +#endif // SHIBOKEN_H + diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.cpp b/sources/shiboken2/libshiboken/shibokenbuffer.cpp new file mode 100644 index 000000000..6cc617668 --- /dev/null +++ b/sources/shiboken2/libshiboken/shibokenbuffer.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "shibokenbuffer.h" +#include +#include + +bool Shiboken::Buffer::checkType(PyObject* pyObj) +{ + return PyObject_CheckReadBuffer(pyObj); +} + +void* Shiboken::Buffer::getPointer(PyObject* pyObj, Py_ssize_t* size) +{ + +#ifdef IS_PY3K + Py_buffer view; + if (PyObject_GetBuffer(pyObj, &view, PyBUF_ND) == 0) { + if (size) + *size = view.len; + return view.buf; + } else { + return 0; + } +#else + const void* buffer = 0; + Py_ssize_t bufferSize = 0; + + PyObject_AsReadBuffer(pyObj, &buffer, &bufferSize); + + if (size) + *size = bufferSize; + return const_cast(buffer); +#endif +} + +PyObject* Shiboken::Buffer::newObject(void* memory, Py_ssize_t size, Type type) +{ + if (size == 0) + Py_RETURN_NONE; +#ifdef IS_PY3K + Py_buffer view; + memset(&view, 0, sizeof(Py_buffer)); + view.buf = memory; + view.len = size; + view.readonly = type == Shiboken::Buffer::ReadOnly; + view.ndim = 1; + view.itemsize = sizeof(char); + Py_ssize_t shape[] = { size }; + view.shape = shape; + return PyMemoryView_FromBuffer(&view); +#else + return type == ReadOnly ? PyBuffer_FromMemory(memory, size) : PyBuffer_FromReadWriteMemory(memory, size); +#endif +} + +PyObject* Shiboken::Buffer::newObject(const void* memory, Py_ssize_t size) +{ + return newObject(const_cast(memory), size, ReadOnly); +} diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.h b/sources/shiboken2/libshiboken/shibokenbuffer.h new file mode 100644 index 000000000..18d86c6e1 --- /dev/null +++ b/sources/shiboken2/libshiboken/shibokenbuffer.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SHIBOKEN_BUFFER_H +#define SHIBOKEN_BUFFER_H + +#include "sbkpython.h" +#include "shibokenmacros.h" + +namespace Shiboken +{ + +namespace Buffer +{ + enum Type { + ReadOnly, + WriteOnly, + ReadWrite + }; + + /** + * Creates a new Python buffer pointing to a contiguous memory block at + * \p memory of size \p size. + */ + LIBSHIBOKEN_API PyObject* newObject(void* memory, Py_ssize_t size, Type type); + + /** + * Creates a new read only Python buffer pointing to a contiguous memory block at + * \p memory of size \p size. + */ + LIBSHIBOKEN_API PyObject* newObject(const void* memory, Py_ssize_t size); + + /** + * Check if is ok to use \p pyObj as argument in all function under Shiboken::Buffer namespace. + */ + LIBSHIBOKEN_API bool checkType(PyObject* pyObj); + + /** + * Returns a pointer to the memory pointed by the buffer \p pyObj, \p size is filled with the buffer + * size if not null. + * + * If the \p pyObj is a non-contiguous buffer a Python error is set. + */ + LIBSHIBOKEN_API void* getPointer(PyObject* pyObj, Py_ssize_t* size = 0); + +} // namespace Buffer +} // namespace Shiboken + +#endif diff --git a/sources/shiboken2/libshiboken/shibokenmacros.h b/sources/shiboken2/libshiboken/shibokenmacros.h new file mode 100644 index 000000000..acd8f6ada --- /dev/null +++ b/sources/shiboken2/libshiboken/shibokenmacros.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SHIBOKENMACROS_H +#define SHIBOKENMACROS_H + +// LIBSHIBOKEN_API macro is used for the public API symbols. +#if defined _WIN32 + #if LIBSHIBOKEN_EXPORTS + #define LIBSHIBOKEN_API __declspec(dllexport) + #else + #ifdef _MSC_VER + #define LIBSHIBOKEN_API __declspec(dllimport) + #endif + #endif + #define SBK_DEPRECATED(func) __declspec(deprecated) func +#elif __GNUC__ >= 4 + #define LIBSHIBOKEN_API __attribute__ ((visibility("default"))) + #define SBK_DEPRECATED(func) func __attribute__ ((deprecated)) +#endif + +#ifndef LIBSHIBOKEN_API + #define LIBSHIBOKEN_API + #define SBK_DEPRECATED(func) func +#endif + +#endif diff --git a/sources/shiboken2/libshiboken/threadstatesaver.cpp b/sources/shiboken2/libshiboken/threadstatesaver.cpp new file mode 100644 index 000000000..3d3ba81ab --- /dev/null +++ b/sources/shiboken2/libshiboken/threadstatesaver.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "threadstatesaver.h" + +namespace Shiboken +{ + +ThreadStateSaver::ThreadStateSaver() + : m_threadState(0) + {} + +ThreadStateSaver::~ThreadStateSaver() +{ + restore(); +} + +void ThreadStateSaver::save() +{ + if (PyEval_ThreadsInitialized()) + m_threadState = PyEval_SaveThread(); +} + +void ThreadStateSaver::restore() +{ + if (m_threadState) { + PyEval_RestoreThread(m_threadState); + m_threadState = 0; + } +} + +} // namespace Shiboken + diff --git a/sources/shiboken2/libshiboken/threadstatesaver.h b/sources/shiboken2/libshiboken/threadstatesaver.h new file mode 100644 index 000000000..3fe595d95 --- /dev/null +++ b/sources/shiboken2/libshiboken/threadstatesaver.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef THREADSTATESAVER_H +#define THREADSTATESAVER_H + +#include "sbkpython.h" +#include + +namespace Shiboken +{ + +class LIBSHIBOKEN_API ThreadStateSaver +{ +public: + ThreadStateSaver(); + ~ThreadStateSaver(); + void save(); + void restore(); +private: + PyThreadState* m_threadState; + + ThreadStateSaver(const ThreadStateSaver&); + ThreadStateSaver& operator=(const ThreadStateSaver&); +}; + +} // namespace Shiboken + +#endif // THREADSTATESAVER_H + diff --git a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp new file mode 100644 index 000000000..c3e25014e --- /dev/null +++ b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "sbkconverter.h" +#include "sbkconverter_p.h" +#include "basewrapper_p.h" + +#include "sbkdbg.h" + +namespace Shiboken { +namespace Conversions { + +static SbkConverter* createConverterObject(PyTypeObject* type, + PythonToCppFunc toCppPointerConvFunc, + IsConvertibleToCppFunc toCppPointerCheckFunc, + CppToPythonFunc pointerToPythonFunc, + CppToPythonFunc copyToPythonFunc) +{ + SbkConverter* converter = new SbkConverter; + converter->pythonType = type; + + converter->pointerToPython = pointerToPythonFunc; + converter->copyToPython = copyToPythonFunc; + + converter->toCppPointerConversion = std::make_pair(toCppPointerCheckFunc, toCppPointerConvFunc); + converter->toCppConversions.clear(); + + return converter; +} + +SbkConverter* createConverter(SbkObjectType* type, + PythonToCppFunc toCppPointerConvFunc, + IsConvertibleToCppFunc toCppPointerCheckFunc, + CppToPythonFunc pointerToPythonFunc, + CppToPythonFunc copyToPythonFunc) +{ + SbkConverter* converter = createConverterObject((PyTypeObject*)type, + toCppPointerConvFunc, toCppPointerCheckFunc, + pointerToPythonFunc, copyToPythonFunc); + type->d->converter = converter; + return converter; +} + +void deleteConverter(SbkConverter* converter) +{ + if (converter) { + converter->toCppConversions.clear(); + delete converter; + } +} + +void addPythonToCppValueConversion(SbkConverter* converter, + PythonToCppFunc pythonToCppFunc, + IsConvertibleToCppFunc isConvertibleToCppFunc) +{ + converter->toCppConversions.push_back(std::make_pair(isConvertibleToCppFunc, pythonToCppFunc)); +} +void addPythonToCppValueConversion(SbkObjectType* type, + PythonToCppFunc pythonToCppFunc, + IsConvertibleToCppFunc isConvertibleToCppFunc) +{ + addPythonToCppValueConversion(type->d->converter, pythonToCppFunc, isConvertibleToCppFunc); +} + +PyObject* pointerToPython(SbkObjectType* type, const void* cppIn) +{ + if (!cppIn) + Py_RETURN_NONE; + return type->d->converter->pointerToPython(cppIn); +} + +static inline PyObject* CopyCppToPython(SbkConverter* converter, const void* cppIn) +{ + assert(cppIn); + return converter->copyToPython(cppIn); +} +PyObject* copyToPython(SbkObjectType* type, const void* cppIn) +{ + return CopyCppToPython(type->d->converter, cppIn); +} +PyObject* toPython(SbkConverter* converter, const void* cppIn) +{ + return CopyCppToPython(converter, cppIn); +} + +PyObject* referenceToPython(SbkObjectType* type, const void* cppIn) +{ + assert(cppIn); + PyObject* pyOut = (PyObject*)BindingManager::instance().retrieveWrapper(cppIn); + if (pyOut) { + Py_INCREF(pyOut); + return pyOut; + } + // If it is Value Type, return a copy of the C++ object. + if (type->d->converter->copyToPython) + return type->d->converter->copyToPython(cppIn); + // If it is an Object Type, return a copy of the C++ object. + return type->d->converter->pointerToPython(cppIn); +} + +PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType* type, PyObject* pyIn) +{ + assert(pyIn); + return type->d->converter->toCppPointerConversion.first(pyIn); +} + +static inline PythonToCppFunc IsPythonToCppConvertible(SbkConverter* converter, PyObject* pyIn) +{ + assert(pyIn); + ToCppConversionList& convs = converter->toCppConversions; + for (ToCppConversionList::iterator conv = convs.begin(); conv != convs.end(); ++conv) { + PythonToCppFunc toCppFunc = 0; + if ((toCppFunc = (*conv).first(pyIn))) + return toCppFunc; + } + return 0; +} +PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType* type, PyObject* pyIn) +{ + return IsPythonToCppConvertible(type->d->converter, pyIn); +} +PythonToCppFunc isPythonToCppConvertible(SbkConverter* converter, PyObject* pyIn) +{ + return IsPythonToCppConvertible(converter, pyIn); +} + +PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType* type, PyObject* pyIn) +{ + if (pyIn != Py_None) { + PythonToCppFunc toCpp = isPythonToCppPointerConvertible(type, pyIn); + if (toCpp) + return toCpp; + } + return isPythonToCppValueConvertible(type, pyIn); +} + +void nonePythonToCppNullPtr(PyObject*, void* cppOut) +{ + assert(cppOut); + *((void**)cppOut) = 0; +} + +void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut) +{ + assert(pyIn); + assert(cppOut); + SbkObjectType* inType = (SbkObjectType*)pyIn->ob_type; + if (ObjectType::hasCast(inType)) + *((void**)cppOut) = ObjectType::cast(inType, (SbkObject*)pyIn, (PyTypeObject*)type); + else + *((void**)cppOut) = Object::cppPointer((SbkObject*)pyIn, (PyTypeObject*)type); +} + +bool isImplicitConversion(SbkObjectType* type, PythonToCppFunc toCppFunc) +{ + // This is the Object Type or Value Type conversion that only + // retrieves the C++ pointer held in the Python wrapper. + if (toCppFunc == type->d->converter->toCppPointerConversion.second) + return false; + + // Object Types doesn't have any kind of value conversion, + // only C++ pointer retrieval. + if (type->d->converter->toCppConversions.empty()) + return false; + + // The first conversion of the non-pointer conversion list is + // a Value Type's copy to C++ function, which is not an implicit + // conversion. + // Otherwise it must be one of the implicit conversions. + // Note that we don't check if the Python to C++ conversion is in + // the list of the type's conversions, for it is expected that the + // caller knows what he's doing. + ToCppConversionList::iterator conv = type->d->converter->toCppConversions.begin(); + return toCppFunc != (*conv).second; +} + +} } // namespace Shiboken::Conversions diff --git a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h new file mode 100644 index 000000000..d4bbbca1d --- /dev/null +++ b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef SBK_CONVERTER_H +#define SBK_CONVERTER_H + +#include +#include +#include "shibokenmacros.h" +#include "basewrapper.h" + +extern "C" +{ + +/** + * SbkConverter is used to perform type conversions from C++ + * to Python and vice-versa;.and it is also used for type checking. + * SbkConverter is a private structure that must be accessed + * using the functions provided by the converter API. + */ +struct SbkConverter; + +/** + * Given a void pointer to a C++ object, this function must return + * the proper Python object. It may be either an existing wrapper + * for the C++ object, or a newly create one. Or even the Python + * equivalent of the C++ value passed in the argument. + * + * C++ -> Python + */ +typedef PyObject* (*CppToPythonFunc)(const void*); + +/** + * This function converts a Python object to a C++ value, it may be + * a pointer, value, class, container or primitive type, passed via + * a void pointer, that will be cast properly inside the function. + * This function is usually returned by an IsConvertibleToCppFunc + * function, or obtained knowing the type of the Python object input, + * thus it will not check the Python object type, and will expect + * the void pointer to be pointing to a proper variable. + * + * Python -> C++ + */ +typedef void (*PythonToCppFunc)(PyObject*,void*); + +/** + * Checks if the Python object passed in the argument is convertible to a + * C++ type defined inside the function, it returns the converter function + * that will transform a Python argument into a C++ value. + * It returns NULL if the Python object is not convertible to the C++ type + * that the function represents. + * + * Python -> C++ ? + */ +typedef PythonToCppFunc (*IsConvertibleToCppFunc)(PyObject*); + +} // extern "C" + + +namespace Shiboken { +namespace Conversions { + +/** + * Creates a converter for a wrapper type. + * \param type A Shiboken.ObjectType that will receive the new converter. + * \param toCppPointerConvFunc Function to retrieve the C++ pointer held by a Python wrapper. + * \param toCppPointerCheckFunc Check and return the retriever function of the C++ pointer held by a Python wrapper. + * \param pointerToPythonFunc Function to convert a C++ object to a Python \p type wrapper, keeping their identity. + * \param copyToPythonFunc Function to convert a C++ object to a Python \p type, copying the object. + * \returns The new converter referred by the wrapper \p type. + */ +LIBSHIBOKEN_API SbkConverter* createConverter(SbkObjectType* type, + PythonToCppFunc toCppPointerConvFunc, + IsConvertibleToCppFunc toCppPointerCheckFunc, + CppToPythonFunc pointerToPythonFunc, + CppToPythonFunc copyToPythonFunc = 0); + +LIBSHIBOKEN_API void deleteConverter(SbkConverter* converter); + +/** + * Adds a new conversion of a Python object to a C++ value. + * This is used in copy and implicit conversions. + */ +LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkConverter* converter, + PythonToCppFunc pythonToCppFunc, + IsConvertibleToCppFunc isConvertibleToCppFunc); +LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkObjectType* type, + PythonToCppFunc pythonToCppFunc, + IsConvertibleToCppFunc isConvertibleToCppFunc); + +// C++ -> Python --------------------------------------------------------------------------- + +/** + * Retrieves the Python wrapper object for the given \p cppIn C++ pointer object. + * This function is used only for Value and Object Types. + * Example usage: + * TYPE* var; + * PyObject* pyVar = pointerToPython(SBKTYPE, &var); + */ +LIBSHIBOKEN_API PyObject* pointerToPython(SbkObjectType* type, const void* cppIn); + +/** + * Retrieves the Python wrapper object for the given C++ value pointed by \p cppIn. + * This function is used only for Value Types. + * Example usage: + * TYPE var; + * PyObject* pyVar = copyToPython(SBKTYPE, &var); + */ +LIBSHIBOKEN_API PyObject* copyToPython(SbkObjectType* type, const void* cppIn); + +// TODO:WRITEDOCSTRING - used only for Value Types - cppIn must point to a value +/** + * Retrieves the Python wrapper object for the given C++ reference pointed by \p cppIn. + * This function is used only for Value and Object Types. + * It differs from pointerToPython() for not checking for a NULL pointer. + * Example usage: + * TYPE& var = SOMETHING; + * PyObject* pyVar = copyToPython(SBKTYPE, &var); + */ +LIBSHIBOKEN_API PyObject* referenceToPython(SbkObjectType* type, const void* cppIn); + +// TODO:WRITEDOCSTRING - used only for Primitives and Containers (and Value Types) - cppIn must point to a primitive, container or value type +/// This is the same as copyToPython function. +LIBSHIBOKEN_API PyObject* toPython(SbkConverter* converter, const void* cppIn); + +// Python -> C++ convertibility checks ----------------------------------------------------- + +// TODO:WRITEDOCSTRING +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType* type, PyObject* pyIn); + +// TODO:WRITEDOCSTRING- Returns a Python to C++ conversion function if true, or NULL if false. +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType* type, PyObject* pyIn); + +// TODO:WRITEDOCSTRING- Returns a Python to C++ conversion function if true, or NULL if false. +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType* type, PyObject* pyIn); + +/// This is the same as isPythonToCppValueConvertible function. +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(SbkConverter* converter, PyObject* pyIn); + +// Python -> C++ --------------------------------------------------------------------------- + +// TODO:WRITEDOCSTRING - function used by the generated [TYPE]_PythonToCpp_[TYPE]_PTR +LIBSHIBOKEN_API void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut); + +// TODO:WRITEDOCSTRING - function used by the generated isConvertible when the PyObject is None, +// making a C++ NULL pointer the result of the toCpp function call. +// DRAFT: When the Python object is a Py_None, it's C++ conversion is always a NULL pointer. +LIBSHIBOKEN_API void nonePythonToCppNullPtr(PyObject*, void* cppOut); + +// TODO:WRITEDOCSTRING - tells if \p toCpp is an implicit conversion. +LIBSHIBOKEN_API bool isImplicitConversion(SbkObjectType* type, PythonToCppFunc toCpp); + +} } // namespace Shiboken::Conversions + +#endif // SBK_CONVERTER_H diff --git a/sources/shiboken2/libshiboken/typeresolver.cpp b/sources/shiboken2/libshiboken/typeresolver.cpp new file mode 100644 index 000000000..b23eb6371 --- /dev/null +++ b/sources/shiboken2/libshiboken/typeresolver.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 "typeresolver.h" +#include "sbkdbg.h" +#include +#include +#include +#include "basewrapper_p.h" + +using namespace Shiboken; + +typedef std::unordered_map TypeResolverMap; +static TypeResolverMap typeResolverMap; + +struct TypeResolver::TypeResolverPrivate +{ + CppToPythonFunc cppToPython; + PythonToCppFunc pythonToCpp; + PyTypeObject* pyType; +}; + +static void deinitTypeResolver() +{ + for (TypeResolverMap::const_iterator it = typeResolverMap.begin(); it != typeResolverMap.end(); ++it) + delete it->second; + typeResolverMap.clear(); +} + +void Shiboken::initTypeResolver() +{ + assert(typeResolverMap.empty()); + std::atexit(deinitTypeResolver); +} + +TypeResolver::TypeResolver() : m_d(new TypeResolverPrivate) +{ +} + +TypeResolver* TypeResolver::createTypeResolver(const char* typeName, + CppToPythonFunc cppToPy, + PythonToCppFunc pyToCpp, + PyTypeObject* pyType) +{ + TypeResolver*& tr = typeResolverMap[typeName]; + if (!tr) { + tr = new TypeResolver; + tr->m_d->cppToPython = cppToPy; + tr->m_d->pythonToCpp = pyToCpp; + tr->m_d->pyType = pyType; + + /* + * Note: + * + * Value types are also registered as object types, but the generator *always* first register the value + * type version in the TypeResolver and it *must* always do it! otherwise this code wont work. + */ + if (pyType && PyType_IsSubtype(pyType, reinterpret_cast(&SbkObject_Type))) { + SbkObjectType* sbkType = reinterpret_cast(pyType); + // TODO-CONVERTERS: to be deprecated + if (!sbkType->d->type_behaviour) { + const size_t len = strlen(typeName); + sbkType->d->type_behaviour = typeName[len -1] == '*' ? BEHAVIOUR_OBJECTTYPE : BEHAVIOUR_VALUETYPE; + } + } + } + return tr; +} + +TypeResolver::~TypeResolver() +{ + delete m_d; +} + +TypeResolver* TypeResolver::get(const char* typeName) +{ + TypeResolverMap::const_iterator it = typeResolverMap.find(typeName); + if (it != typeResolverMap.end()) { + return it->second; + } else { + if (Py_VerboseFlag > 0) + SbkDbg() << "Can't find type resolver for " << typeName; + return 0; + } +} + +void TypeResolver::toCpp(PyObject* pyObj, void** place) +{ + m_d->pythonToCpp(pyObj, place); +} + +PyObject* TypeResolver::toPython(void* cppObj) +{ + return m_d->cppToPython(cppObj); +} + +PyTypeObject* TypeResolver::pythonType() +{ + return m_d->pyType; +} + +TypeResolver::Type TypeResolver::getType(const char* name) +{ + const size_t len = strlen(name); + bool isObjTypeName = name[len - 1] == '*'; + if (TypeResolver::get(name)) { + // great, we found the type in our first attempt! + return isObjTypeName ? ObjectType : ValueType; + } else { + // Type not found... let's copy the string. + std::string typeName(name); + if (isObjTypeName) + typeName.erase(len - 1, 1); + else + typeName += '*'; + isObjTypeName = !isObjTypeName; + + if (TypeResolver::get(typeName.c_str())) + return isObjTypeName ? ObjectType : ValueType; + else + return UnknownType; + } +} + diff --git a/sources/shiboken2/libshiboken/typeresolver.h b/sources/shiboken2/libshiboken/typeresolver.h new file mode 100644 index 000000000..bc56522fe --- /dev/null +++ b/sources/shiboken2/libshiboken/typeresolver.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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$ +** +****************************************************************************/ + +#ifndef TYPERESOLVER_H +#define TYPERESOLVER_H + +#include "shibokenmacros.h" +#include "conversions.h" + +namespace Shiboken +{ + +/* To C++ convertion functions. */ +template +inline void pythonToValueType(PyObject* pyobj, void** data) +{ + *reinterpret_cast(*data) = Shiboken::Converter::toCpp(pyobj); +} + +template +inline void pythonToObjectType(PyObject* pyobj, void** data) +{ + *reinterpret_cast(*data) = Shiboken::Converter::toCpp(pyobj); +} + +template +inline PyObject* objectTypeToPython(void* cptr) +{ + return Shiboken::Converter::toPython(*reinterpret_cast(cptr)); +} + +template +inline PyObject* referenceTypeToPython(void* cptr) +{ + // cptr comes the same way it come when we have a value type, but + // we deliver a Python object of a reference + return Shiboken::Converter::toPython(*reinterpret_cast(cptr)); +} + +/** +* \internal This function is not part of the public API. +* Initialize the TypeResource internal cache. +*/ +void initTypeResolver(); + +class LIBSHIBOKEN_API TypeResolver +{ +public: + enum Type + { + ObjectType, + ValueType, + UnknownType + }; + + typedef PyObject* (*CppToPythonFunc)(void*); + typedef void (*PythonToCppFunc)(PyObject*, void**); + + ~TypeResolver(); + + template + static TypeResolver* createValueTypeResolver(const char* typeName) + { + return createTypeResolver(typeName, &Shiboken::Converter::toPython, &pythonToValueType, SbkType()); + } + + template + static TypeResolver* createObjectTypeResolver(const char* typeName) + { + return createTypeResolver(typeName, &objectTypeToPython, &pythonToObjectType, SbkType()); + } + + /** + * This kind of type resolver is used only when we have a signal with a reference in their arguments + * like on QSqlTableModel::primeInsert. + */ + template + static TypeResolver* createReferenceTypeResolver(const char* typeName) + { + return createTypeResolver(typeName, &referenceTypeToPython, &pythonToValueType, SbkType()); + } + + static Type getType(const char* name); + static TypeResolver* get(const char* typeName); + + PyObject* toPython(void* cppObj); + void toCpp(PyObject* pyObj, void** place); + PyTypeObject* pythonType(); + +private: + struct TypeResolverPrivate; + TypeResolverPrivate* m_d; + + TypeResolver(); + // disable object copy + TypeResolver(const TypeResolver&); + TypeResolver& operator=(const TypeResolver&); + + static TypeResolver* createTypeResolver(const char* typeName, CppToPythonFunc cppToPy, PythonToCppFunc pyToCpp, PyTypeObject* pyType); +}; +} + +#endif diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt new file mode 100644 index 000000000..7e90b51ab --- /dev/null +++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt @@ -0,0 +1,40 @@ +project(shibokenmodule) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/shibokenmodule.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/shibokenmodule.txt" @ONLY) + + +set(sample_SRC +${CMAKE_CURRENT_BINARY_DIR}/shiboken2/shiboken2_module_wrapper.cpp +) + +add_custom_command(OUTPUT ${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 +COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/shibokenmodule.txt ${GENERATOR_EXTRA_FLAGS} +WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +COMMENT "Running generator for 'shiboken2'..." +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR} + ${SBK_PYTHON_INCLUDE_DIR} + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) +add_library(shibokenmodule MODULE ${sample_SRC}) +set_property(TARGET shibokenmodule PROPERTY PREFIX "") +set_property(TARGET shibokenmodule PROPERTY OUTPUT_NAME "shiboken2") +if(WIN32) + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set_property(TARGET shibokenmodule PROPERTY OUTPUT_NAME "shiboken2_d") + endif() + set_property(TARGET shibokenmodule PROPERTY SUFFIX ".pyd") +endif() +target_link_libraries(shibokenmodule + ${SBK_PYTHON_LIBRARIES} + libshiboken) + +add_dependencies(shibokenmodule shiboken2) + +install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}) \ No newline at end of file diff --git a/sources/shiboken2/shibokenmodule/nothing.h b/sources/shiboken2/shibokenmodule/nothing.h new file mode 100644 index 000000000..e69de29bb diff --git a/sources/shiboken2/shibokenmodule/shibokenmodule.txt.in b/sources/shiboken2/shibokenmodule/shibokenmodule.txt.in new file mode 100644 index 000000000..c5adc6091 --- /dev/null +++ b/sources/shiboken2/shibokenmodule/shibokenmodule.txt.in @@ -0,0 +1,16 @@ +[generator-project] + +generator-set = shiboken + +header-file = @CMAKE_CURRENT_SOURCE_DIR@/nothing.h +typesystem-file = @CMAKE_CURRENT_SOURCE_DIR@/typesystem_shiboken.xml + +output-directory = @CMAKE_CURRENT_BINARY_DIR@ + +# include-path = @libsample_SOURCE_DIR@ + +typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@ + +avoid-protected-hack +#enable-parent-ctor-heuristic +#use-isnull-as-nb_nonzero diff --git a/sources/shiboken2/shibokenmodule/typesystem_shiboken.xml b/sources/shiboken2/shibokenmodule/typesystem_shiboken.xml new file mode 100644 index 000000000..18ab52e80 --- /dev/null +++ b/sources/shiboken2/shibokenmodule/typesystem_shiboken.xml @@ -0,0 +1,120 @@ + + + + + + + + + + bool isValid = Shiboken::Object::isValid(%1, false); + %PYARG_0 = %CONVERTTOPYTHON[bool](isValid); + + + + + + Shiboken::Object::invalidate(%1); + + + + + + if (Shiboken::ObjectType::checkType((PyTypeObject*)%2)) + %PYARG_0 = Shiboken::Object::newObject((SbkObjectType*)%2, (void*)%1, false, true); + else + PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type."); + + + + + + if (Shiboken::Object::checkType(%1)) { + std::vector<void*> ptrs = Shiboken::Object::cppPointers((SbkObject*)%1); + %PYARG_0 = PyTuple_New(ptrs.size()); + for (std::size_t i = 0; i < ptrs.size(); ++i) + PyTuple_SET_ITEM(%PYARG_0, i, PyLong_FromVoidPtr(ptrs[i])); + } else { + PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type."); + } + + + + + + if (Shiboken::Object::checkType(%1)) { + Shiboken::Object::callCppDestructors((SbkObject*)%1); + } else { + PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type."); + } + + + + + + if (Shiboken::Object::checkType(%1)) { + bool hasOwnership = Shiboken::Object::hasOwnership((SbkObject*)%1); + %PYARG_0 = %CONVERTTOPYTHON[bool](hasOwnership); + } else { + PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type."); + } + + + + + + if (Shiboken::Object::checkType(%1)) { + bool wasCreatedByPython = Shiboken::Object::wasCreatedByPython((SbkObject*)%1); + %PYARG_0 = %CONVERTTOPYTHON[bool](wasCreatedByPython); + } else { + PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type."); + } + + + + + + if (!Shiboken::Object::checkType(%1)) { + %PYARG_0 = Shiboken::String::fromCString("Ordinary Python type."); + } else { + std::string str = Shiboken::Object::info((SbkObject*)%1); + %PYARG_0 = Shiboken::String::fromCString(str.c_str()); + } + + + + + + std::set<PyObject*> setAll = Shiboken::BindingManager::instance().getAllPyObjects(); + PyObject* listAll = PyList_New(0); + if (listAll == NULL) + return NULL; + + const std::set<PyObject*>::iterator end = setAll.end(); + for (std::set<PyObject*>::iterator iter = setAll.begin(); iter != end; ++iter) { + if (*iter != NULL) { + if (PyList_Append(listAll, *iter) != 0) { + Py_DECREF(listAll); + return NULL; + } + } + } + return listAll; + + + + + + + + // Add __version__ and __version_info__ attributes to the module + PyObject* version = PyTuple_New(5); + PyTuple_SET_ITEM(version, 0, PyInt_FromLong(SHIBOKEN_MAJOR_VERSION)); + PyTuple_SET_ITEM(version, 1, PyInt_FromLong(SHIBOKEN_MINOR_VERSION)); + PyTuple_SET_ITEM(version, 2, PyInt_FromLong(SHIBOKEN_MICRO_VERSION)); + PyTuple_SET_ITEM(version, 3, Shiboken::String::fromCString(SHIBOKEN_RELEASE_LEVEL)); + PyTuple_SET_ITEM(version, 4, PyInt_FromLong(SHIBOKEN_SERIAL)); + PyModule_AddObject(module, "__version_info__", version); + PyModule_AddStringConstant(module, "__version__", SHIBOKEN_VERSION); + + diff --git a/sources/shiboken2/tests/CMakeLists.txt b/sources/shiboken2/tests/CMakeLists.txt new file mode 100644 index 000000000..c06c56f6d --- /dev/null +++ b/sources/shiboken2/tests/CMakeLists.txt @@ -0,0 +1,102 @@ +find_package(Qt5 REQUIRED COMPONENTS Core) +include_directories(${Qt5Core_INCLUDE_DIRS}) + +add_subdirectory(libminimal) +if(NOT DEFINED MINIMAL_TESTS) + add_subdirectory(libsample) + add_subdirectory(libsmart) + add_subdirectory(libother) +endif() + +if(WIN32 OR DEFINED AVOID_PROTECTED_HACK) + message(STATUS "Tests will be generated avoiding the protected hack!") + set(GENERATOR_EXTRA_FLAGS --avoid-protected-hack) +else() + message(STATUS "Tests will be generated using the protected hack!") + set(GENERATOR_EXTRA_FLAGS ) +endif() + +add_subdirectory(minimalbinding) +if(NOT DEFINED MINIMAL_TESTS) + add_subdirectory(samplebinding) + add_subdirectory(smartbinding) + add_subdirectory(otherbinding) +endif() + +if(DEFINED MINIMAL_TESTS) + file(GLOB TEST_FILES minimalbinding/*_test.py) +else() + file(GLOB TEST_FILES minimalbinding/*_test.py + samplebinding/*_test.py + otherbinding/*_test.py + smartbinding/*_test.py + shibokenmodule/*_test.py) +endif() +list(SORT TEST_FILES) + +set(test_blacklist "") + +find_package(PythonInterp REQUIRED) +if(NOT CTEST_TESTING_TIMEOUT) + set(CTEST_TESTING_TIMEOUT 60) +endif() + +if(CMAKE_VERSION VERSION_LESS 2.8) + message("CMake version greater than 2.8 necessary to run tests") +else() + if(WIN32) + set(TEST_PYTHONPATH "${smart_BINARY_DIR};${minimal_BINARY_DIR};${sample_BINARY_DIR};${other_BINARY_DIR};${shibokenmodule_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}") + set(TEST_LIBRARY_PATH "$ENV{PATH};${libminimal_BINARY_DIR};${libsample_BINARY_DIR};${libother_BINARY_DIR};${libsmart_BINARY_DIR};${libshiboken_BINARY_DIR}") + set(LIBRARY_PATH_VAR "PATH") + string(REPLACE "\\" "/" TEST_PYTHONPATH "${TEST_PYTHONPATH}") + string(REPLACE "\\" "/" TEST_LIBRARY_PATH "${TEST_LIBRARY_PATH}") + string(REPLACE ";" "\\;" TEST_PYTHONPATH "${TEST_PYTHONPATH}") + string(REPLACE ";" "\\;" TEST_LIBRARY_PATH "${TEST_LIBRARY_PATH}") + else() + set(TEST_PYTHONPATH "${smart_BINARY_DIR}:${minimal_BINARY_DIR}:${sample_BINARY_DIR}:${other_BINARY_DIR}:${shibokenmodule_BINARY_DIR}:${CMAKE_CURRENT_SOURCE_DIR}") + set(TEST_LIBRARY_PATH "$ENV{LD_LIBRARY_PATH}:${libminimal_BINARY_DIR}:${libsample_BINARY_DIR}:${libother_BINARY_DIR}:${libsmart_BINARY_DIR}:${libshiboken_BINARY_DIR}") + set(LIBRARY_PATH_VAR "LD_LIBRARY_PATH") + endif() + foreach(test_file ${TEST_FILES}) + string(REGEX MATCH "/([^/]+)(binding|module)/([^/]+)_test.py" tmp ${test_file}) + set(test_name "${CMAKE_MATCH_1}_${CMAKE_MATCH_3}") + list(FIND test_blacklist ${test_name} expect_fail) + add_test(${test_name} ${PYTHON_EXECUTABLE} ${test_file}) + set_tests_properties(${test_name} PROPERTIES ENVIRONMENT "PYTHONPATH=${TEST_PYTHONPATH};${LIBRARY_PATH_VAR}=${TEST_LIBRARY_PATH}") + set_tests_properties(${test_name} PROPERTIES TIMEOUT ${CTEST_TESTING_TIMEOUT}) + if (${expect_fail} GREATER -1) + set_tests_properties(${test_name} PROPERTIES WILL_FAIL TRUE) + endif() + endforeach() +endif() + +add_subdirectory(dumpcodemodel) + +# FIXME Skipped until add an option to choose the generator +# add_subdirectory(test_generator) + +if (NOT APIEXTRACTOR_DOCSTRINGS_DISABLED) +# project(sphinxtabletest) +# +# # TODO +# set(sphinxtabletest_SRC sphinxtabletest.cpp) +# qt4_automoc(${sphinxtabletest_SRC}) +# +# include_directories(${QT_INCLUDE_DIR} +# ${QT_QTCORE_INCLUDE_DIR} +# ${CMAKE_CURRENT_BINARY_DIR} +# ${qtdoc_generator_SOURCE_DIR}) +# +# add_executable(sphinxtabletest ${sphinxtabletest_SRC}) +# +# target_link_libraries(sphinxtabletest +# ${QT_QTTEST_LIBRARY} +# ${APIEXTRACTOR_LIBRARY} +# qtdoc_generator +# genrunner) +# +# add_test("sphinxtable" sphinxtabletest) +# if (INSTALL_TESTS) +# install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/sphinxtabletest DESTINATION ${TEST_INSTALL_DIR}) +# endif() +endif() diff --git a/sources/shiboken2/tests/dumpcodemodel/CMakeLists.txt b/sources/shiboken2/tests/dumpcodemodel/CMakeLists.txt new file mode 100644 index 000000000..af18cb3c8 --- /dev/null +++ b/sources/shiboken2/tests/dumpcodemodel/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(dumpcodemodel main.cpp) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${apiextractor_SOURCE_DIR} ${Qt5Core_INCLUDE_DIRS}) + +target_link_libraries(dumpcodemodel apiextractor ${Qt5Core_LIBRARIES}) diff --git a/sources/shiboken2/tests/dumpcodemodel/main.cpp b/sources/shiboken2/tests/dumpcodemodel/main.cpp new file mode 100644 index 000000000..13dab6e8a --- /dev/null +++ b/sources/shiboken2/tests/dumpcodemodel/main.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + QCommandLineParser parser; + parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); + parser.setApplicationDescription(QStringLiteral("Code model tester")); + parser.addHelpOption(); + parser.addVersionOption(); + QCommandLineOption verboseOption(QStringLiteral("d"), + QStringLiteral("Display verbose output about types")); + parser.addOption(verboseOption); + parser.addPositionalArgument(QStringLiteral("file"), QStringLiteral("C++ source file")); + + parser.process(app); + const QStringList &positionalArguments = parser.positionalArguments(); + if (positionalArguments.isEmpty()) + parser.showHelp(1); + + QByteArrayList arguments; + std::transform(positionalArguments.cbegin(), positionalArguments.cend(), + std::back_inserter(arguments), QFile::encodeName); + const FileModelItem dom = AbstractMetaBuilderPrivate::buildDom(arguments, 0); + if (dom.isNull()) { + QString message = QLatin1String("Unable to parse ") + positionalArguments.join(QLatin1Char(' ')); + std::cerr << qPrintable(message) << '\n'; + return -2; + } + + QString output; + { + QDebug debug(&output); + if (parser.isSet(verboseOption)) + debug.setVerbosity(3); + debug << dom.data(); + } + std::cout << qPrintable(output) << '\n'; + + return 0; +} diff --git a/sources/shiboken2/tests/libminimal/CMakeLists.txt b/sources/shiboken2/tests/libminimal/CMakeLists.txt new file mode 100644 index 000000000..a25892571 --- /dev/null +++ b/sources/shiboken2/tests/libminimal/CMakeLists.txt @@ -0,0 +1,13 @@ +project(libminimal) + +set(libminimal_SRC +obj.cpp +listuser.cpp +typedef.cpp +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +add_definitions("-DLIBMINIMAL_BUILD") +add_library(libminimal SHARED ${libminimal_SRC}) +set_property(TARGET libminimal PROPERTY PREFIX "") + diff --git a/sources/shiboken2/tests/libminimal/libminimalmacros.h b/sources/shiboken2/tests/libminimal/libminimalmacros.h new file mode 100644 index 000000000..5c9e62e8a --- /dev/null +++ b/sources/shiboken2/tests/libminimal/libminimalmacros.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 LIBMINIMALMACROS_H +#define LIBMINIMALMACROS_H + +#if defined _WIN32 || defined __CYGWIN__ + #if LIBMINIMAL_BUILD + #define LIBMINIMAL_API __declspec(dllexport) + #else + #define LIBMINIMAL_API __declspec(dllimport) + #endif +#else +#if __GNUC__ >= 4 + #define LIBMINIMAL_API __attribute__ ((visibility("default"))) +#else + #define LIBMINIMAL_API +#endif +#endif + +#endif diff --git a/sources/shiboken2/tests/libminimal/listuser.cpp b/sources/shiboken2/tests/libminimal/listuser.cpp new file mode 100644 index 000000000..ec2eb3923 --- /dev/null +++ b/sources/shiboken2/tests/libminimal/listuser.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include +#include "listuser.h" + +std::list +ListUser::createIntList(int num) +{ + std::list retval; + for (int i = 0; i < num; ++i) + retval.push_back(i); + return retval; +} + +int +ListUser::sumIntList(std::list intList) +{ + int total = 0; + for (std::list::iterator iter = intList.begin(); iter != intList.end(); iter++) + total += *iter; + return total; +} + +std::list +ListUser::createMinBoolList(MinBool mb1, MinBool mb2) +{ + std::list retval; + retval.push_back(mb1); + retval.push_back(mb2); + return retval; +} + +MinBool +ListUser::oredMinBoolList(std::list minBoolList) +{ + MinBool result(false); + for (std::list::iterator iter = minBoolList.begin(); iter != minBoolList.end(); iter++) + result |= *iter; + return result; +} + +std::list +ListUser::createValList(int num) +{ + std::list retval; + for (int i = 0; i < num; ++i) + retval.push_back(Val(i)); + return retval; +} + +int +ListUser::sumValList(std::list valList) +{ + int total = 0; + for (std::list::iterator iter = valList.begin(); iter != valList.end(); iter++) + total += iter->valId(); + return total; +} + +std::list +ListUser::createObjList(Obj* o1, Obj* o2) +{ + std::list retval; + retval.push_back(o1); + retval.push_back(o2); + return retval; +} + +int +ListUser::sumObjList(std::list objList) +{ + int total = 0; + for (std::list::iterator iter = objList.begin(); iter != objList.end(); iter++) + total += (*iter)->objId(); + return total; +} + +std::list > +ListUser::createListOfIntLists(int num) +{ + std::list > retval; + for (int i = 0; i < num; ++i) + retval.push_back(createIntList(num)); + return retval; +} + +int +ListUser::sumListOfIntLists(std::list > intListList) +{ + int total = 0; + for (std::list >::iterator it0 = intListList.begin(); it0 != intListList.end(); it0++) { + for (std::list::iterator it1 = (*it0).begin(); it1 != (*it0).end(); it1++) + total += *it1; + } + return total; +} + diff --git a/sources/shiboken2/tests/libminimal/listuser.h b/sources/shiboken2/tests/libminimal/listuser.h new file mode 100644 index 000000000..4138b9f3c --- /dev/null +++ b/sources/shiboken2/tests/libminimal/listuser.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 LISTUSER_H +#define LISTUSER_H + +#include +#include "obj.h" +#include "val.h" +#include "minbool.h" + +#include "libminimalmacros.h" + +struct LIBMINIMAL_API ListUser +{ + virtual ~ListUser() {} + + // List of C++ primitive type items + virtual std::list createIntList(int num); + std::list callCreateIntList(int num) { return createIntList(num); } + virtual int sumIntList(std::list intList); + int callSumIntList(std::list intList) { return sumIntList(intList); } + + // List of C++ MinBool objects used as primitives in Python + virtual std::list createMinBoolList(MinBool mb1, MinBool mb2); + std::list callCreateMinBoolList(MinBool mb1, MinBool mb2) { return createMinBoolList(mb1, mb2); } + virtual MinBool oredMinBoolList(std::list minBoolList); + MinBool callOredMinBoolList(std::list minBoolList) { return oredMinBoolList(minBoolList); } + + // List of C++ value types + virtual std::list createValList(int num); + std::list callCreateValList(int num) { return createValList(num); } + virtual int sumValList(std::list valList); + int callSumValList(std::list valList) { return sumValList(valList); } + + // List of C++ object types + virtual std::list createObjList(Obj* o1, Obj* o2); + std::list callCreateObjList(Obj* o1, Obj* o2) { return createObjList(o1, o2); } + virtual int sumObjList(std::list objList); + int callSumObjList(std::list objList) { return sumObjList(objList); } + + // List of lists of C++ primitive type items + virtual std::list > createListOfIntLists(int num); + std::list > callCreateListOfIntLists(int num) { return createListOfIntLists(num); } + virtual int sumListOfIntLists(std::list > intListList); + int callSumListOfIntLists(std::list > intListList) { return sumListOfIntLists(intListList); } +}; + +#endif // LISTUSER_H + diff --git a/sources/shiboken2/tests/libminimal/minbool.h b/sources/shiboken2/tests/libminimal/minbool.h new file mode 100644 index 000000000..ebd2f71e2 --- /dev/null +++ b/sources/shiboken2/tests/libminimal/minbool.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 MINBOOL_H +#define MINBOOL_H + +#include "libminimalmacros.h" + +class LIBMINIMAL_API MinBool +{ +public: + inline explicit MinBool(bool b) : m_value(b) {} + bool value() const { return m_value; } + inline MinBool operator!() const { return MinBool(!m_value); } + inline MinBool& operator|=(const MinBool& other) { + m_value = m_value | other.m_value; + return *this; + } +private: + bool m_value; +}; + +inline bool operator==(MinBool b1, bool b2) { return (!b1).value() == !b2; } +inline bool operator==(bool b1, MinBool b2) { return (!b1) == (!b2).value(); } +inline bool operator==(MinBool b1, MinBool b2) { return (!b1).value() == (!b2).value(); } +inline bool operator!=(MinBool b1, bool b2) { return (!b1).value() != !b2; } +inline bool operator!=(bool b1, MinBool b2) { return (!b1) != (!b2).value(); } +inline bool operator!=(MinBool b1, MinBool b2) { return (!b1).value() != (!b2).value(); } + +class LIBMINIMAL_API MinBoolUser +{ +public: + MinBoolUser() : m_minbool(MinBool(false)) {} + virtual ~MinBoolUser() {} + inline MinBool minBool() { return m_minbool; } + inline void setMinBool(MinBool minBool) { m_minbool = minBool; } + virtual MinBool invertedMinBool() { return !m_minbool; } + inline MinBool callInvertedMinBool() { return invertedMinBool(); } +private: + MinBool m_minbool; +}; + +#endif diff --git a/sources/shiboken2/tests/libminimal/obj.cpp b/sources/shiboken2/tests/libminimal/obj.cpp new file mode 100644 index 000000000..a1d18d0e3 --- /dev/null +++ b/sources/shiboken2/tests/libminimal/obj.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "obj.h" + +Obj::Obj(int objId) : m_objId(objId) +{ +} + +Obj::~Obj() +{ +} + +bool +Obj::virtualMethod(int val) +{ + return !bool(val%2); +} + diff --git a/sources/shiboken2/tests/libminimal/obj.h b/sources/shiboken2/tests/libminimal/obj.h new file mode 100644 index 000000000..16f838e19 --- /dev/null +++ b/sources/shiboken2/tests/libminimal/obj.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OBJ_H +#define OBJ_H + +#include "libminimalmacros.h" + +class LIBMINIMAL_API Obj +{ +public: + explicit Obj(int objId); + virtual ~Obj(); + + int objId() { return m_objId; } + void setObjId(int objId) { m_objId = objId; } + + virtual bool virtualMethod(int val); + bool callVirtualMethod(int val) { return virtualMethod(val); } + + virtual Obj* passObjectType(Obj* obj) { return obj; } + Obj* callPassObjectType(Obj* obj) { return passObjectType(obj); } + + virtual Obj* passObjectTypeReference(Obj& obj) { return &obj; } + Obj* callPassObjectTypeReference(Obj& obj) { return passObjectTypeReference(obj); } + +private: + Obj(const Obj&); + Obj& operator=(const Obj&); + int m_objId; +}; + +#endif // OBJ_H + diff --git a/sources/shiboken2/tests/libminimal/typedef.cpp b/sources/shiboken2/tests/libminimal/typedef.cpp new file mode 100644 index 000000000..4948d9944 --- /dev/null +++ b/sources/shiboken2/tests/libminimal/typedef.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "typedef.h" + +// +// Test wrapping of a typedef +// +bool arrayFuncInt(std::vector a) +{ + return a.empty(); +} + +bool arrayFuncIntTypedef(MyArray a) +{ + return arrayFuncInt(a); +} + +std::vector arrayFuncIntReturn(int size) +{ + return std::vector(size); +} + +MyArray arrayFuncIntReturnTypedef(int size) +{ + return arrayFuncIntReturn(size); +} + +// +// Test wrapping of a typedef of a typedef +// +bool arrayFunc(std::vector a) +{ + return a.empty(); +} + +bool arrayFuncTypedef(MyArray a) +{ + return arrayFunc(a); +} + +std::vector arrayFuncReturn(int size) +{ + return std::vector(size); +} + +MyArray arrayFuncReturnTypedef(int size) +{ + return arrayFuncReturn(size); +} diff --git a/sources/shiboken2/tests/libminimal/typedef.h b/sources/shiboken2/tests/libminimal/typedef.h new file mode 100644 index 000000000..f54a6ed18 --- /dev/null +++ b/sources/shiboken2/tests/libminimal/typedef.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TYPEDEF_H +#define TYPEDEF_H + +#include "libminimalmacros.h" + +#include + +// Test wrapping of a typedef +typedef std::vector MyArrayInt; + +LIBMINIMAL_API bool arrayFuncInt(std::vector a); +LIBMINIMAL_API bool arrayFuncIntTypedef(MyArrayInt a); + +LIBMINIMAL_API std::vector arrayFuncIntReturn(int size); +LIBMINIMAL_API MyArrayInt arrayFuncIntReturnTypedef(int size); + +// Test wrapping of a typedef of a typedef +typedef MyArrayInt MyArray; + +LIBMINIMAL_API bool arrayFunc(std::vector a); +LIBMINIMAL_API bool arrayFuncTypedef(MyArray a); + +LIBMINIMAL_API std::vector arrayFuncReturn(int size); +LIBMINIMAL_API MyArray arrayFuncReturnTypedef(int size); + +#endif diff --git a/sources/shiboken2/tests/libminimal/val.h b/sources/shiboken2/tests/libminimal/val.h new file mode 100644 index 000000000..5ba4b3aff --- /dev/null +++ b/sources/shiboken2/tests/libminimal/val.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 VAL_H +#define VAL_H + +#include "libminimalmacros.h" + +class LIBMINIMAL_API Val +{ +public: + explicit Val(int valId) : m_valId(valId) {} + virtual ~Val() {} + + int valId() { return m_valId; } + void setValId(int valId) { m_valId = valId; } + + virtual Val passValueType(Val val) { return val; } + Val callPassValueType(Val val) { return passValueType(val); } + + virtual Val* passValueTypePointer(Val* val) { return val; } + Val* callPassValueTypePointer(Val* val) { return passValueTypePointer(val); } + + virtual Val* passValueTypeReference(Val& val) { return &val; } + Val* callPassValueTypeReference(Val& val) { return passValueTypeReference(val); } + + enum ValEnum { One, Other }; + ValEnum oneOrTheOtherEnumValue(ValEnum enumValue) { return enumValue == One ? Other : One; } +private: + int m_valId; +}; + +#endif // VAL_H + diff --git a/sources/shiboken2/tests/libother/CMakeLists.txt b/sources/shiboken2/tests/libother/CMakeLists.txt new file mode 100644 index 000000000..9b3cf5552 --- /dev/null +++ b/sources/shiboken2/tests/libother/CMakeLists.txt @@ -0,0 +1,18 @@ +project(libother) + +set(libother_SRC +number.cpp +otherderived.cpp +otherobjecttype.cpp +othermultiplederived.cpp +) + +add_definitions("-DLIBOTHER_BUILD") +add_library(libother SHARED ${libother_SRC}) +set_property(TARGET libother PROPERTY PREFIX "") + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${libsample_SOURCE_DIR} + ${libsample_SOURCE_DIR}/..) +target_link_libraries(libother libsample) + diff --git a/sources/shiboken2/tests/libother/extendsnoimplicitconversion.h b/sources/shiboken2/tests/libother/extendsnoimplicitconversion.h new file mode 100644 index 000000000..744bfdc0d --- /dev/null +++ b/sources/shiboken2/tests/libother/extendsnoimplicitconversion.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 EXTENDSNOIMPLICITCONVERSION_H +#define EXTENDSNOIMPLICITCONVERSION_H + +#include "libothermacros.h" +#include "noimplicitconversion.h" + +class ExtendsNoImplicitConversion +{ +public: + explicit ExtendsNoImplicitConversion(int objId) : m_objId(objId) {}; + inline int objId() const { return m_objId; } + inline operator NoImplicitConversion() const { return NoImplicitConversion(m_objId); } +private: + int m_objId; +}; +#endif // EXTENDSNOIMPLICITCONVERSION_H + diff --git a/sources/shiboken2/tests/libother/libothermacros.h b/sources/shiboken2/tests/libother/libothermacros.h new file mode 100644 index 000000000..41a4fb13e --- /dev/null +++ b/sources/shiboken2/tests/libother/libothermacros.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 LIBOTHERMACROS_H +#define LIBOTHERMACROS_H + +#if defined _WIN32 || defined __CYGWIN__ + #if LIBOTHER_BUILD + #define LIBOTHER_API __declspec(dllexport) + #else + #define LIBOTHER_API __declspec(dllimport) + #endif +#else +#if __GNUC__ >= 4 + #define LIBOTHER_API __attribute__ ((visibility("default"))) +#else + #define LIBOTHER_API +#endif +#endif + +#endif diff --git a/sources/shiboken2/tests/libother/number.cpp b/sources/shiboken2/tests/libother/number.cpp new file mode 100644 index 000000000..4da254286 --- /dev/null +++ b/sources/shiboken2/tests/libother/number.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "number.h" +#include +#include + +using namespace std; + +Str +Number::toStr() const +{ + ostringstream in; + in << m_value; + return in.str().c_str(); +} + +Point +operator*(const Point& p, const Number& n) +{ + return Point(p.x() * n.value(), p.y() * n.value()); +} + +Complex +Number::toComplex() const +{ + return Complex(m_value); +} + +Number +Number::fromComplex(Complex cpx) +{ + return Number(cpx.real()); +} diff --git a/sources/shiboken2/tests/libother/number.h b/sources/shiboken2/tests/libother/number.h new file mode 100644 index 000000000..4286068d5 --- /dev/null +++ b/sources/shiboken2/tests/libother/number.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 NUMBER_H +#define NUMBER_H + +#include "libothermacros.h" +#include "str.h" +#include "point.h" +#include "complex.h" + +class LIBOTHER_API Number +{ +public: + explicit Number(int value) : m_value(value) {}; + inline int value() const { return m_value; } + + Str toStr() const; + inline operator Str() const { return toStr(); } + + friend LIBOTHER_API Point operator*(const Point&, const Number&); + + Complex toComplex() const; + static Number fromComplex(Complex cpx); + +private: + int m_value; +}; + +LIBOTHER_API Point operator*(const Point&, const Number&); + +#endif // NUMBER_H diff --git a/sources/shiboken2/tests/libother/otherderived.cpp b/sources/shiboken2/tests/libother/otherderived.cpp new file mode 100644 index 000000000..4128d73ff --- /dev/null +++ b/sources/shiboken2/tests/libother/otherderived.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "otherderived.h" + +OtherDerived::OtherDerived(int id) : Abstract(id) +{ +} + +OtherDerived::~OtherDerived() +{ +} + +Abstract* +OtherDerived::createObject() +{ + static int id = 100; + return new OtherDerived(id++); +} + +void +OtherDerived::pureVirtual() +{ +} + +void* +OtherDerived::pureVirtualReturningVoidPtr() +{ + return 0; +} + +void +OtherDerived::unpureVirtual() +{ +} + diff --git a/sources/shiboken2/tests/libother/otherderived.h b/sources/shiboken2/tests/libother/otherderived.h new file mode 100644 index 000000000..792b7c408 --- /dev/null +++ b/sources/shiboken2/tests/libother/otherderived.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OTHERDERIVED_H +#define OTHERDERIVED_H + +#include "libothermacros.h" +#include "abstract.h" +#include "derived.h" +#include "objecttype.h" +#include "complex.h" + +class ObjectType; + +class LIBOTHER_API OtherDerived : public Abstract +{ +public: + OtherDerived(int id = -1); + virtual ~OtherDerived(); + virtual void pureVirtual(); + virtual void* pureVirtualReturningVoidPtr(); + virtual void unpureVirtual(); + virtual PrintFormat returnAnEnum() { return Short; } + + inline void useObjectTypeFromOtherModule(ObjectType*) {} + inline Event useValueTypeFromOtherModule(const Event& e) { return e; } + inline Complex useValueTypeFromOtherModule(const Complex& c) { return c; } + inline void useEnumTypeFromOtherModule(OverloadedFuncEnum) {} + + // factory method + static Abstract* createObject(); + + void hideFunction(HideType*) {} + +protected: + inline const char* getClassName() { return className(); } + virtual const char* className() { return "OtherDerived"; } +}; +#endif // OTHERDERIVED_H + diff --git a/sources/shiboken2/tests/libother/othermultiplederived.cpp b/sources/shiboken2/tests/libother/othermultiplederived.cpp new file mode 100644 index 000000000..77fa44b83 --- /dev/null +++ b/sources/shiboken2/tests/libother/othermultiplederived.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "othermultiplederived.h" + +VirtualMethods OtherMultipleDerived::returnUselessClass() +{ + return VirtualMethods(); +} + +Base1* OtherMultipleDerived::createObject(const std::string& objName) +{ + if (objName == "Base1") + return new Base1; + else if (objName == "MDerived1") + return new MDerived1; + else if (objName == "SonOfMDerived1") + return new SonOfMDerived1; + else if (objName == "MDerived3") + return new MDerived3; + else if (objName == "OtherMultipleDerived") + return new OtherMultipleDerived; + return 0; +} + diff --git a/sources/shiboken2/tests/libother/othermultiplederived.h b/sources/shiboken2/tests/libother/othermultiplederived.h new file mode 100644 index 000000000..e75504320 --- /dev/null +++ b/sources/shiboken2/tests/libother/othermultiplederived.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OTHERMULTIPLEDERIVED_H +#define OTHERMULTIPLEDERIVED_H + +#include "libothermacros.h" +#include "multiple_derived.h" +#include "virtualmethods.h" + +class ObjectType; + +class LIBOTHER_API OtherMultipleDerived : public MDerived1 +{ +public: + // this will use CppCopier from other module (bug#142) + VirtualMethods returnUselessClass(); + static Base1* createObject(const std::string& objName); +}; + +#endif diff --git a/sources/shiboken2/tests/libother/otherobjecttype.cpp b/sources/shiboken2/tests/libother/otherobjecttype.cpp new file mode 100644 index 000000000..266b2583e --- /dev/null +++ b/sources/shiboken2/tests/libother/otherobjecttype.cpp @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "otherobjecttype.h" + +Collector& +operator<<(Collector& collector, const OtherObjectType& obj) +{ + collector << obj.identifier()*2; + return collector; +} diff --git a/sources/shiboken2/tests/libother/otherobjecttype.h b/sources/shiboken2/tests/libother/otherobjecttype.h new file mode 100644 index 000000000..2bba912b6 --- /dev/null +++ b/sources/shiboken2/tests/libother/otherobjecttype.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OTHEROBJECTTYPE_H +#define OTHEROBJECTTYPE_H + +#include +#include "str.h" + +#include "libothermacros.h" +#include "objecttype.h" +#include "collector.h" + +class OtherObjectType : public ObjectType +{ +public: + +}; + + +LIBOTHER_API Collector& operator<<(Collector&, const OtherObjectType&); + +#endif // OTHEROBJECTTYPE_H + diff --git a/sources/shiboken2/tests/libsample/CMakeLists.txt b/sources/shiboken2/tests/libsample/CMakeLists.txt new file mode 100644 index 000000000..7bbc0c3dd --- /dev/null +++ b/sources/shiboken2/tests/libsample/CMakeLists.txt @@ -0,0 +1,57 @@ +project(libsample) + +set(libsample_SRC +abstract.cpp +blackbox.cpp +bytearray.cpp +bucket.cpp +collector.cpp +complex.cpp +onlycopy.cpp +derived.cpp +echo.cpp +functions.cpp +handle.cpp +implicitconv.cpp +injectcode.cpp +listuser.cpp +modifications.cpp +mapuser.cpp +modified_constructor.cpp +multiple_derived.cpp +objectmodel.cpp +objecttype.cpp +objecttypeholder.cpp +objecttypelayout.cpp +objecttypeoperators.cpp +objectview.cpp +overload.cpp +overloadsort.cpp +pairuser.cpp +pen.cpp +photon.cpp +point.cpp +pointf.cpp +polygon.cpp +protected.cpp +reference.cpp +sample.cpp +samplenamespace.cpp +sbkdate.cpp +simplefile.cpp +size.cpp +sometime.cpp +str.cpp +strlist.cpp +templateptr.cpp +transform.cpp +virtualmethods.cpp +expression.cpp +filter.cpp +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +add_definitions("-DLIBSAMPLE_BUILD") +add_library(libsample SHARED ${libsample_SRC}) +set_property(TARGET libsample PROPERTY PREFIX "") + diff --git a/sources/shiboken2/tests/libsample/abstract.cpp b/sources/shiboken2/tests/libsample/abstract.cpp new file mode 100644 index 000000000..ab00a3bcc --- /dev/null +++ b/sources/shiboken2/tests/libsample/abstract.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "abstract.h" +#include "objecttype.h" + +using namespace std; + +const int Abstract::staticPrimitiveField = 0; + +Abstract::Abstract(int id) : m_id(id) +{ + primitiveField = 123; + valueTypeField = Point(12, 34); + objectTypeField = 0; + bitField = 0; +} + +Abstract::~Abstract() +{ +} + +void +Abstract::unpureVirtual() +{ +} + +void +Abstract::callUnpureVirtual() +{ + this->unpureVirtual(); +} + + +void +Abstract::callPureVirtual() +{ + this->pureVirtual(); +} + +void +Abstract::show(PrintFormat format) +{ + cout << '<'; + switch(format) { + case Short: + cout << this; + break; + case Verbose: + cout << "class " << className() << " | cptr: " << this; + cout << ", id: " << m_id; + break; + case OnlyId: + cout << "id: " << m_id; + break; + case ClassNameAndId: + cout << className() << " - id: " << m_id; + break; + } + cout << '>'; +} + +void Abstract::callVirtualGettingEnum(PrintFormat p) +{ + virtualGettingAEnum(p); +} + +void Abstract::virtualGettingAEnum(Abstract::PrintFormat p) +{ +} + diff --git a/sources/shiboken2/tests/libsample/abstract.h b/sources/shiboken2/tests/libsample/abstract.h new file mode 100644 index 000000000..77a43f3d1 --- /dev/null +++ b/sources/shiboken2/tests/libsample/abstract.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 ABSTRACT_H +#define ABSTRACT_H + +#include "libsamplemacros.h" +#include "point.h" +#include "complex.h" + +class ObjectType; + +// this class is not exported to python +class HideType +{ +}; + +class LIBSAMPLE_API Abstract +{ +private: + enum PrivateEnum { + PrivValue0, + PrivValue1, + PrivValue2 = PrivValue1 + 2 + }; +public: + enum PrintFormat { + Short, + Verbose, + OnlyId, + ClassNameAndId, + DummyItemToTestPrivateEnum1 = Abstract::PrivValue1, + DummyItemToTestPrivateEnum2 = PrivValue2, + }; + + enum Type { + TpAbstract, TpDerived + }; + + static const int staticPrimitiveField; + int primitiveField; + Complex userPrimitiveField; + Point valueTypeField; + ObjectType* objectTypeField; + + Abstract(int id = -1); + virtual ~Abstract(); + + inline int id() { return m_id; } + + // factory method + inline static Abstract* createObject() { return 0; } + + // method that receives an Object Type + inline static int getObjectId(Abstract* obj) { return obj->id(); } + + virtual void pureVirtual() = 0; + virtual void* pureVirtualReturningVoidPtr() = 0; + virtual void unpureVirtual(); + + virtual PrintFormat returnAnEnum() = 0; + void callVirtualGettingEnum(PrintFormat p); + virtual void virtualGettingAEnum(PrintFormat p); + + void callPureVirtual(); + void callUnpureVirtual(); + + void show(PrintFormat format = Verbose); + virtual Type type() const { return TpAbstract; } + + virtual void hideFunction(HideType* arg) = 0; + +protected: + virtual const char* className() { return "Abstract"; } + + // Protected bit-field structure member. + unsigned int bitField: 1; + +private: + int m_id; +}; +#endif // ABSTRACT_H diff --git a/sources/shiboken2/tests/libsample/blackbox.cpp b/sources/shiboken2/tests/libsample/blackbox.cpp new file mode 100644 index 000000000..9a10850f3 --- /dev/null +++ b/sources/shiboken2/tests/libsample/blackbox.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "blackbox.h" + +using namespace std; + +BlackBox::~BlackBox() +{ + // Free all maps. + while (!m_objects.empty()) { + delete (*m_objects.begin()).second; + m_objects.erase(m_objects.begin()); + } + while (!m_points.empty()) { + delete (*m_points.begin()).second; + m_points.erase(m_points.begin()); + } +} + +int +BlackBox::keepObjectType(ObjectType* object) +{ + m_ticket++; + std::pair item(m_ticket, object); + m_objects.insert(item); + object->setParent(0); + + return m_ticket; +} + +ObjectType* +BlackBox::retrieveObjectType(int ticket) +{ + map::iterator it = m_objects.find(ticket); + if (it != m_objects.end()) { + ObjectType* second = it->second; + m_objects.erase(it); + return second; + } + return 0; +} + +void +BlackBox::disposeObjectType(int ticket) +{ + ObjectType* object = retrieveObjectType(ticket); + if (object) + delete object; +} + +int +BlackBox::keepPoint(Point* point) +{ + m_ticket++; + std::pair item(m_ticket, point); + m_points.insert(item); + + return m_ticket; +} + +Point* +BlackBox::retrievePoint(int ticket) +{ + map::iterator it = m_points.find(ticket); + if (it != m_points.end()) { + Point* second = it->second; + m_points.erase(it); + return second; + } + return 0; +} + +void +BlackBox::disposePoint(int ticket) +{ + Point* point = retrievePoint(ticket); + if (point) + delete point; +} + + +std::list +BlackBox::objects() +{ + std::list l; + map::iterator it; + + for ( it = m_objects.begin() ; it != m_objects.end(); it++ ) + l.push_back((*it).second); + + return l; +} + +std::list +BlackBox::points() +{ + std::list l; + map::iterator it; + + for ( it = m_points.begin() ; it != m_points.end(); it++ ) + l.push_back((*it).second); + + return l; +} + diff --git a/sources/shiboken2/tests/libsample/blackbox.h b/sources/shiboken2/tests/libsample/blackbox.h new file mode 100644 index 000000000..de776668c --- /dev/null +++ b/sources/shiboken2/tests/libsample/blackbox.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 BLACKBOX_H +#define BLACKBOX_H + +#include "libsamplemacros.h" +#include +#include "objecttype.h" +#include "point.h" + +class LIBSAMPLE_API BlackBox +{ +public: + typedef std::map ObjectTypeMap; + typedef std::map PointMap; + + BlackBox() { m_ticket = -1;} + ~BlackBox(); + + int keepObjectType(ObjectType* object); + ObjectType* retrieveObjectType(int ticket); + void disposeObjectType(int ticket); + + int keepPoint(Point* point); + Point* retrievePoint(int ticket); + void disposePoint(int ticket); + + std::list objects(); + std::list points(); + + inline void referenceToValuePointer(Point*&) {} + inline void referenceToObjectPointer(ObjectType*&) {} + +private: + ObjectTypeMap m_objects; + PointMap m_points; + int m_ticket; +}; + +#endif // BLACKBOX_H + diff --git a/sources/shiboken2/tests/libsample/bucket.cpp b/sources/shiboken2/tests/libsample/bucket.cpp new file mode 100644 index 000000000..50a1310e7 --- /dev/null +++ b/sources/shiboken2/tests/libsample/bucket.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "bucket.h" +#include + +#ifdef _WIN32 // _WIN32 is defined by all Windows 32 and 64 bit compilers, but not by others. +#include +#define SLEEP(x) Sleep(x) +#else +#include +#define SLEEP(x) usleep(x) +#endif + + +using namespace std; + +Bucket::Bucket() : m_locked(false) +{ +} + +void Bucket::push(int x) +{ + m_data.push_back(x); +} + +int Bucket::pop(void) +{ + int x = 0; + + if (m_data.size() > 0) { + x = m_data.front(); + m_data.pop_front(); + } + + return x; +} + +bool Bucket::empty() +{ + return m_data.empty(); +} + +void Bucket::lock() +{ + m_locked = true; + while (m_locked) { SLEEP(300); } +} + +void Bucket::unlock() +{ + m_locked = false; +} + +bool Bucket::virtualBlockerMethod() +{ + lock(); + // The return value was added just for diversity sake. + return true; +} + diff --git a/sources/shiboken2/tests/libsample/bucket.h b/sources/shiboken2/tests/libsample/bucket.h new file mode 100644 index 000000000..bd8648b6b --- /dev/null +++ b/sources/shiboken2/tests/libsample/bucket.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 BUCKET_H +#define BUCKET_H + +#include "libsamplemacros.h" +#include "objecttype.h" +#include + +class ObjectType; + +class LIBSAMPLE_API Bucket : public ObjectType +{ +public: + Bucket(); + void push(int); + int pop(); + bool empty(); + void lock(); + inline bool locked() { return m_locked; } + void unlock(); + + virtual bool virtualBlockerMethod(); + inline bool callVirtualBlockerMethodButYouDontKnowThis() { return virtualBlockerMethod(); } + +private: + std::list m_data; + + volatile bool m_locked; +}; + +#endif // BUCKET_H + diff --git a/sources/shiboken2/tests/libsample/bytearray.cpp b/sources/shiboken2/tests/libsample/bytearray.cpp new file mode 100644 index 000000000..c86ada124 --- /dev/null +++ b/sources/shiboken2/tests/libsample/bytearray.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "bytearray.h" + +ByteArray::ByteArray() +{ + m_data = std::vector(1); + m_data[0] = '\0'; +} + +ByteArray::ByteArray(char c) +{ + m_data = std::vector(2); + m_data[0] = c; + m_data[1] = '\0'; +} + +ByteArray::ByteArray(const char* data) +{ + size_t len = strlen(data); + m_data = std::vector(len + 1); + memcpy(&m_data[0], data, len); + m_data[len] = '\0'; +} + +ByteArray::ByteArray(const char* data, int len) +{ + m_data = std::vector(len + 1); + memcpy(&m_data[0], data, len); + m_data[len] = '\0'; +} + +ByteArray::ByteArray(const ByteArray& other) +{ + m_data = std::vector(other.size() + 1); + memcpy(&m_data[0], &other.m_data[0], other.size()); + m_data[other.size()] = '\0'; +} + +int +ByteArray::size() const +{ + return m_data.size() - 1; +} + +char +ByteArray::at(int pos) const +{ + return m_data[pos]; +} + +const char* +ByteArray::data() const +{ + return &(m_data[0]); +} + +ByteArray& +ByteArray::append(char c) +{ + m_data.pop_back(); + m_data.push_back(c); + m_data.push_back('\0'); + return *this; +} + +ByteArray& +ByteArray::append(const char* data) +{ + m_data.pop_back(); + for (int i = 0; i < (int)strlen(data); ++i) + m_data.push_back(data[i]); + m_data.push_back('\0'); + return *this; +} + +ByteArray& +ByteArray::append(const char* data, int len) +{ + m_data.pop_back(); + for (int i = 0; i < len; ++i) + m_data.push_back(data[i]); + m_data.push_back('\0'); + return *this; +} + +ByteArray& +ByteArray::append(const ByteArray& other) +{ + m_data.pop_back(); + for (int i = 0; i < (int)other.m_data.size(); ++i) + m_data.push_back(other.m_data[i]); + m_data.push_back('\0'); + return *this; +} + +static bool compare(const std::vector& mine, const char* other) +{ + for (int i = 0; i < (int)mine.size() - 1; ++i) { + if (mine[i] != other[i]) + return false; + } + return true; +} + +bool +ByteArray::operator==(const ByteArray& other) const +{ + return compare(m_data, &other.m_data[0]); +} +bool +operator==(const ByteArray& ba1, const char* ba2) +{ + return compare(ba1.m_data, ba2); +} +bool +operator==(const char* ba1, const ByteArray& ba2) +{ + return compare(ba2.m_data, ba1); +} + +bool +ByteArray::operator!=(const ByteArray& other) const +{ + return !(m_data == other.m_data); +} +bool +operator!=(const ByteArray& ba1, const char* ba2) +{ + return !(ba1 == ba2); +} +bool +operator!=(const char* ba1, const ByteArray& ba2) +{ + return !(ba1 == ba2); +} + +ByteArray& +ByteArray::operator+=(char c) +{ + return append(c); +} +ByteArray& +ByteArray::operator+=(const char* data) +{ + return append(data); +} +ByteArray& +ByteArray::operator+=(const ByteArray& other) +{ + return append(other); +} + +ByteArray +operator+(const ByteArray& ba1, const ByteArray& ba2) +{ + return ByteArray(ba1) += ba2; +} +ByteArray +operator+(const ByteArray& ba1, const char* ba2) +{ + return ByteArray(ba1) += ByteArray(ba2); +} +ByteArray +operator+(const char* ba1, const ByteArray& ba2) +{ + return ByteArray(ba1) += ba2; +} +ByteArray +operator+(const ByteArray& ba1, char ba2) +{ + return ByteArray(ba1) += ByteArray(ba2); +} +ByteArray +operator+(char ba1, const ByteArray& ba2) +{ + return ByteArray(ba1) += ba2; +} + +unsigned int +ByteArray::hash(const ByteArray& byteArray) +{ + unsigned int result = 0; + for (int i = 0; i < (int)byteArray.m_data.size(); ++i) + result = 5 * result + byteArray.m_data[i]; + return result; +} diff --git a/sources/shiboken2/tests/libsample/bytearray.h b/sources/shiboken2/tests/libsample/bytearray.h new file mode 100644 index 000000000..d2219ee5d --- /dev/null +++ b/sources/shiboken2/tests/libsample/bytearray.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 BYTEARRAY_H +#define BYTEARRAY_H + +#include "str.h" +#include "libsamplemacros.h" +#include + +class LIBSAMPLE_API ByteArray +{ +public: + ByteArray(); + ByteArray(char data); + ByteArray(const char* data); + ByteArray(const char* data, int len); + ByteArray(const ByteArray& other); + + int size() const; + char at(int i) const; + char operator[](int i) const; + + const char* data() const; + + ByteArray& append(char c); + ByteArray& append(const char* data); + ByteArray& append(const char* data, int len); + ByteArray& append(const ByteArray& other); + + bool operator==(const ByteArray& other) const; + bool operator!=(const ByteArray& other) const; + + ByteArray& operator+=(char c); + ByteArray& operator+=(const char* data); + ByteArray& operator+=(const ByteArray& other); + + static unsigned int hash(const ByteArray& byteArray); +private: + std::vector m_data; + friend LIBSAMPLE_API bool operator==(const ByteArray& ba1, const char* ba2); + friend LIBSAMPLE_API bool operator==(const char* ba1, const ByteArray& ba2); + friend LIBSAMPLE_API bool operator!=(const ByteArray& ba1, const char* ba2); + friend LIBSAMPLE_API bool operator!=(const char* ba1, const ByteArray& ba2); + + friend LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, const ByteArray& ba2); + friend LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, const char* ba2); + friend LIBSAMPLE_API ByteArray operator+(const char* ba1, const ByteArray& ba2); + friend LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, char ba2); + friend LIBSAMPLE_API ByteArray operator+(char ba1, const ByteArray& ba2); +}; + +LIBSAMPLE_API bool operator==(const ByteArray& ba1, const char* ba2); +LIBSAMPLE_API bool operator==(const char* ba1, const ByteArray& ba2); +LIBSAMPLE_API bool operator!=(const ByteArray& ba1, const char* ba2); +LIBSAMPLE_API bool operator!=(const char* ba1, const ByteArray& ba2); + +LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, const ByteArray& ba2); +LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, const char* ba2); +LIBSAMPLE_API ByteArray operator+(const char* ba1, const ByteArray& ba2); +LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, char ba2); +LIBSAMPLE_API ByteArray operator+(char ba1, const ByteArray& ba2); + +#endif // BYTEARRAY_H diff --git a/sources/shiboken2/tests/libsample/collector.cpp b/sources/shiboken2/tests/libsample/collector.cpp new file mode 100644 index 000000000..e60ed3af3 --- /dev/null +++ b/sources/shiboken2/tests/libsample/collector.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "collector.h" + +void Collector::clear() +{ + m_items.clear(); +} + +Collector& Collector::operator<<(ObjectType::Identifier item) +{ + m_items.push_back(item); + return *this; +} + +Collector& Collector::operator<<(const ObjectType *obj) +{ + m_items.push_back(obj->identifier()); + return *this; +} + +std::list Collector::items() +{ + return m_items; +} + +int Collector::size() +{ + return (int) m_items.size(); +} + +Collector &operator<<(Collector &s, const IntWrapper &w) +{ + s << w.value; + return s; +} diff --git a/sources/shiboken2/tests/libsample/collector.h b/sources/shiboken2/tests/libsample/collector.h new file mode 100644 index 000000000..fe82909cb --- /dev/null +++ b/sources/shiboken2/tests/libsample/collector.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 COLLECTOR_H +#define COLLECTOR_H + +#include +#include "libsamplemacros.h" + +#include "objecttype.h" + +class LIBSAMPLE_API Collector +{ +public: + Collector() {} + virtual ~Collector() {} + + void clear(); + + Collector& operator<<(ObjectType::Identifier item); + + Collector& operator<<(const ObjectType *); + + std::list items(); + int size(); + +private: + std::list m_items; + + Collector(const Collector&); + Collector& operator=(const Collector&); +}; + +/* Helper for testing external operators */ +class IntWrapper +{ +public: + IntWrapper(int x=0):value(x){} + + int value; +}; + +LIBSAMPLE_API Collector &operator<<(Collector&, const IntWrapper&); + +#endif // COLLECTOR_H + diff --git a/sources/shiboken2/tests/libsample/complex.cpp b/sources/shiboken2/tests/libsample/complex.cpp new file mode 100644 index 000000000..10e4b3f58 --- /dev/null +++ b/sources/shiboken2/tests/libsample/complex.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "complex.h" + +using namespace std; + +Complex::Complex(double real, double imag) + : m_real(real), m_imag(imag) +{ +} + +Complex +Complex::operator+(Complex& other) +{ + Complex result; + result.setReal(m_real + other.real()); + result.setImaginary(m_imag + other.imag()); + return result; +} + +void +Complex::show() +{ + cout << "(real: " << m_real << ", imag: " << m_imag << ")"; +} + + diff --git a/sources/shiboken2/tests/libsample/complex.h b/sources/shiboken2/tests/libsample/complex.h new file mode 100644 index 000000000..cb167bde9 --- /dev/null +++ b/sources/shiboken2/tests/libsample/complex.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 COMPLEX_H +#define COMPLEX_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Complex +{ +public: + Complex(double real = 0.0, double imag = 0.0); + ~Complex() {} + + inline double real() const { return m_real; } + inline void setReal(double real) { m_real = real; } + inline double imag() const { return m_imag; } + inline void setImaginary(double imag) { m_imag = imag; } + + Complex operator+(Complex& other); + + void show(); + +private: + double m_real; + double m_imag; +}; + +#endif // COMPLEX_H + diff --git a/sources/shiboken2/tests/libsample/ctorconvrule.h b/sources/shiboken2/tests/libsample/ctorconvrule.h new file mode 100644 index 000000000..776f4744c --- /dev/null +++ b/sources/shiboken2/tests/libsample/ctorconvrule.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 CTORCONVRULE_H +#define CTORCONVRULE_H + +#include "libsamplemacros.h" + +class CtorConvRule +{ +public: + explicit CtorConvRule(long value) : m_value(value) {} + virtual ~CtorConvRule() {} + virtual void dummyVirtualMethod() {} + long value() { return m_value; } +private: + long m_value; +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/cvlist.h b/sources/shiboken2/tests/libsample/cvlist.h new file mode 100644 index 000000000..c74007945 --- /dev/null +++ b/sources/shiboken2/tests/libsample/cvlist.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 CONSTVALUELIST_H +#define CONSTVALUELIST_H + +#include +#include "libsamplemacros.h" + +class CVValueType +{ + CVValueType(); +}; + +typedef std::list const_ptr_value_list; + +// This tests binding generation for a container of a const value type. The +// class doesn't need to do anything; this is just to verify that the generated +// binding code (the container conversion in particular) is const-valid. + +class CVListUser +{ +public: + static const_ptr_value_list produce() { return const_ptr_value_list(); } + static void consume(const const_ptr_value_list& l) { (void)l; } +}; + +#endif // LIST_H diff --git a/sources/shiboken2/tests/libsample/derived.cpp b/sources/shiboken2/tests/libsample/derived.cpp new file mode 100644 index 000000000..00ac8ebe5 --- /dev/null +++ b/sources/shiboken2/tests/libsample/derived.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "derived.h" + +using namespace std; + +Derived::Derived(int id) : Abstract(id) +{ +} + +Derived::~Derived() +{ +} + +Abstract* +Derived::createObject() +{ + static int id = 100; + return new Derived(id++); +} + +void +Derived::pureVirtual() +{ +} + +void* +Derived::pureVirtualReturningVoidPtr() +{ + return 0; +} + +void +Derived::unpureVirtual() +{ +} + +bool +Derived::singleArgument(bool b) +{ + return !b; +} + +double +Derived::defaultValue(int n) +{ + return ((double) n) + 0.1; +} + +OverloadedFuncEnum +Derived::overloaded(int i, int d) +{ + return OverloadedFunc_ii; +} + +OverloadedFuncEnum +Derived::overloaded(double n) +{ + return OverloadedFunc_d; +} + +Derived::OtherOverloadedFuncEnum +Derived::otherOverloaded(int a, int b, bool c, double d) +{ + return OtherOverloadedFunc_iibd; +} + +Derived::OtherOverloadedFuncEnum +Derived::otherOverloaded(int a, double b) +{ + return OtherOverloadedFunc_id; +} + +struct SecretClass : public Abstract { + virtual void pureVirtual() {} + virtual void* pureVirtualReturningVoidPtr() { return 0; } + virtual PrintFormat returnAnEnum() { return Short; } + void hideFunction(HideType*){}; +}; + +Abstract* Derived::triggerImpossibleTypeDiscovery() +{ + return new SecretClass; +} + +struct AnotherSecretClass : public Derived { +}; + +Abstract* Derived::triggerAnotherImpossibleTypeDiscovery() +{ + return new AnotherSecretClass; +} diff --git a/sources/shiboken2/tests/libsample/derived.h b/sources/shiboken2/tests/libsample/derived.h new file mode 100644 index 000000000..5c57e4691 --- /dev/null +++ b/sources/shiboken2/tests/libsample/derived.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 DERIVED_H +#define DERIVED_H + +#include "libsamplemacros.h" +#include "abstract.h" + +enum OverloadedFuncEnum { + OverloadedFunc_ii, + OverloadedFunc_d +}; + +class LIBSAMPLE_API Derived : public Abstract +{ +public: + enum OtherOverloadedFuncEnum { + OtherOverloadedFunc_iibd, + OtherOverloadedFunc_id + }; + + class SomeInnerClass { + public: + void uselessMethod() {} + SomeInnerClass operator+(const SomeInnerClass& other) { return other; } + bool operator==(const SomeInnerClass& other) { return true; } + }; + + Derived(int id = -1); + virtual ~Derived(); + virtual void pureVirtual(); + virtual void* pureVirtualReturningVoidPtr(); + virtual void unpureVirtual(); + + virtual PrintFormat returnAnEnum() { return Short; } + virtual Type type() const { return TpDerived; } + + // factory method + static Abstract* createObject(); + + // single argument + bool singleArgument(bool b); + + // method with default value + double defaultValue(int n = 0); + + // overloads + OverloadedFuncEnum overloaded(int i = 0, int d = 0); + OverloadedFuncEnum overloaded(double n); + + // more overloads + OtherOverloadedFuncEnum otherOverloaded(int a, int b, bool c, double d); + OtherOverloadedFuncEnum otherOverloaded(int a, double b); + + inline SomeInnerClass returnMyParameter(const SomeInnerClass& s) { return s; } + + static Abstract* triggerImpossibleTypeDiscovery(); + static Abstract* triggerAnotherImpossibleTypeDiscovery(); + + void hideFunction(HideType*) {} +protected: + const char* getClassName() { return className(); } + virtual const char* className() { return "Derived"; } +}; +#endif // DERIVED_H + diff --git a/sources/shiboken2/tests/libsample/echo.cpp b/sources/shiboken2/tests/libsample/echo.cpp new file mode 100644 index 000000000..00fec78b0 --- /dev/null +++ b/sources/shiboken2/tests/libsample/echo.cpp @@ -0,0 +1,29 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "echo.h" diff --git a/sources/shiboken2/tests/libsample/echo.h b/sources/shiboken2/tests/libsample/echo.h new file mode 100644 index 000000000..a976c9cbc --- /dev/null +++ b/sources/shiboken2/tests/libsample/echo.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 ECHO_H +#define ECHO_H + +#include "libsamplemacros.h" +#include "str.h" + +class ObjectType; + +class Echo +{ +public: + Echo(){} + ~Echo(){} + + void doNothingWithConstBool(const bool hi) {} + void methodWithNamedArg(const Str& string = Str("")) {} + + Str operator()(const Str& s, const int i) { return s + i; } + + // These method are here just for compilation test purposes + Echo& operator<<(unsigned int item) { return *this; } + Echo& operator<<(signed int item) { return *this; } + Echo& operator<<(const ObjectType* item) { return *this; } + Echo& operator<<(Str str) { return *this; } +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/expression.cpp b/sources/shiboken2/tests/libsample/expression.cpp new file mode 100644 index 000000000..ff87e2ed2 --- /dev/null +++ b/sources/shiboken2/tests/libsample/expression.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "expression.h" +#include + +Expression::Expression() : m_value(0), m_operation(None), m_operand1(0), m_operand2(0) +{ +} + +Expression::Expression(int number) : m_value(number), m_operation(None), m_operand1(0), m_operand2(0) +{ +} + +Expression::Expression(const Expression& other) +{ + m_operand1 = other.m_operand1 ? new Expression(*other.m_operand1) : 0; + m_operand2 = other.m_operand2 ? new Expression(*other.m_operand2) : 0; + m_value = other.m_value; + m_operation = other.m_operation; +} + +Expression& Expression::operator=(const Expression& other) +{ + delete m_operand1; + delete m_operand2; + m_operand1 = other.m_operand1 ? new Expression(*other.m_operand1) : 0; + m_operand2 = other.m_operand2 ? new Expression(*other.m_operand2) : 0; + m_operation = other.m_operation; + m_value = other.m_value; + return *this; +} + +Expression::~Expression() +{ + delete m_operand1; + delete m_operand2; +} + +Expression Expression::operator+(const Expression& other) +{ + Expression expr; + expr.m_operation = Add; + expr.m_operand1 = new Expression(*this); + expr.m_operand2 = new Expression(other); + return expr; +} + +Expression Expression::operator-(const Expression& other) +{ + Expression expr; + expr.m_operation = Add; + expr.m_operand1 = new Expression(*this); + expr.m_operand2 = new Expression(other); + return expr; +} + +Expression Expression::operator<(const Expression& other) +{ + Expression expr; + expr.m_operation = LessThan; + expr.m_operand1 = new Expression(*this); + expr.m_operand2 = new Expression(other); + return expr; +} + +Expression Expression::operator>(const Expression& other) +{ + Expression expr; + expr.m_operation = GreaterThan; + expr.m_operand1 = new Expression(*this); + expr.m_operand2 = new Expression(other); + return expr; +} + +std::string Expression::toString() const +{ + if (m_operation == None) { + std::ostringstream s; + s << m_value; + return s.str(); + } + + std::string result; + result += '('; + result += m_operand1->toString(); + char op; + switch (m_operation) { + case Add: + op = '+'; + break; + case Sub: + op = '-'; + break; + case LessThan: + op = '<'; + break; + case GreaterThan: + op = '<'; + break; + case None: // just to avoid the compiler warning + default: + op = '?'; + break; + } + result += op; + result += m_operand2->toString(); + result += ')'; + return result; +} + diff --git a/sources/shiboken2/tests/libsample/expression.h b/sources/shiboken2/tests/libsample/expression.h new file mode 100644 index 000000000..c4bb1a1f5 --- /dev/null +++ b/sources/shiboken2/tests/libsample/expression.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 EXPRESSION_H +#define EXPRESSION_H + +#include "libsamplemacros.h" +#include + +class LIBSAMPLE_API Expression +{ +public: + enum Operation { + None, Add, Sub, LessThan, GreaterThan + }; + + Expression(int number); + Expression(const Expression& other); + Expression& operator=(const Expression& other); + + ~Expression(); + + Expression operator>(const Expression& other); + Expression operator<(const Expression& other); + Expression operator+(const Expression& other); + Expression operator-(const Expression& other); + + std::string toString() const; +private: + int m_value; + Operation m_operation; + Expression* m_operand1; + Expression* m_operand2; + + Expression(); +}; + +#endif // EXPRESSION_H diff --git a/sources/shiboken2/tests/libsample/filter.cpp b/sources/shiboken2/tests/libsample/filter.cpp new file mode 100644 index 000000000..dac5d5e96 --- /dev/null +++ b/sources/shiboken2/tests/libsample/filter.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "filter.h" +Data::Data(Field field, std::string value) + : m_field(field), m_value(value) +{ +} + +Union::Union(const Data& filter) +{ + m_filters.push_back(filter); +} + +Union::Union(const Intersection& filter) +{ + m_filters.push_back(filter); +} + +Union::Union(const Union& filter) +{ + m_filters = filter.filters(); +} + +Intersection::Intersection(const Data& filter) +{ + m_filters.push_back(filter); +} + +Intersection::Intersection(const Union& filter) +{ + m_filters.push_back(filter); +} + +Intersection::Intersection(const Intersection& filter) +{ + m_filters = filter.filters(); +} + +Intersection operator&(const Intersection& a, const Intersection& b) +{ + Intersection filter; + filter.addFilter(a); + filter.addFilter(b); + + return filter; +} diff --git a/sources/shiboken2/tests/libsample/filter.h b/sources/shiboken2/tests/libsample/filter.h new file mode 100644 index 000000000..6ee2e6123 --- /dev/null +++ b/sources/shiboken2/tests/libsample/filter.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 FILTER_H +#define FILTER_H + +#include +#include + +#include "libsamplemacros.h" + +class Intersection; + +class LIBSAMPLE_API Filter +{ +}; + +class LIBSAMPLE_API Data : public Filter +{ + +public: + enum Field { + Name, + Album, + Year + }; + + Data(Field field, std::string value); + + Field field() const { return m_field; } + std::string value() const { return m_value; } + +private: + Field m_field; + std::string m_value; +}; + +class LIBSAMPLE_API Union : public Filter +{ +public: + + Union(const Data&); + Union(const Intersection&); + Union() {}; + Union(const Union&); + + std::list filters() const { return m_filters; } + void addFilter(const Filter& data) { m_filters.push_back(data); } + +private: + std::list m_filters; +}; + +class LIBSAMPLE_API Intersection : public Filter +{ +public: + + Intersection(const Data&); + Intersection(const Union&); + Intersection() {}; + Intersection(const Intersection&); + + std::list filters() const { return m_filters; } + void addFilter(const Filter& data) { m_filters.push_back(data); } + +private: + std::list m_filters; +}; + +LIBSAMPLE_API Intersection operator&(const Intersection& a, const Intersection& b); + +#endif // FILTER_H + + diff --git a/sources/shiboken2/tests/libsample/functions.cpp b/sources/shiboken2/tests/libsample/functions.cpp new file mode 100644 index 000000000..4a15cdae8 --- /dev/null +++ b/sources/shiboken2/tests/libsample/functions.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "functions.h" +#include +#include + +using namespace std; + +void +printSomething() +{ + cout << __FUNCTION__ << endl; +} + +int +gimmeInt() +{ + static int val = 2; + val = val * 1.3; + return val; +} + +double +gimmeDouble() +{ + static double val = 7.77; + val = val * 1.3; + return val; +} + +std::list +gimmeComplexList() +{ + std::list lst; + lst.push_back(Complex()); + lst.push_back(Complex(1.1, 2.2)); + lst.push_back(Complex(1.3, 2.4)); + return lst; +} + +Complex +sumComplexPair(std::pair cpx_pair) +{ + return cpx_pair.first + cpx_pair.second; +} + +double +multiplyPair(std::pair pair) +{ + return pair.first * pair.second; +} + +int +countCharacters(const char* text) +{ + if (!text) + return -1; + int count; + for(count = 0; text[count] != '\0'; count++) + ; + return count; +} + +char* +makeCString() +{ + char* string = new char[strlen(__FUNCTION__) + 1]; + strcpy(string, __FUNCTION__); + return string; +} + +const char* +returnCString() +{ + return __FUNCTION__; +} + +GlobalOverloadFuncEnum +overloadedFunc(int val) +{ + return GlobalOverloadFunc_i; +} + +GlobalOverloadFuncEnum +overloadedFunc(double val) +{ + return GlobalOverloadFunc_d; +} + +char* +returnNullPrimitivePointer() +{ + return 0; +} + +ObjectType* +returnNullObjectTypePointer() +{ + return 0; +} + +Event* +returnNullValueTypePointer() +{ + return 0; +} + +unsigned int +doubleUnsignedInt(unsigned int value) +{ + return value * 2; +} + +long long +doubleLongLong(long long value) +{ + return value * 2; +} + +unsigned long long +doubleUnsignedLongLong(unsigned long long value) +{ + return value * 2; +} + +short +doubleShort(short value) +{ + return value * 2; +} + +int +acceptInt(int x) +{ + return x; +} + +unsigned int +acceptUInt(unsigned int x) +{ + return x; +} + +long +acceptLong(long x) +{ + return x; +} + +unsigned long +acceptULong(unsigned long x) +{ + return x; +} + +double +acceptDouble(double x) +{ + return x; +} + +int +acceptIntReference(int& x) +{ + return x; +} + +OddBool +acceptOddBoolReference(OddBool& x) +{ + return x; +} + +ClassWithFunctionPointer::ClassWithFunctionPointer() +{ + callFunctionPointer(0, &ClassWithFunctionPointer::doNothing); +} + +void ClassWithFunctionPointer::callFunctionPointer(int dummy, void (*fp)(void *)) +{ + size_t a = dummy; + fp(reinterpret_cast(a)); +} + +void ClassWithFunctionPointer::doNothing(void *operand) +{ + (void) operand; +} diff --git a/sources/shiboken2/tests/libsample/functions.h b/sources/shiboken2/tests/libsample/functions.h new file mode 100644 index 000000000..89a175bc4 --- /dev/null +++ b/sources/shiboken2/tests/libsample/functions.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 FUNCTIONS_H +#define FUNCTIONS_H + +#include "libsamplemacros.h" +#include +#include +#include "oddbool.h" +#include "complex.h" +#include "objecttype.h" + +enum GlobalEnum { + NoThing, + FirstThing, + SecondThing, + ThirdThing +}; + +enum GlobalOverloadFuncEnum { + GlobalOverloadFunc_i, + GlobalOverloadFunc_d +}; + +LIBSAMPLE_API void printSomething(); +LIBSAMPLE_API int gimmeInt(); +LIBSAMPLE_API double gimmeDouble(); +LIBSAMPLE_API double multiplyPair(std::pair pair); +LIBSAMPLE_API std::list gimmeComplexList(); +LIBSAMPLE_API Complex sumComplexPair(std::pair cpx_pair); + +LIBSAMPLE_API int countCharacters(const char* text); +LIBSAMPLE_API char* makeCString(); +LIBSAMPLE_API const char* returnCString(); + +LIBSAMPLE_API char* returnNullPrimitivePointer(); +LIBSAMPLE_API ObjectType* returnNullObjectTypePointer(); +LIBSAMPLE_API Event* returnNullValueTypePointer(); + +// Tests overloading on functions (!methods) +LIBSAMPLE_API GlobalOverloadFuncEnum overloadedFunc(int val); +LIBSAMPLE_API GlobalOverloadFuncEnum overloadedFunc(double val); + +LIBSAMPLE_API unsigned int doubleUnsignedInt(unsigned int value); +LIBSAMPLE_API long long doubleLongLong(long long value); +LIBSAMPLE_API unsigned long long doubleUnsignedLongLong(unsigned long long value); +LIBSAMPLE_API short doubleShort(short value); + +LIBSAMPLE_API int acceptInt(int x); +LIBSAMPLE_API unsigned int acceptUInt(unsigned int x); +LIBSAMPLE_API long acceptLong(long x); +LIBSAMPLE_API unsigned long acceptULong(unsigned long x); +LIBSAMPLE_API double acceptDouble(double x); + +LIBSAMPLE_API int acceptIntReference(int& x); +LIBSAMPLE_API OddBool acceptOddBoolReference(OddBool& x); + + +class LIBSAMPLE_API ClassWithFunctionPointer +{ +public: + explicit ClassWithFunctionPointer(); + void callFunctionPointer(int dummy, void (*fp)(void *)); + static void doNothing(void *operand); +}; + +#endif // FUNCTIONS_H diff --git a/sources/shiboken2/tests/libsample/handle.cpp b/sources/shiboken2/tests/libsample/handle.cpp new file mode 100644 index 000000000..e0b1d8d18 --- /dev/null +++ b/sources/shiboken2/tests/libsample/handle.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "handle.h" + +HANDLE HandleHolder::createHandle() +{ + return (HANDLE) new OBJ; +} + +bool HandleHolder::compare(HandleHolder* other) +{ + return other->m_handle == m_handle; +} + +bool HandleHolder::compare2(HandleHolder* other) +{ + return other->m_handle2 == m_handle2; +} diff --git a/sources/shiboken2/tests/libsample/handle.h b/sources/shiboken2/tests/libsample/handle.h new file mode 100644 index 000000000..d656f946b --- /dev/null +++ b/sources/shiboken2/tests/libsample/handle.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 HANDLE_H +#define HANDLE_H + +#include "libsamplemacros.h" + +/* See http://bugs.pyside.org/show_bug.cgi?id=1105. */ +namespace Foo { + typedef unsigned long HANDLE; +} + +class LIBSAMPLE_API OBJ +{ +}; + +typedef OBJ* HANDLE; + +class LIBSAMPLE_API HandleHolder +{ +public: + explicit HandleHolder(HANDLE ptr = 0) : m_handle(ptr) {} + explicit HandleHolder(Foo::HANDLE val): m_handle2(val) {} + + inline void set(HANDLE ptr) { HANDLE tmp; tmp = m_handle; m_handle = tmp; } + inline void set(const Foo::HANDLE& val) { m_handle2 = val; } + inline HANDLE handle() { return m_handle; } + inline Foo::HANDLE handle2() { return m_handle2; } + + static HANDLE createHandle(); + bool compare(HandleHolder* other); + bool compare2(HandleHolder* other); + +private: + HANDLE m_handle; + Foo::HANDLE m_handle2; +}; + +struct LIBSAMPLE_API PrimitiveStruct {}; +typedef struct PrimitiveStruct* PrimitiveStructPtr; +struct LIBSAMPLE_API PrimitiveStructPointerHolder +{ + PrimitiveStructPtr primitiveStructPtr; +}; + +#endif // HANDLE_H diff --git a/sources/shiboken2/tests/libsample/implicitconv.cpp b/sources/shiboken2/tests/libsample/implicitconv.cpp new file mode 100644 index 000000000..df4af2537 --- /dev/null +++ b/sources/shiboken2/tests/libsample/implicitconv.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "implicitconv.h" + +ImplicitConv +ImplicitConv::implicitConvCommon(ImplicitConv implicit) +{ + return implicit; +} + +ImplicitConv +ImplicitConv::implicitConvDefault(ImplicitConv implicit) +{ + return implicit; +} + +ImplicitConv::ICOverloadedFuncEnum +ImplicitConv::implicitConvOverloading(ImplicitConv implicit, int dummyArg) +{ + return ImplicitConv::OverFunc_Ii; +} + +ImplicitConv::ICOverloadedFuncEnum +ImplicitConv::implicitConvOverloading(ImplicitConv implicit, bool dummyArg) +{ + return ImplicitConv::OverFunc_Ib; +} + +ImplicitConv::ICOverloadedFuncEnum +ImplicitConv::implicitConvOverloading(int dummyArg) +{ + return ImplicitConv::OverFunc_i; +} + +ImplicitConv::ICOverloadedFuncEnum +ImplicitConv::implicitConvOverloading(CtorEnum dummyArg) +{ + return ImplicitConv::OverFunc_C; +} + diff --git a/sources/shiboken2/tests/libsample/implicitconv.h b/sources/shiboken2/tests/libsample/implicitconv.h new file mode 100644 index 000000000..2a8ac66c2 --- /dev/null +++ b/sources/shiboken2/tests/libsample/implicitconv.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 IMPLICITCONV_H +#define IMPLICITCONV_H + +#include "libsamplemacros.h" +#include "null.h" + +class ObjectType; + +class LIBSAMPLE_API ImplicitConv +{ +public: + enum CtorEnum { + CtorNone, + CtorOne, + CtorTwo, + CtorThree, + CtorObjectTypeReference, + CtorPrimitiveType + }; + + enum ICOverloadedFuncEnum { + OverFunc_Ii, + OverFunc_Ib, + OverFunc_i, + OverFunc_C + }; + + ImplicitConv() : m_ctorEnum(CtorNone), m_objId(-1), m_value(-1.0) {} + ImplicitConv(int objId) : m_ctorEnum(CtorOne), m_objId(objId), m_value(-1.0) {} + ImplicitConv(CtorEnum ctorEnum) : m_ctorEnum(ctorEnum), m_objId(-1), m_value(-1.0) {} + ImplicitConv(ObjectType&) : m_ctorEnum(CtorObjectTypeReference), m_objId(-1), m_value(-1.0) {} + ImplicitConv(double value, bool=true) : m_ctorEnum(CtorNone), m_value(value) {} + ImplicitConv(const Null& null) : m_ctorEnum(CtorPrimitiveType) {} + ~ImplicitConv() {} + + inline CtorEnum ctorEnum() { return m_ctorEnum; } + inline int objId() { return m_objId; } + inline double value() { return m_value; } + + static ImplicitConv implicitConvCommon(ImplicitConv implicit); + + static ImplicitConv implicitConvDefault(ImplicitConv implicit = CtorTwo); + + static ICOverloadedFuncEnum implicitConvOverloading(ImplicitConv implicit, int dummyArg); + static ICOverloadedFuncEnum implicitConvOverloading(ImplicitConv implicit, bool dummyArg); + static ICOverloadedFuncEnum implicitConvOverloading(int dummyArg); + static ICOverloadedFuncEnum implicitConvOverloading(CtorEnum dummyArg); + +private: + CtorEnum m_ctorEnum; + int m_objId; + double m_value; +}; + +#endif // IMPLICITCONV_H diff --git a/sources/shiboken2/tests/libsample/injectcode.cpp b/sources/shiboken2/tests/libsample/injectcode.cpp new file mode 100644 index 000000000..4406cdc5c --- /dev/null +++ b/sources/shiboken2/tests/libsample/injectcode.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "injectcode.h" +#include + +using namespace std; + +InjectCode::InjectCode() +{ +} + +InjectCode::~InjectCode() +{ +} + +template +const char* InjectCode::toStr(const T& value) +{ + std::ostringstream s; + s << value; + m_valueHolder = s.str(); + return m_valueHolder.c_str(); +} + +const char* InjectCode::simpleMethod1(int arg0, int arg1) +{ + return toStr(arg0 + arg1); +} + +const char* InjectCode::simpleMethod2() +{ + return "_"; +} + +const char* InjectCode::simpleMethod3(int argc, char** argv) +{ + for (int i = 0; i < argc; ++i) + m_valueHolder += argv[i]; + return m_valueHolder.c_str(); +} + +const char* InjectCode::overloadedMethod(int arg0, bool arg1) +{ + toStr(arg0); + m_valueHolder += arg1 ? "true" : "false"; + return m_valueHolder.c_str(); +} + +const char* InjectCode::overloadedMethod(int arg0, double arg1) +{ + return toStr(arg0 + arg1); +} + +const char* InjectCode::overloadedMethod(int argc, char** argv) +{ + return simpleMethod3(argc, argv); +} + +const char* InjectCode::virtualMethod(int arg) +{ + return toStr(arg); +} + +int InjectCode::arrayMethod(int count, int *values) const +{ + int ret = 0; + for (int i=0; i < count; i++) + ret += values[i]; + return ret; +} + +int InjectCode::sumArrayAndLength(int* values) const +{ + int sum = 0; + + while(*values) { + sum = sum + *values + 1; + values++; + } + + return sum; +} diff --git a/sources/shiboken2/tests/libsample/injectcode.h b/sources/shiboken2/tests/libsample/injectcode.h new file mode 100644 index 000000000..ba1bedb17 --- /dev/null +++ b/sources/shiboken2/tests/libsample/injectcode.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 INJECTCODE_H +#define INJECTCODE_H + +#include "libsamplemacros.h" +#include +#include + +class LIBSAMPLE_API InjectCode +{ +public: + InjectCode(); + virtual ~InjectCode(); + + const char* simpleMethod1(int arg0, int arg1); + const char* simpleMethod2(); + const char* simpleMethod3(int argc, char** argv); + + const char* overloadedMethod(int argc, char** argv); + const char* overloadedMethod(int arg0, double arg1); + const char* overloadedMethod(int arg0, bool arg1); + + virtual int arrayMethod(int count, int* values) const; + inline int callArrayMethod(int count, int *values) const { return arrayMethod(count, values); } + virtual const char* virtualMethod(int arg); + int sumArrayAndLength(int* values) const; +private: + // This attr is just to retain the memory pointed by all return values, + // So, the memory returned by all methods will be valid until someone call + // another method of this class. + std::string m_valueHolder; + + template + const char* toStr(const T& value); +}; + +#endif // INJECTCODE_H + diff --git a/sources/shiboken2/tests/libsample/libsamplemacros.h b/sources/shiboken2/tests/libsample/libsamplemacros.h new file mode 100644 index 000000000..6a1bba88d --- /dev/null +++ b/sources/shiboken2/tests/libsample/libsamplemacros.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 LIBSAMPLEMACROS_H +#define LIBSAMPLEMACROS_H + +#if defined _WIN32 || defined __CYGWIN__ + #if LIBSAMPLE_BUILD + #define LIBSAMPLE_API __declspec(dllexport) + #else + #define LIBSAMPLE_API __declspec(dllimport) + #endif +#else +#if __GNUC__ >= 4 + #define LIBSAMPLE_API __attribute__ ((visibility("default"))) +#else + #define LIBSAMPLE_API +#endif +#endif + +#endif diff --git a/sources/shiboken2/tests/libsample/list.h b/sources/shiboken2/tests/libsample/list.h new file mode 100644 index 000000000..f1183440c --- /dev/null +++ b/sources/shiboken2/tests/libsample/list.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 LIST_H +#define LIST_H + +#include +#include "libsamplemacros.h" +#include "point.h" + +class ObjectType; + +template +class List : public std::list +{ +}; + +class IntList : public List +{ +public: + enum CtorEnum { + NoParamsCtor, + IntCtor, + CopyCtor, + ListOfIntCtor + }; + + inline IntList() : m_ctorUsed(NoParamsCtor) {} + inline explicit IntList(int val) : m_ctorUsed(IntCtor) { push_back(val); } + inline IntList(const IntList& lst) : List(lst), m_ctorUsed(CopyCtor) {} + inline IntList(const List& lst) : List(lst), m_ctorUsed(ListOfIntCtor) {} + + inline void append(int v) { insert(end(), v); } + CtorEnum constructorUsed() { return m_ctorUsed; } +private: + CtorEnum m_ctorUsed; +}; + +class PointValueList : public List +{ +public: + enum CtorEnum { + NoParamsCtor, + PointCtor, + CopyCtor, + ListOfPointValuesCtor + }; + + inline PointValueList() : m_ctorUsed(NoParamsCtor) {} + inline explicit PointValueList(Point val) : m_ctorUsed(PointCtor) { push_back(val); } + inline PointValueList(const PointValueList& lst) : List(lst), m_ctorUsed(CopyCtor) {} + inline PointValueList(const List& lst) : List(lst), m_ctorUsed(ListOfPointValuesCtor) {} + + inline void append(Point v) { insert(end(), v); } + CtorEnum constructorUsed() { return m_ctorUsed; } +private: + CtorEnum m_ctorUsed; +}; + +class ObjectTypePtrList : public List +{ +public: + enum CtorEnum { + NoParamsCtor, + ObjectTypeCtor, + CopyCtor, + ListOfObjectTypePtrCtor + }; + + inline ObjectTypePtrList() : m_ctorUsed(NoParamsCtor) {} + inline explicit ObjectTypePtrList(ObjectType* val) : m_ctorUsed(ObjectTypeCtor) { push_back(val); } + inline ObjectTypePtrList(const ObjectTypePtrList& lst) : List(lst), m_ctorUsed(CopyCtor) {} + inline ObjectTypePtrList(const List& lst) : List(lst), m_ctorUsed(ListOfObjectTypePtrCtor) {} + + inline void append(ObjectType* v) { insert(end(), v); } + CtorEnum constructorUsed() { return m_ctorUsed; } +private: + CtorEnum m_ctorUsed; +}; + +#endif // LIST_H diff --git a/sources/shiboken2/tests/libsample/listuser.cpp b/sources/shiboken2/tests/libsample/listuser.cpp new file mode 100644 index 000000000..24389766e --- /dev/null +++ b/sources/shiboken2/tests/libsample/listuser.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include +#include "listuser.h" + +using namespace std; + +std::list +ListUser::callCreateList() +{ + return createList(); +} + +std::list +ListUser::createList() +{ + std::list retval; + for (int i = 0; i < 4; i++) + retval.push_front(rand()); + return retval; +} + +std::list +ListUser::createComplexList(Complex cpx0, Complex cpx1) +{ + std::list retval; + retval.push_back(cpx0); + retval.push_back(cpx1); + return retval; +} + +double +ListUser::sumList(std::list vallist) +{ + return std::accumulate(vallist.begin(), vallist.end(), 0.0); +} + +double +ListUser::sumList(std::list vallist) +{ + return std::accumulate(vallist.begin(), vallist.end(), 0.0); +} + +ListUser::ListOfSomething +ListUser::listOfPoints(const std::list& pointlist) +{ + return ListOfPoint; +} + +ListUser::ListOfSomething +ListUser::listOfPoints(const std::list& pointlist) +{ + return ListOfPointF; +} + +void +ListUser::multiplyPointList(PointList& points, double multiplier) +{ + for(PointList::iterator piter = points.begin(); piter != points.end(); piter++) { + (*piter)->setX((*piter)->x() * multiplier); + (*piter)->setY((*piter)->y() * multiplier); + } +} + diff --git a/sources/shiboken2/tests/libsample/listuser.h b/sources/shiboken2/tests/libsample/listuser.h new file mode 100644 index 000000000..8f49c80d3 --- /dev/null +++ b/sources/shiboken2/tests/libsample/listuser.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 LISTUSER_H +#define LISTUSER_H + +#include +#include "complex.h" +#include "point.h" +#include "pointf.h" + +#include "libsamplemacros.h" + +class LIBSAMPLE_API ListUser +{ +public: + typedef std::list PointList; + + enum ListOfSomething { + ListOfPoint, + ListOfPointF + }; + + ListUser() {} + ListUser(const ListUser& other) : m_lst(other.m_lst) {} + virtual ~ListUser() {} + + virtual std::list createList(); + std::list callCreateList(); + + static std::list createComplexList(Complex cpx0, Complex cpx1); + + double sumList(std::list vallist); + double sumList(std::list vallist); + + static ListOfSomething listOfPoints(const std::list& pointlist); + static ListOfSomething listOfPoints(const std::list& pointlist); + + static void multiplyPointList(PointList& points, double multiplier); + + inline void setList(std::list lst) { m_lst = lst; } + inline std::list getList() { return m_lst; } + +private: + std::list m_lst; +}; + +#endif // LISTUSER_H + diff --git a/sources/shiboken2/tests/libsample/main.cpp b/sources/shiboken2/tests/libsample/main.cpp new file mode 100644 index 000000000..b22d05a36 --- /dev/null +++ b/sources/shiboken2/tests/libsample/main.cpp @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include +#include "abstract.h" +#include "derived.h" +#include "kindergarten.h" +#include "complex.h" +#include "point.h" +#include "size.h" +#include "listuser.h" +#include "samplenamespace.h" + +using namespace std; + +int +main(int argv, char **argc) +{ + cout << endl; + + Derived derived; + + cout << endl; + + derived.unpureVirtual(); + derived.pureVirtual(); + derived.callPureVirtual(); + + cout << endl; + Abstract* abs; + abs = Abstract::createObject(); + cout << "Abstract::createObject(): " << abs << endl << endl; + delete abs; + + abs = Derived::createObject(); + cout << "Derived::createObject() : "; + abs->show(); + cout << endl; + delete abs; + cout << endl; + + abs = Derived::createObject(); + cout << "Derived::createObject() : "; + abs->show(); + cout << endl; + delete abs; + cout << endl; + + cout << endl << "-----------------------------------------" << endl; + + KinderGarten kg; + Derived* d[] = { 0, 0, 0 }; + + for (int i = 0; i < 3; i++) { + d[i] = new Derived(i); + d[i]->show(); + cout << endl; + kg.addChild(d[i]); + } + + kg.show(); + cout << endl; + + cout << endl << "* kill child "; + d[2]->show(); + cout << " ----------------" << endl; + kg.killChild(d[2]); + kg.show(); + cout << endl; + + cout << endl << "* release child "; + d[1]->show(); + cout << " -------------" << endl; + Abstract* released = kg.releaseChild(d[1]); + cout << "released: "; + released->show(); + cout << endl; + kg.show(); + cout << endl; + + cout << endl << "* kill children ------------------------------------" << endl; + kg.killChildren(); + kg.show(); + cout << endl << endl; + + cout << "-----------------------------------------" << endl; + ListUser lu; + cout << "ListUser::createList()" << endl; + std::list intlist = lu.createList(); + for (std::list::iterator it = intlist.begin(); it != intlist.end(); it++) { + cout << "* " << *it << endl; + } + + cout << "ListUser::createComplexList" << endl; + std::list cpxlist = ListUser::createComplexList(Complex(1.1, 2.2), Complex(3.3, 4.4)); + for (std::list::iterator it = cpxlist.begin(); it != cpxlist.end(); it++) { + cout << "* "; + (*it).show(); + cout << endl; + } + cout << endl; + + cout << "-----------------------------------------" << endl; + cout << "SampleNamespace" << endl; + + cout << "SampleNamespace::RandomNumber: "; + cout << SampleNamespace::getNumber(SampleNamespace::RandomNumber); + cout << endl; + cout << "SampleNamespace::UnixTime: "; + cout << SampleNamespace::getNumber(SampleNamespace::UnixTime); + cout << endl; + double val_d = 1.3; + cout << "SampleNamespace::powerOfTwo(" << val_d << "): "; + cout << SampleNamespace::powerOfTwo(val_d) << endl; + int val_i = 7; + cout << "SampleNamespace::powerOfTwo(" << val_i << "): "; + cout << SampleNamespace::powerOfTwo(val_i) << endl; + cout << endl; + + cout << "-----------------------------------------" << endl; + cout << "Point" << endl; + + Point p1(1.1, 2.2); + cout << "p1: "; + p1.show(); + cout << endl; + + Point p2(3.4, 5.6); + cout << "p2: "; + p2.show(); + cout << endl; + + cout << "p1 + p2 == "; + (p1 + p2).show(); + cout << endl; + + cout << "p1 * 2.0 == "; + (p1 * 2.0).show(); + cout << endl; + + cout << "1.5 * p2 == "; + (1.5 * p2).show(); + cout << endl; + + cout << "p1: "; + p1.show(); + cout << endl << "p2: "; + p2.show(); + cout << endl << "p1 += p2" << endl; + p1 += p2; + cout << "p1: "; + p1.show(); + cout << endl; + + cout << "p1 == p2 ? " << ((p1 == p2) ? "true" : "false") << endl; + cout << "p1 == p1 ? " << ((p1 == p1) ? "true" : "false") << endl; + cout << "p2 == p2 ? " << ((p2 == p2) ? "true" : "false") << endl; + + cout << "-----------------------------------------" << endl; + cout << "Size" << endl; + + Size s1(2, 2); + cout << "s1: "; + s1.show(); + cout << ", area: " << s1.calculateArea(); + cout << endl; + + Size s2(3, 5); + cout << "s2: "; + s2.show(); + cout << ", area: " << s2.calculateArea(); + cout << endl; + + cout << endl; + + cout << "s1 == s2 ? " << ((s1 == s2) ? "true" : "false") << endl; + cout << "s1 != s2 ? " << ((s1 != s2) ? "true" : "false") << endl; + + cout << "s1 < s2 ? " << ((s1 < s2) ? "true" : "false") << endl; + cout << "s1 <= s2 ? " << ((s1 <= s2) ? "true" : "false") << endl; + cout << "s1 > s2 ? " << ((s1 > s2) ? "true" : "false") << endl; + cout << "s1 >= s2 ? " << ((s1 >= s2) ? "true" : "false") << endl; + + cout << "s1 < 10 ? " << ((s1 < 10) ? "true" : "false") << endl; + cout << "s1 <= 10 ? " << ((s1 <= 10) ? "true" : "false") << endl; + cout << "s1 > 10 ? " << ((s1 > 10) ? "true" : "false") << endl; + cout << "s1 >= 10 ? " << ((s1 >= 10) ? "true" : "false") << endl; + cout << "s2 < 10 ? " << ((s2 < 10) ? "true" : "false") << endl; + cout << "s2 <= 10 ? " << ((s2 <= 10) ? "true" : "false") << endl; + cout << "s2 > 10 ? " << ((s2 > 10) ? "true" : "false") << endl; + cout << "s2 >= 10 ? " << ((s2 >= 10) ? "true" : "false") << endl; + cout << endl; + + cout << "s1: "; + s1.show(); + cout << endl << "s2: "; + s2.show(); + cout << endl << "s1 += s2" << endl; + s1 += s2; + cout << "s1: "; + s1.show(); + cout << endl; + + cout << endl; + + cout << "s1: "; + s1.show(); + cout << endl << "s1 *= 2.0" << endl; + s1 *= 2.0; + cout << "s1: "; + s1.show(); + cout << endl; + + cout << endl; + + return 0; +} + diff --git a/sources/shiboken2/tests/libsample/mapuser.cpp b/sources/shiboken2/tests/libsample/mapuser.cpp new file mode 100644 index 000000000..666188512 --- /dev/null +++ b/sources/shiboken2/tests/libsample/mapuser.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "mapuser.h" + +using namespace std; + +std::map > +MapUser::callCreateMap() +{ + return createMap(); +} + + +std::map > +MapUser::createMap() +{ + std::map > retval; + + std::pair > + item0("zero", std::pair(Complex(1.2, 3.4), 2)); + retval.insert(item0); + + std::pair > + item1("one", std::pair(Complex(5.6, 7.8), 3)); + retval.insert(item1); + + std::pair > + item2("two", std::pair(Complex(9.1, 2.3), 5)); + retval.insert(item2); + + return retval; +} + +void +MapUser::showMap(std::map mapping) +{ + std::map::iterator it; + cout << __FUNCTION__ << endl; + for (it = mapping.begin() ; it != mapping.end(); it++) + cout << (*it).first << " => " << (*it).second << endl; +} + diff --git a/sources/shiboken2/tests/libsample/mapuser.h b/sources/shiboken2/tests/libsample/mapuser.h new file mode 100644 index 000000000..90d036945 --- /dev/null +++ b/sources/shiboken2/tests/libsample/mapuser.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 MAPUSER_H +#define MAPUSER_H + +#include +#include +#include +#include +#include "complex.h" +#include "bytearray.h" + +#include "libsamplemacros.h" + +class LIBSAMPLE_API MapUser +{ +public: + MapUser() {} + virtual ~MapUser() {} + + virtual std::map > createMap(); + std::map > callCreateMap(); + + void showMap(std::map mapping); + + inline void setMap(std::map > map) { m_map = map; } + inline std::map > getMap() { return m_map; } + + // Compile test + static void pointerToMap(std::map* arg) {} + static void referenceToMap(std::map& arg) {} + + inline const std::map& passMapIntValueType(const std::map& arg) { return arg; } + +private: + std::map > m_map; +}; + +#endif // MAPUSER_H diff --git a/sources/shiboken2/tests/libsample/modelindex.h b/sources/shiboken2/tests/libsample/modelindex.h new file mode 100644 index 000000000..12cc97ce4 --- /dev/null +++ b/sources/shiboken2/tests/libsample/modelindex.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 MODELINDEX_H +#define MODELINDEX_H + +#include "libsamplemacros.h" + +class ModelIndex +{ +public: + ModelIndex() : m_value(0) {} + ModelIndex(const ModelIndex& other) { m_value = other.m_value; } + inline void setValue(int value) { m_value = value; } + inline int value() const { return m_value; } + static int getValue(const ModelIndex& index) { return index.value(); } +private: + int m_value; +}; + +class ReferentModelIndex +{ +public: + ReferentModelIndex() {} + ReferentModelIndex(const ModelIndex& index) : m_index(index) {} + ReferentModelIndex(const ReferentModelIndex& other) { m_index = other.m_index; } + inline void setValue(int value) { m_index.setValue(value); } + inline int value() const { return m_index.value(); } + operator const ModelIndex&() const { return m_index; } +private: + ModelIndex m_index; +}; + +class PersistentModelIndex +{ +public: + PersistentModelIndex() {} + PersistentModelIndex(const ModelIndex& index) : m_index(index) {} + PersistentModelIndex(const PersistentModelIndex& other) { m_index = other.m_index; } + inline void setValue(int value) { m_index.setValue(value); } + inline int value() const { return m_index.value(); } + operator ModelIndex() const { return m_index; } +private: + ModelIndex m_index; +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/modifications.cpp b/sources/shiboken2/tests/libsample/modifications.cpp new file mode 100644 index 000000000..4a60a8071 --- /dev/null +++ b/sources/shiboken2/tests/libsample/modifications.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "modifications.h" +#include "objecttype.h" + +using namespace std; + +Modifications::Modifications() +{ + m_object = new ObjectType(); + m_object->setObjectName("MyObject"); +} + +Modifications::~Modifications() +{ + delete m_object; +} + +std::pair +Modifications::pointToPair(Point pt, bool* ok) +{ + std::pair retval(pt.x(), pt.y()); + *ok = true; + return retval; +} + +double +Modifications::multiplyPointCoordsPlusValue(bool* ok, Point pt, double value) +{ + double retval = (pt.x() * pt.y()) + value; + *ok = true; + return retval; +} + +int +Modifications::doublePlus(int value, int plus) +{ + return (2 * value) + plus; +} + +int +Modifications::power(int base, int exponent) +{ + if (exponent == 0) + return 1; + int retval = base; + for (int i = 1; i < exponent; i++) + retval = retval * base; + return retval; +} + +int +Modifications::timesTen(int number) +{ + return number * 10; +} + +int +Modifications::increment(int number) +{ + return ++number; +} + +void +Modifications::exclusiveCppStuff() +{ + cout << __FUNCTION__ << endl; +} + +int +Modifications::cppMultiply(int a, int b) +{ + return a * b; +} + +const char* +Modifications::className() +{ + return "Modifications"; +} + +Point +Modifications::sumPointArray(int arraySize, const Point pointArray[]) +{ + Point point; + for (int i = 0; i < arraySize; ++i) + point = point + pointArray[i]; + return point; +} + +int +Modifications::getSize(const void* data, int size) +{ + (void)data; + return size; +} + +int +Modifications::sumPointCoordinates(const Point* point) +{ + return point->x() + point->y(); +} + +double +Modifications::differenceOfPointCoordinates(const Point* pt, bool* ok) +{ + if (!pt) { + *ok = false; + return 0.0; + } + *ok = true; + double result = pt->x() - pt->y(); + if (result < 0) + result = result * -1.0; + return result; +} + +bool +Modifications::nonConversionRuleForArgumentWithDefaultValue(ObjectType** object) +{ + if (object) + *object = m_object; + return true; +} diff --git a/sources/shiboken2/tests/libsample/modifications.h b/sources/shiboken2/tests/libsample/modifications.h new file mode 100644 index 000000000..2978270b0 --- /dev/null +++ b/sources/shiboken2/tests/libsample/modifications.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 MODIFICATIONS_H +#define MODIFICATIONS_H + +#include "libsamplemacros.h" +#include +#include "point.h" +#include "oddbool.h" + +class ObjectType; + +class LIBSAMPLE_API Modifications +{ +public: + Modifications(); + virtual ~Modifications(); + + enum OverloadedModFunc { + OverloadedNone, + Overloaded_ibid, + Overloaded_ibib, + Overloaded_ibiP, + Overloaded_ibii, + Overloaded_ibPP + }; + + // those overloaded methods should be heavily modified + // to push the overload decisor to its limits + inline OverloadedModFunc overloaded(int a0, bool b0, int c0, double d0) { return Overloaded_ibid; } + inline OverloadedModFunc overloaded(int a1, bool b1, int c1, bool d1) { return Overloaded_ibib; } + inline OverloadedModFunc overloaded(int a2, bool b2, int c2, Point d2) { return Overloaded_ibiP; } + inline OverloadedModFunc overloaded(int a3, bool b3, int c3 = 123, int d3 = 456) { return Overloaded_ibii; } + inline OverloadedModFunc overloaded(int a4, bool b4, Point c4, Point d4) { return Overloaded_ibPP; } + + inline void argRemoval0(int a0, bool a1, int a2 = 123, int a3 = 456) {} + inline void argRemoval0(int a0, bool a1, int a2, bool a3) {} + + inline void argRemoval1(int a0, bool a1, Point a2 = Point(1, 2), Point a3 = Point(3, 4), int a4 = 333) {} + inline void argRemoval1(int a0, bool a1, int a2, bool a3) {} + + inline void argRemoval2(int a0, bool a1, Point a2 = Point(1, 2), Point a3 = Point(3, 4), int a4 = 333) {} + + inline void argRemoval3(int a0, Point a1 = Point(1, 2), bool a2 = true, Point a3 = Point(3, 4), int a4 = 333) {} + + inline void argRemoval4(int a0, Point a1, bool a2, Point a3 = Point(3, 4), int a4 = 333) {} + + inline void argRemoval5(int a0, bool a1, Point a2 = Point(1, 2), Point a3 = Point(3, 4), int a4 = 333) {} + inline void argRemoval5(int a0, bool a1, int a2, bool a3) {} + + // 'ok' must be removed and the return value will be changed + // to a tuple (PyObject*) containing the expected result plus + // the 'ok' value as a Python boolean + std::pair pointToPair(Point pt, bool* ok); + + // same as 'pointToPair' except that this time 'ok' is the first argument + double multiplyPointCoordsPlusValue(bool* ok, Point pt, double value); + + // completely remove 'plus' from the Python side + int doublePlus(int value, int plus = 0); + + // the default value for both arguments must be changed in Python + int power(int base = 1, int exponent = 0); + + // in Python set argument default value to 10 + int timesTen(int number); + + // in Python remove the argument default value + int increment(int number = 0); + + // don't export this method to Python + void exclusiveCppStuff(); + + // change the name of this regular method + int cppMultiply(int a, int b); + + // change the name of this virtual method + virtual const char* className(); + + Point sumPointArray(int arraySize, const Point pointArray[]); + + // Replace 'const void*' by 'ByteArray&'. + int getSize(const void* data, int size); + + // Mark the argument with a tag; + // the test implementation must expect point never to be null. + int sumPointCoordinates(const Point* point); + + // Modify the return value of a virtual method. + virtual double differenceOfPointCoordinates(const Point* pt, bool* ok); + double callDifferenceOfPointCoordinates(const Point* pt, bool* ok) { return differenceOfPointCoordinates(pt, ok); } + + // Sets an ObjectType in the argument and returns true. + bool nonConversionRuleForArgumentWithDefaultValue(ObjectType** object = 0); + ObjectType* getObject() const { return m_object; } + + // Inject code with a %CONVERTTOPYTHON that receives an user's primitive type. + static inline OddBool passOddBool(OddBool ob) { return ob; } + +private: + ObjectType* m_object; +}; + +class LIBSAMPLE_API AbstractModifications : public Modifications +{ +public: + AbstractModifications() {} + virtual ~AbstractModifications() {} + + inline bool invert(bool value) { return !value; } + + // completely remove this method in Python + virtual void pointlessPureVirtualMethod() = 0; +}; + +#endif // MODIFICATIONS_H diff --git a/sources/shiboken2/tests/libsample/modified_constructor.cpp b/sources/shiboken2/tests/libsample/modified_constructor.cpp new file mode 100644 index 000000000..48224358f --- /dev/null +++ b/sources/shiboken2/tests/libsample/modified_constructor.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "modified_constructor.h" + +ModifiedConstructor::ModifiedConstructor(int first_arg) +{ + m_stored_value = first_arg; +} + +int +ModifiedConstructor::retrieveValue() +{ + return m_stored_value; +} + + diff --git a/sources/shiboken2/tests/libsample/modified_constructor.h b/sources/shiboken2/tests/libsample/modified_constructor.h new file mode 100644 index 000000000..9ac5497d7 --- /dev/null +++ b/sources/shiboken2/tests/libsample/modified_constructor.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 MODIFIEDCONSTRUCTOR_H +#define MODIFIEDCONSTRUCTOR_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API ModifiedConstructor +{ +public: + + ModifiedConstructor(int first_arg); + int retrieveValue(); + +private: + int m_stored_value; +}; + +#endif // MODIFIEDCONSTRUCTOR_H + diff --git a/sources/shiboken2/tests/libsample/multiple_derived.cpp b/sources/shiboken2/tests/libsample/multiple_derived.cpp new file mode 100644 index 000000000..1d7a33cbe --- /dev/null +++ b/sources/shiboken2/tests/libsample/multiple_derived.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "multiple_derived.h" + +MDerived1::MDerived1() : m_value(100) +{ +} + +MDerived2::MDerived2() : m_value(200) +{ +} + +MDerived3::MDerived3() : m_value(3000) +{ +} + +MDerived4::MDerived4() +{ +} + +MDerived5::MDerived5() +{ +} + +MDerived1* +MDerived1::transformFromBase1(Base1* self) +{ + MDerived1* ptr = dynamic_cast(self); + return ptr; +} + +MDerived1* +MDerived1::transformFromBase2(Base2* self) +{ + MDerived1* ptr = dynamic_cast(self); + return ptr; +} + diff --git a/sources/shiboken2/tests/libsample/multiple_derived.h b/sources/shiboken2/tests/libsample/multiple_derived.h new file mode 100644 index 000000000..5825e59b4 --- /dev/null +++ b/sources/shiboken2/tests/libsample/multiple_derived.h @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 MDERIVED_H +#define MDERIVED_H + +#include "libsamplemacros.h" +#include + +class Base1 +{ +public: + Base1() : m_value(1) {} + virtual ~Base1() {} + virtual int base1Method() { return m_value; } + + virtual void publicMethod() {}; +private: + int m_value; +}; + +class Base2 +{ +public: + Base2() : m_value(2) {} + virtual ~Base2() {} + virtual int base2Method() { return m_value; } +private: + int m_value; +}; + +class LIBSAMPLE_API MDerived1 : public Base1, public Base2 +{ +public: + MDerived1(); + virtual ~MDerived1() {} + + virtual int mderived1Method() { return m_value; } + virtual int base1Method() { return Base1::base1Method() * 10; } + virtual int base2Method() { return Base2::base2Method() * 10; } + + inline Base1* castToBase1() { return (Base1*) this; } + inline Base2* castToBase2() { return (Base2*) this; } + + static MDerived1* transformFromBase1(Base1 *self); + static MDerived1* transformFromBase2(Base2 *self); + +private: + virtual void publicMethod() {} + int m_value; +}; + +class SonOfMDerived1 : public MDerived1 +{ +public: + SonOfMDerived1() : m_value(0) {} + ~SonOfMDerived1() {} + + inline MDerived1* castToMDerived1() { return (MDerived1*) this; } + + int sonOfMDerived1Method() { return m_value; } +private: + int m_value; +}; + +class Base3 +{ +public: + explicit Base3(int val = 3) : m_value(val) {} + virtual ~Base3() {} + int base3Method() { return m_value; } +private: + int m_value; +}; + +class Base4 +{ +public: + Base4() : m_value(4) {} + virtual ~Base4() {} + int base4Method() { return m_value; } +private: + int m_value; +}; + +class Base5 +{ +public: + Base5() : m_value(5) {} + virtual ~Base5() {} + virtual int base5Method() { return m_value; } +private: + int m_value; +}; + +class Base6 +{ +public: + Base6() : m_value(6) {} + virtual ~Base6() {} + virtual int base6Method() { return m_value; } +private: + int m_value; +}; + + +class LIBSAMPLE_API MDerived2 : public Base3, public Base4, public Base5, public Base6 +{ +public: + MDerived2(); + virtual ~MDerived2() {} + + inline int base4Method() { return Base3::base3Method() * 10; } + inline int mderived2Method() { return m_value; } + + inline Base3* castToBase3() { return (Base3*) this; } + inline Base4* castToBase4() { return (Base4*) this; } + inline Base5* castToBase5() { return (Base5*) this; } + inline Base6* castToBase6() { return (Base6*) this; } + +private: + int m_value; +}; + +class LIBSAMPLE_API MDerived3 : public MDerived1, public MDerived2 +{ +public: + MDerived3(); + virtual ~MDerived3() {} + + inline virtual int mderived3Method() { return m_value; } + + inline MDerived1* castToMDerived1() { return (MDerived1*) this; } + inline MDerived2* castToMDerived2() { return (MDerived2*) this; } + + inline Base3* castToBase3() { return (Base3*) this; } + +private: + int m_value; +}; + +class LIBSAMPLE_API MDerived4 : public Base3, public Base4 +{ +public: + MDerived4(); + ~MDerived4() {} + + inline int mderived4Method() { return 0; } + inline int justDummyMethod() { return m_value; } + + inline Base3* castToBase3() { return (Base3*) this; } + inline Base4* castToBase4() { return (Base4*) this; } +private: + int m_value; +}; + +class LIBSAMPLE_API MDerived5 : public Base3, public Base4 +{ +public: + MDerived5(); + virtual ~MDerived5() {} + + virtual int mderived5Method() { return 0; } + + inline Base3* castToBase3() { return (Base3*) this; } + inline Base4* castToBase4() { return (Base4*) this; } +}; + +#endif // MDERIVED_H + diff --git a/sources/shiboken2/tests/libsample/noimplicitconversion.h b/sources/shiboken2/tests/libsample/noimplicitconversion.h new file mode 100644 index 000000000..0a8882d3a --- /dev/null +++ b/sources/shiboken2/tests/libsample/noimplicitconversion.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 NOIMPLICITCONVERSION_H +#define NOIMPLICITCONVERSION_H + +#include "libsamplemacros.h" + +// This class must not have implicit conversions AND +// no conversion operators should be defined in its own module. +class NoImplicitConversion +{ +public: + explicit NoImplicitConversion(int objId) : m_objId(objId) {} + inline int objId() const { return m_objId; } + inline static int receivesNoImplicitConversionByValue(NoImplicitConversion arg) { return arg.m_objId; } + inline static int receivesNoImplicitConversionByPointer(NoImplicitConversion* arg) { return arg->m_objId; } + inline static int receivesNoImplicitConversionByReference(NoImplicitConversion& arg) { return arg.m_objId; } +private: + int m_objId; +}; + +#endif // NOIMPLICITCONVERSION_H + diff --git a/sources/shiboken2/tests/libsample/nondefaultctor.h b/sources/shiboken2/tests/libsample/nondefaultctor.h new file mode 100644 index 000000000..d2b186bd8 --- /dev/null +++ b/sources/shiboken2/tests/libsample/nondefaultctor.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 NONDEFAULTCTOR_H +#define NONDEFAULTCTOR_H + +#include "libsamplemacros.h" + +class NonDefaultCtor +{ + int m_value; +public: + NonDefaultCtor(int value) : m_value(value) + { + } + + inline int value() + { + return m_value; + } + + inline NonDefaultCtor returnMyself() + { + return *this; + } + + inline NonDefaultCtor returnMyself(int) + { + return *this; + } + + inline NonDefaultCtor returnMyself(int, NonDefaultCtor) + { + return *this; + } + + virtual NonDefaultCtor returnMyselfVirtual() + { + return *this; + } + + inline NonDefaultCtor callReturnMyselfVirtual() + { + return returnMyselfVirtual(); + } + + virtual ~NonDefaultCtor() {} +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/null.h b/sources/shiboken2/tests/libsample/null.h new file mode 100644 index 000000000..634262a99 --- /dev/null +++ b/sources/shiboken2/tests/libsample/null.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 NULL_H +#define NULL_H + +class Null +{ +public: + Null(bool value) : m_isNull(value) {} + Null() : m_isNull(false) {} + void setIsNull(bool flag) { m_isNull = flag; } + +private: + bool m_isNull; +}; + +#endif // STR_H + diff --git a/sources/shiboken2/tests/libsample/objectmodel.cpp b/sources/shiboken2/tests/libsample/objectmodel.cpp new file mode 100644 index 000000000..370b58aa1 --- /dev/null +++ b/sources/shiboken2/tests/libsample/objectmodel.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "objectmodel.h" + +void +ObjectModel::setData(ObjectType* data) +{ + m_data = data; +} + +ObjectType* +ObjectModel::data() const +{ + return m_data; +} + diff --git a/sources/shiboken2/tests/libsample/objectmodel.h b/sources/shiboken2/tests/libsample/objectmodel.h new file mode 100644 index 000000000..aa4a64433 --- /dev/null +++ b/sources/shiboken2/tests/libsample/objectmodel.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OBJECTMODEL_H +#define OBJECTMODEL_H + +#include "objecttype.h" +#include "libsamplemacros.h" + +class LIBSAMPLE_API ObjectModel : public ObjectType +{ +public: + explicit ObjectModel(ObjectType* parent = 0) + : ObjectType(parent), m_data(0) + {} + + void setData(ObjectType* data); + virtual ObjectType* data() const; + + // The MethodCalled enum and related static methods were created to + // test bug #630 [http://bugs.openbossa.org/show_bug.cgi?id=630] + enum MethodCalled { ObjectTypeCalled, ObjectModelCalled }; + static MethodCalled receivesObjectTypeFamily(const ObjectType& object) { return ObjectModel::ObjectTypeCalled; } + static MethodCalled receivesObjectTypeFamily(const ObjectModel& object) { return ObjectModel::ObjectModelCalled; } + +private: + // The model holds only one piece of data. + // (This is just a test after all.) + ObjectType* m_data; +}; + +#endif // OBJECTMODEL_H + diff --git a/sources/shiboken2/tests/libsample/objecttype.cpp b/sources/shiboken2/tests/libsample/objecttype.cpp new file mode 100644 index 000000000..4f10b01df --- /dev/null +++ b/sources/shiboken2/tests/libsample/objecttype.cpp @@ -0,0 +1,311 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "objecttype.h" +#include "objecttypelayout.h" +#include +#include +#include +#include + +using namespace std; + +ObjectType::ObjectType(ObjectType* parent) : m_parent(0), m_layout(0), m_call_id(-1) +{ + setParent(parent); +} + +ObjectType::~ObjectType() +{ + for (ObjectTypeList::iterator child_iter = m_children.begin(); + child_iter != m_children.end(); ++child_iter) + delete *child_iter; +} + +ObjectType* +ObjectType::createWithChild() +{ + ObjectType* parent = create(); + ObjectType* child = create(); + child->setObjectName("child"); + child->setParent(parent); + return parent; +} + +void +ObjectType::removeChild(ObjectType* child) +{ + if (!child) + return; + + ObjectTypeList::iterator child_iter = std::find(m_children.begin(), m_children.end(), child); + if (child_iter != m_children.end()) { + m_children.erase(child_iter); + child->m_parent = 0; + } +} + +ObjectType* +ObjectType::takeChild(ObjectType* child) +{ + if (!child) + return 0; + + ObjectTypeList::iterator child_iter = std::find(m_children.begin(), m_children.end(), child); + if (child_iter != m_children.end()) { + m_children.erase(child_iter); + child->m_parent = 0; + return child; + } + return 0; +} + +ObjectType* +ObjectType::takeChild(const Str& name) +{ + return takeChild(findChild(name)); + +} + +ObjectType* +ObjectType::findChild(const Str& name) +{ + for (ObjectTypeList::iterator child_iter = m_children.begin(); + child_iter != m_children.end(); ++child_iter) { + + if ((*child_iter)->objectName() == name) + return *child_iter; + } + return 0; +} + +void +ObjectType::killChild(const Str& name) +{ + for (ObjectTypeList::iterator child_iter = m_children.begin(); + child_iter != m_children.end(); ++child_iter) { + + if ((*child_iter)->objectName() == name) { + ObjectType* child = *child_iter; + removeChild(child); + delete child; + break; + } + } +} + +void +ObjectType::setParent(ObjectType* parent) +{ + if (m_parent == parent) + return; + + if (m_parent) + m_parent->removeChild(this); + + m_parent = parent; + if (m_parent) + m_parent->m_children.push_back(this); +} + +void +ObjectType::setObjectName(const Str& name) +{ + m_objectName = name; +} + +Str +ObjectType::objectName() const +{ + return m_objectName; +} + +bool +ObjectType::causeEvent(Event::EventType eventType) +{ + Event e(eventType); + return event(&e); +} + +bool +ObjectType::event(Event* event) +{ + return true; +} + +int +ObjectType::processEvent(ObjectTypeList objects, Event *event) +{ + int evaluated = 0; + + for (ObjectTypeList::iterator obj_iter = objects.begin(); + obj_iter != objects.end(); ++obj_iter) { + if((*obj_iter)->event(event)) + evaluated++; + } + + return evaluated; + +} + +void +ObjectType::callInvalidateEvent(Event* event) +{ + invalidateEvent(event); +} + +void +ObjectType::setLayout(ObjectTypeLayout* l) +{ + if (!l) { + cerr << "[WARNING] ObjectType::setLayout: Cannot set layout to 0." << endl; + return; + } + + if (layout()) { + if (layout() != l) { + cerr << "[WARNING] ObjectType::setLayout: Attempting to set ObjectTypeLayout '" << l->objectName().cstring(); + cerr << "' on ObjectType '" << objectName().cstring() << "', which already has a layout." << endl; + } + return; + } + + ObjectType* oldParent = l->parent(); + if (oldParent && oldParent != this) { + if (oldParent->isLayoutType()) { + cerr << "[WARNING] ObjectType::setLayout: Attempting to set ObjectTypeLayout '" << l->objectName().cstring(); + cerr << "' on ObjectType '" << objectName().cstring() << "', when the ObjectTypeLayout already has a parent layout." << endl; + return; + } else { + // Steal the layout from an ObjectType parent. + oldParent->takeLayout(); + } + } + + m_layout = l; + if (oldParent != this) { + l->setParent(this); + l->reparentChildren(this); + } +} + +ObjectTypeLayout* ObjectType::takeLayout() +{ + ObjectTypeLayout* l = layout(); + if (!l) + return 0; + m_layout = 0; + l->setParent(0); + return l; +} + +unsigned int +objectTypeHash(const ObjectType* objectType) +{ + return reinterpret_cast(objectType); +} + +unsigned char +ObjectType::callWithEnum(const Str& prefix, Event::EventType type, unsigned char value){ + return value*value; +} + +unsigned char +ObjectType::callWithEnum(const Str& prefix, unsigned char value) { + return value; +} + +void +ObjectType::setObjectSplittedName(const char*, const Str& prefix, const Str& suffix) +{ + std::string result(prefix.cstring()); + result += suffix.cstring(); + m_objectName = result.c_str(); +} + +void +ObjectType::setObjectNameWithSize(const char*, int size, const Str& name) +{ + std::string result(name.cstring(), size); + m_objectName = result.c_str(); +} + +void +ObjectType::setObjectNameWithSize(const Str& name, int size) +{ + setObjectNameWithSize("", size, name); +} + +void ObjectType::setObject(ObjectType *) +{ + m_call_id = 0; +} + +void ObjectType::setObject(const Null&) +{ + m_call_id = 1; +} + +int ObjectType::callId() const +{ + return m_call_id; +} + + +void ObjectType::callVirtualCreateChild() +{ + ObjectType* fake_parent = new ObjectType(); + ObjectType* fake_child = createChild(fake_parent); + assert(fake_child->isPython()); + delete fake_parent; +} + +ObjectType* ObjectType::createChild(ObjectType* parent) +{ + return new ObjectType(parent); +} + +std::size_t ObjectType::createObjectType() +{ + void* addr = new ObjectType(); + return (std::size_t) addr; +} + +OtherBase::~OtherBase() +{ +} + +ObjectTypeDerived::~ObjectTypeDerived() +{ +} + +bool +ObjectTypeDerived::event(Event* event) +{ + return true; +} diff --git a/sources/shiboken2/tests/libsample/objecttype.h b/sources/shiboken2/tests/libsample/objecttype.h new file mode 100644 index 000000000..eae95b3b1 --- /dev/null +++ b/sources/shiboken2/tests/libsample/objecttype.h @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OBJECTTYPE_H +#define OBJECTTYPE_H + +#include +#include "str.h" +#include "null.h" + +#include "libsamplemacros.h" + +#include + +struct Event +{ + enum EventType { + NO_EVENT, + BASIC_EVENT, + SOME_EVENT, + ANY_EVENT + }; + Event(EventType eventType) : m_eventType(eventType) {} + EventType eventType() { return m_eventType; } +private: + EventType m_eventType; +}; + +class ObjectTypeLayout; +class ObjectType; +typedef std::list ObjectTypeList; + +class LIBSAMPLE_API ObjectType +{ +public: + // ### Fixme: Use uintptr_t in C++ 11 + typedef size_t Identifier; + + explicit ObjectType(ObjectType* parent = 0); + virtual ~ObjectType(); + + // factory method + inline static ObjectType* create() { return new ObjectType(); } + static ObjectType* createWithChild(); + + void setParent(ObjectType* parent); + inline ObjectType* parent() const { return m_parent; } + inline const ObjectTypeList& children() const { return m_children; } + void killChild(const Str& name); + void removeChild(ObjectType* child); + ObjectType* takeChild(ObjectType* child); + virtual ObjectType* takeChild(const Str& name); + ObjectType* findChild(const Str& name); + + Str objectName() const; + void setObjectName(const Str& name); + + inline Identifier identifier() const { return reinterpret_cast(this); } + + bool causeEvent(Event::EventType eventType); + + // Returns true if the event is processed. + virtual bool event(Event* event); + static int processEvent(ObjectTypeList objects, Event *event); + + void callInvalidateEvent(Event* event); + virtual void invalidateEvent(Event* event) {} + + // This nonsense method emulate QWidget.setLayout method + // All layout objects will became children of this object. + void setLayout(ObjectTypeLayout* layout); + inline ObjectTypeLayout* layout() const { return m_layout; } + + // This method should be reimplemented by ObjectTypeLayout. + virtual bool isLayoutType() { return false; } + + unsigned char callWithEnum(const Str& prefix, Event::EventType type, unsigned char value=80); + unsigned char callWithEnum(const Str& prefix, unsigned char value=0); + + //Functions used in test with named arguments + void setObjectSplittedName(const char*, const Str& prefix = Str("")); + void setObjectNameWithSize(const char*, int size=9, const Str& name = Str("")); + void setObjectNameWithSize(const Str& name = Str(""), int size=9); + + //Function used to confuse the generator when two values accept Null as arg + void setObject(ObjectType *); + void setObject(const Null&); + int callId() const; + + //Function used to create a parent from C++ + virtual bool isPython() { return false; } + void callVirtualCreateChild(); + virtual ObjectType* createChild(ObjectType* parent); + static std::size_t createObjectType(); + + //return a parent from C++ + ObjectType* getCppParent() { + if (!m_parent) { + ObjectType* parent = new ObjectType(); + setParent(parent); + } + return m_parent; + } + + void destroyCppParent() { + delete m_parent; + m_parent = 0; + } + + //Deprecated test + bool deprecatedFunction() { return true; } + + // nextInFocusChain simply returns the parent to test object cycles; the parent + // may be returned by the QWidget's implementation but isn't always returned + ObjectType* nextInFocusChain() { return m_parent; } + +private: + ObjectType(const ObjectType&); + ObjectType& operator=(const ObjectType&); + + ObjectTypeLayout* takeLayout(); + + Str m_objectName; + ObjectType* m_parent; + ObjectTypeList m_children; + + ObjectTypeLayout* m_layout; + + + //used on overload null test + int m_call_id; +}; + +LIBSAMPLE_API unsigned int objectTypeHash(const ObjectType* objectType); + +class LIBSAMPLE_API OtherBase { +public: + OtherBase() {}; + virtual ~OtherBase(); +}; + +class LIBSAMPLE_API ObjectTypeDerived: public ObjectType, public OtherBase { +public: + ObjectTypeDerived(): ObjectType(), OtherBase() {}; + + virtual bool event(Event* event); + virtual ~ObjectTypeDerived(); +}; + +#endif // OBJECTTYPE_H + diff --git a/sources/shiboken2/tests/libsample/objecttypebyvalue.h b/sources/shiboken2/tests/libsample/objecttypebyvalue.h new file mode 100644 index 000000000..1b61ec4dc --- /dev/null +++ b/sources/shiboken2/tests/libsample/objecttypebyvalue.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OBJECTTYPEBYVALUE_H +#define OBJECTTYPEBYVALUE_H +#include +#include "protected.h" + +class ObjectTypeByValue +{ +public: + ObjectTypeByValue returnSomeKindOfMe() { return ObjectTypeByValue(); } + void acceptKindOfMeAsValue(ObjectTypeByValue kindOfMe) {} + + void acceptListOfObjectTypeByValue(std::list listOfMe) {} + + // prop used to check for segfaults + ProtectedProperty prop; +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/objecttypeholder.cpp b/sources/shiboken2/tests/libsample/objecttypeholder.cpp new file mode 100644 index 000000000..dabeb2f86 --- /dev/null +++ b/sources/shiboken2/tests/libsample/objecttypeholder.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "objecttypeholder.h" + +ObjectTypeHolder::ObjectTypeHolder(const char* objectName) +{ + m_objectType = new ObjectType(); + m_objectType->setObjectName(objectName); +} + +ObjectTypeHolder::~ObjectTypeHolder() +{ + delete m_objectType; +} + +Str +ObjectTypeHolder::passObjectTypeAsReference(const ObjectType& objectType) +{ + return objectType.objectName(); +} + +Str +ObjectTypeHolder::callPassObjectTypeAsReference() +{ + return passObjectTypeAsReference(*m_objectType); +} diff --git a/sources/shiboken2/tests/libsample/objecttypeholder.h b/sources/shiboken2/tests/libsample/objecttypeholder.h new file mode 100644 index 000000000..c2e7275d4 --- /dev/null +++ b/sources/shiboken2/tests/libsample/objecttypeholder.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OBJECTTYPEHOLDER_H +#define OBJECTTYPEHOLDER_H + +#include "libsamplemacros.h" +#include "objecttype.h" +#include "str.h" + +class LIBSAMPLE_API ObjectTypeHolder +{ +public: + explicit ObjectTypeHolder(const char* objectName); + virtual ~ObjectTypeHolder(); + + ObjectType* getObjecType() { return m_objectType; } + + virtual Str passObjectTypeAsReference(const ObjectType& objectType); + Str callPassObjectTypeAsReference(); + +private: + ObjectType* m_objectType; +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/objecttypelayout.cpp b/sources/shiboken2/tests/libsample/objecttypelayout.cpp new file mode 100644 index 000000000..d2a7d1bba --- /dev/null +++ b/sources/shiboken2/tests/libsample/objecttypelayout.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "objecttypelayout.h" +#include + +using namespace std; + +void ObjectTypeLayout::addObject(ObjectType* obj) +{ + if (obj->isLayoutType()) { + ObjectTypeLayout* l = reinterpret_cast(obj); + if (l->parent()) { + cerr << "[WARNING] ObjectTypeLayout::addObject: layout '" << l->objectName().cstring(); + cerr << "' already has a parent." << endl; + return; + } + + l->setParent(this); + + if (parent() && !parent()->isLayoutType()) + l->reparentChildren(parent()); + } + + m_objects.push_back(obj); +} + +std::list< ObjectType* > ObjectTypeLayout::objects() const +{ + return m_objects; +} + +void ObjectTypeLayout::reparentChildren(ObjectType* parent) +{ + std::list::const_iterator it = m_objects.begin(); + for (; it != m_objects.end(); ++it) { + if ((*it)->isLayoutType()) + reinterpret_cast(*it)->reparentChildren(parent); + else + (*it)->setParent(parent); + } +} + diff --git a/sources/shiboken2/tests/libsample/objecttypelayout.h b/sources/shiboken2/tests/libsample/objecttypelayout.h new file mode 100644 index 000000000..3fa8b9dbf --- /dev/null +++ b/sources/shiboken2/tests/libsample/objecttypelayout.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OBJECTTYPELAYOUT_H +#define OBJECTTYPELAYOUT_H + +#include "libsamplemacros.h" +#include "objecttype.h" +#include + +class ObjectType; + +class LIBSAMPLE_API ObjectTypeLayout : public ObjectType +{ +public: + void addObject(ObjectType* obj); + std::list objects() const; + + virtual bool isLayoutType() { return true; } + inline static ObjectTypeLayout* create() { return new ObjectTypeLayout(); } + + virtual ObjectType* takeChild(const Str& name) { return ObjectType::takeChild(name); } +private: + std::list m_objects; + + void reparentChildren(ObjectType* parent); + friend LIBSAMPLE_API void ObjectType::setLayout(ObjectTypeLayout* l); +}; + +#endif // OBJECTTYPELAYOUT_H + diff --git a/sources/shiboken2/tests/libsample/objecttypeoperators.cpp b/sources/shiboken2/tests/libsample/objecttypeoperators.cpp new file mode 100644 index 000000000..1bdaded30 --- /dev/null +++ b/sources/shiboken2/tests/libsample/objecttypeoperators.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "objecttypeoperators.h" + +ObjectTypeOperators::ObjectTypeOperators(const std::string key) : m_key(key) +{ +} + +bool ObjectTypeOperators::operator==(const ObjectTypeOperators& other) const +{ + return m_key == other.m_key; +} + +const ObjectTypeOperators& ObjectTypeOperators::operator<(const ObjectTypeOperators& other) const +{ + return m_key < other.m_key ? *this : other; +} + +bool operator==(const ObjectTypeOperators* obj, const std::string& str) +{ + return obj->key() == str; +} + +bool operator==(const std::string& str, const ObjectTypeOperators* obj) +{ + return str == obj->key(); +} + +std::string operator+(const ObjectTypeOperators* obj, const std::string& str) +{ + return obj->key() + str; +} + +std::string operator+(const std::string& str, const ObjectTypeOperators* obj) +{ + return str + obj->key(); +} diff --git a/sources/shiboken2/tests/libsample/objecttypeoperators.h b/sources/shiboken2/tests/libsample/objecttypeoperators.h new file mode 100644 index 000000000..5795ac456 --- /dev/null +++ b/sources/shiboken2/tests/libsample/objecttypeoperators.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OBJECTTYPEOPERATORS_H +#define OBJECTTYPEOPERATORS_H + +#include "libsamplemacros.h" +#include + +class LIBSAMPLE_API ObjectTypeOperators +{ +public: + explicit ObjectTypeOperators(const std::string key); + virtual ~ObjectTypeOperators() {} + + bool operator==(const ObjectTypeOperators& other) const; + const ObjectTypeOperators& operator<(const ObjectTypeOperators& other) const; + + // chaos! + virtual void operator>(const ObjectTypeOperators&) { m_key.append("operator>"); } + + std::string key() const { return m_key; } + +private: + std::string m_key; + + ObjectTypeOperators(ObjectTypeOperators&); + ObjectTypeOperators& operator=(ObjectTypeOperators&); +}; + +LIBSAMPLE_API bool operator==(const ObjectTypeOperators* obj, const std::string& str); +LIBSAMPLE_API bool operator==(const std::string& str, const ObjectTypeOperators* obj); +LIBSAMPLE_API std::string operator+(const ObjectTypeOperators* obj, const std::string& str); +LIBSAMPLE_API std::string operator+(const std::string& str, const ObjectTypeOperators* obj); + +#endif // OBJECTTYPEOPERATORS_H diff --git a/sources/shiboken2/tests/libsample/objectview.cpp b/sources/shiboken2/tests/libsample/objectview.cpp new file mode 100644 index 000000000..08c5f45f6 --- /dev/null +++ b/sources/shiboken2/tests/libsample/objectview.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "objectview.h" +#include "objectmodel.h" +#include "str.h" + +Str +ObjectView::displayModelData() +{ + if (!m_model) + return Str("(NULL)"); + return Str("Name: %VAR").arg(m_model->objectName()); +} + +void +ObjectView::modifyModelData(Str& data) +{ + if (m_model) + m_model->setObjectName(data); +} + + +ObjectType* +ObjectView::getRawModelData() +{ + return m_model->data(); +} + diff --git a/sources/shiboken2/tests/libsample/objectview.h b/sources/shiboken2/tests/libsample/objectview.h new file mode 100644 index 000000000..0bcc09a30 --- /dev/null +++ b/sources/shiboken2/tests/libsample/objectview.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OBJECTVIEW_H +#define OBJECTVIEW_H + +#include "objecttype.h" +#include "libsamplemacros.h" + +class Str; +class ObjectModel; + +class LIBSAMPLE_API ObjectView : public ObjectType +{ +public: + ObjectView(ObjectModel* model = 0, ObjectType* parent = 0) + : ObjectType(parent), m_model(model) + {} + + inline void setModel(ObjectModel* model) { m_model = model; } + inline ObjectModel* model() const { return m_model; } + + Str displayModelData(); + void modifyModelData(Str& data); + + ObjectType* getRawModelData(); + +private: + ObjectModel* m_model; +}; + +#endif // OBJECTVIEW_H + diff --git a/sources/shiboken2/tests/libsample/oddbool.h b/sources/shiboken2/tests/libsample/oddbool.h new file mode 100644 index 000000000..ee0f4fa03 --- /dev/null +++ b/sources/shiboken2/tests/libsample/oddbool.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 ODDBOOL_H +#define ODDBOOL_H + +#include "libsamplemacros.h" + +class OddBool +{ + +public: + inline explicit OddBool(bool b) : m_value(b) {} + bool value() const { return m_value; } + + inline OddBool operator!() const { return OddBool(!m_value); } + +private: + bool m_value; +}; + +inline bool operator==(OddBool b1, bool b2) { return (!b1).value() == !b2; } +inline bool operator==(bool b1, OddBool b2) { return (!b1) == (!b2).value(); } +inline bool operator==(OddBool b1, OddBool b2) { return (!b1).value() == (!b2).value(); } +inline bool operator!=(OddBool b1, bool b2) { return (!b1).value() != !b2; } +inline bool operator!=(bool b1, OddBool b2) { return (!b1) != (!b2).value(); } +inline bool operator!=(OddBool b1, OddBool b2) { return (!b1).value() != (!b2).value(); } + +class OddBoolUser +{ +public: + OddBoolUser() : m_oddbool(OddBool(false)) {} + OddBoolUser(const OddBool& oddBool) : m_oddbool(oddBool) {} + virtual ~OddBoolUser() {} + + inline OddBool oddBool() { return m_oddbool; } + inline void setOddBool(OddBool oddBool) { m_oddbool = oddBool; } + + virtual OddBool invertedOddBool() + { + return !m_oddbool; + } + + inline OddBool callInvertedOddBool() + { + return invertedOddBool(); + } + + static inline OddBool getOddBool(const OddBoolUser& oddBoolUser) + { + return oddBoolUser.m_oddbool; + } + +private: + OddBool m_oddbool; +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/onlycopy.cpp b/sources/shiboken2/tests/libsample/onlycopy.cpp new file mode 100644 index 000000000..5407f9d33 --- /dev/null +++ b/sources/shiboken2/tests/libsample/onlycopy.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "onlycopy.h" + +OnlyCopy::OnlyCopy(const OnlyCopy& other) +{ + m_value = other.m_value; +} + +OnlyCopy& +OnlyCopy::operator=(const OnlyCopy& other) +{ + m_value = other.m_value; + return *this; +} + +OnlyCopy +FriendOfOnlyCopy::createOnlyCopy(int value) +{ + + return OnlyCopy(value); +} + +std::list +FriendOfOnlyCopy::createListOfOnlyCopy(int quantity) +{ + std::list list; + for (int i = 0; i < quantity; ++i) + list.push_back(createOnlyCopy(i)); + return list; +} diff --git a/sources/shiboken2/tests/libsample/onlycopy.h b/sources/shiboken2/tests/libsample/onlycopy.h new file mode 100644 index 000000000..6abad7382 --- /dev/null +++ b/sources/shiboken2/tests/libsample/onlycopy.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 ONLYCOPYCLASS_H +#define ONLYCOPYCLASS_H + +#include "libsamplemacros.h" +#include + +// These classes simulate a situation found in +// QtWebKit's QWebDatabase and QWebSecurityOrigin. + +class LIBSAMPLE_API OnlyCopy +{ +public: + OnlyCopy(const OnlyCopy& other); + OnlyCopy& operator=(const OnlyCopy& other); + int value() const { return m_value; } + static int getValue(OnlyCopy onlyCopy) { return onlyCopy.m_value; } + static int getValueFromReference(const OnlyCopy& onlyCopy) { return onlyCopy.m_value; } +private: + int m_value; + OnlyCopy(int value) : m_value(value) {}; + friend class FriendOfOnlyCopy; +}; + +class LIBSAMPLE_API FriendOfOnlyCopy +{ +public: + static OnlyCopy createOnlyCopy(int value); + static std::list createListOfOnlyCopy(int quantity); +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/overload.cpp b/sources/shiboken2/tests/libsample/overload.cpp new file mode 100644 index 000000000..753407e35 --- /dev/null +++ b/sources/shiboken2/tests/libsample/overload.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "overload.h" + +Overload::FunctionEnum Overload::overloaded() +{ + return Function0; +} + +Overload::FunctionEnum Overload::overloaded(Size* size) +{ + return Function1; +} + +Overload::FunctionEnum Overload::overloaded(Point* point, ParamEnum param) +{ + return Function2; +} + +Overload::FunctionEnum Overload::overloaded(const Point& point) +{ + return Function3; +} + diff --git a/sources/shiboken2/tests/libsample/overload.h b/sources/shiboken2/tests/libsample/overload.h new file mode 100644 index 000000000..5005b4f8c --- /dev/null +++ b/sources/shiboken2/tests/libsample/overload.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OVERLOAD_H +#define OVERLOAD_H + +#include "echo.h" +#include "str.h" +#include "size.h" +#include "point.h" +#include "pointf.h" +#include "polygon.h" +#include "rect.h" + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Overload +{ +public: + enum FunctionEnum { + Function0, + Function1, + Function2, + Function3, + Function4, + Function5, + Function6 + }; + + enum ParamEnum { + Param0, + Param1 + }; + + Overload() {} + virtual ~Overload() {} + + FunctionEnum overloaded(); + FunctionEnum overloaded(Size* size); + FunctionEnum overloaded(Point* point, ParamEnum param); + FunctionEnum overloaded(const Point& point); + + inline void differentReturnTypes(ParamEnum param = Param0) {} + inline int differentReturnTypes(ParamEnum param, int val) { return val; } + + inline int intOverloads(const Point& p, double d) { return 1; } + inline int intOverloads(int i, int i2) { return 2; } + inline int intOverloads(int i, int removedArg, double d) { return 3; } + + inline FunctionEnum intDoubleOverloads(int a0, int a1) const { return Function0; } + inline FunctionEnum intDoubleOverloads(double a0, double a1) const { return Function1; } + + void singleOverload(Point* x) {} + Point* singleOverload() {return new Point();} + + // Similar to QImage::trueMatrix(QMatrix,int,int) and QImage::trueMatrix(QTransform,int,int) + FunctionEnum wrapperIntIntOverloads(const Point& arg0, int arg1, int arg2) { return Function0; } + FunctionEnum wrapperIntIntOverloads(const Polygon& arg0, int arg1, int arg2) { return Function1; } + + // Similar to QImage constructor + FunctionEnum strBufferOverloads(const Str& arg0, const char* arg1 = 0, bool arg2 = true) { return Function0; } + FunctionEnum strBufferOverloads(unsigned char* arg0, int arg1) { return Function1; } + FunctionEnum strBufferOverloads() { return Function2; } + + // Similar to QPainter::drawText(...) + FunctionEnum drawText(const Point& a0, const Str& a1) { return Function0; } + FunctionEnum drawText(const PointF& a0, const Str& a1) { return Function1; } + FunctionEnum drawText(const Rect& a0, int a1, const Str& a2) { return Function2; } + FunctionEnum drawText(const RectF& a0, int a1, const Str& a2) { return Function3; } + FunctionEnum drawText(const RectF& a0, const Str& a1, const Echo& a2 = Echo()) { return Function4; } + FunctionEnum drawText(int a0, int a1, const Str& a2) { return Function5; } + FunctionEnum drawText(int a0, int a1, int a2, int a3, int a4, const Str& a5) { return Function6; } + + // A variant of the one similar to QPainter::drawText(...) + FunctionEnum drawText2(const Point& a0, const Str& a1) { return Function0; } + FunctionEnum drawText2(const PointF& a0, const Str& a1) { return Function1; } + FunctionEnum drawText2(const Rect& a0, int a1, const Str& a2) { return Function2; } + FunctionEnum drawText2(const RectF& a0, int a1, const Str& a2) { return Function3; } + FunctionEnum drawText2(const RectF& a0, const Str& a1, const Echo& a2 = Echo()) { return Function4; } + FunctionEnum drawText2(int a0, int a1, const Str& a2) { return Function5; } + FunctionEnum drawText2(int a0, int a1, int a2, int a3 = 0, int a4 = 0, const Str& a5 = Str()) { return Function6; } + + // A simpler variant of the one similar to QPainter::drawText(...) + FunctionEnum drawText3(const Str& a0, const Str& a1, const Str& a2) { return Function0; } + FunctionEnum drawText3(int a0, int a1, int a2, int a3, int a4) { return Function1; } + + // Another simpler variant of the one similar to QPainter::drawText(...) + FunctionEnum drawText4(int a0, int a1, int a2) { return Function0; } + FunctionEnum drawText4(int a0, int a1, int a2, int a3, int a4) { return Function1; } + + FunctionEnum acceptSequence() { return Function0; } + FunctionEnum acceptSequence(int a0, int a1) { return Function1; } + FunctionEnum acceptSequence(const Str& a0, ParamEnum a1 = Param0) { return Function2; } + FunctionEnum acceptSequence(const Size& a0) { return Function3; } + // The type must be changed to PySequence. + FunctionEnum acceptSequence(const char* const a0[]) { return Function4; } + FunctionEnum acceptSequence(void* a0) { return Function5; } +}; + +class LIBSAMPLE_API Overload2 : public Overload +{ +public: + // test bug#616, public and private method differ only by const + void doNothingInPublic() const {} + void doNothingInPublic(int) {} + virtual void doNothingInPublic3() const {} + void doNothingInPublic3(int) const {} +protected: + void doNothingInPublic2() const {} + void doNothingInPublic2(int) {} +private: + void doNothingInPublic() {} + void doNothingInPublic2() {} + void doNothingInPublic3() {} +}; + +#endif // OVERLOAD_H + diff --git a/sources/shiboken2/tests/libsample/overloadsort.cpp b/sources/shiboken2/tests/libsample/overloadsort.cpp new file mode 100644 index 000000000..f1bc9665b --- /dev/null +++ b/sources/shiboken2/tests/libsample/overloadsort.cpp @@ -0,0 +1,30 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "overloadsort.h" + diff --git a/sources/shiboken2/tests/libsample/overloadsort.h b/sources/shiboken2/tests/libsample/overloadsort.h new file mode 100644 index 000000000..9145504ae --- /dev/null +++ b/sources/shiboken2/tests/libsample/overloadsort.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 OVERLOADSORT_H +#define OVERLOADSORT_H + +#include "libsamplemacros.h" + +#include + +class ImplicitTarget +{ +public: + ImplicitTarget(){} +}; + +class ImplicitBase +{ +public: + ImplicitBase(){} + ImplicitBase(const ImplicitTarget &b){} +}; + +class SortedOverload +{ +public: + + inline const char *overload(int x) { + return "int"; + } + + inline const char *overload(double x) { + return "double"; + } + + inline const char *overload(ImplicitBase x) { + return "ImplicitBase"; + } + + inline const char *overload(ImplicitTarget x) { + return "ImplicitTarget"; + } + + inline const char *overload(const std::list &x) { + return "list(ImplicitBase)"; + } + + inline int implicit_overload(const ImplicitBase &x) { + return 1; + } + + inline const char *overloadDeep(int x, ImplicitBase &y) { + return "ImplicitBase"; + } + + + inline const char* pyObjOverload(int, int) { return "int,int"; } + inline const char* pyObjOverload(unsigned char*, int) { return "PyObject,int"; } + +}; + +#endif // OVERLOADSORT_H + diff --git a/sources/shiboken2/tests/libsample/pairuser.cpp b/sources/shiboken2/tests/libsample/pairuser.cpp new file mode 100644 index 000000000..b4b51b8cf --- /dev/null +++ b/sources/shiboken2/tests/libsample/pairuser.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "pairuser.h" + +using namespace std; + +std::pair +PairUser::callCreatePair() +{ + return createPair(); +} + +std::pair +PairUser::createPair() +{ + return std::pair(10, 20); +} + +std::pair +PairUser::createComplexPair(Complex cpx0, Complex cpx1) +{ + return std::pair(cpx0, cpx1); +} + +double +PairUser::sumPair(std::pair pair) +{ + return ((double) pair.first) + pair.second; +} + diff --git a/sources/shiboken2/tests/libsample/pairuser.h b/sources/shiboken2/tests/libsample/pairuser.h new file mode 100644 index 000000000..7b87ba65b --- /dev/null +++ b/sources/shiboken2/tests/libsample/pairuser.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 PAIRUSER_H +#define PAIRUSER_H + +#include +#include "complex.h" + +#include "libsamplemacros.h" + +class LIBSAMPLE_API PairUser +{ +public: + PairUser() {} + virtual ~PairUser() {} + + virtual std::pair createPair(); + std::pair callCreatePair(); + static std::pair createComplexPair(Complex cpx0, Complex cpx1); + double sumPair(std::pair pair); + + inline void setPair(std::pair pair) { m_pair = pair; } + inline std::pair getPair() { return m_pair; } + +private: + std::pair m_pair; +}; +#endif // PAIRUSER_H + diff --git a/sources/shiboken2/tests/libsample/pen.cpp b/sources/shiboken2/tests/libsample/pen.cpp new file mode 100644 index 000000000..509b47c76 --- /dev/null +++ b/sources/shiboken2/tests/libsample/pen.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "pen.h" + +Color::Color() : m_null(true) +{ +} + +Color::Color(SampleNamespace::InValue arg) : m_null(false) +{ +} + +Color::Color(unsigned int arg) : m_null(false) +{ +} + +bool Color::isNull() const +{ + return m_null; +} + +Pen::Pen() : m_ctor(EmptyCtor) +{ +} + +Pen::Pen(SampleNamespace::Option option) : m_ctor(EnumCtor) +{ +} + +Pen::Pen(const Color& color) : m_ctor(ColorCtor) +{ +} + +Pen::Pen(const Pen& pen) : m_ctor(CopyCtor) +{ +} + +int Pen::ctorType() +{ + return m_ctor; +} diff --git a/sources/shiboken2/tests/libsample/pen.h b/sources/shiboken2/tests/libsample/pen.h new file mode 100644 index 000000000..e1fb641d3 --- /dev/null +++ b/sources/shiboken2/tests/libsample/pen.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 PEN_H +#define PEN_H + +#include "libsamplemacros.h" +#include "samplenamespace.h" + +class LIBSAMPLE_API Color +{ +public: + Color(); + Color(SampleNamespace::InValue arg); + Color(unsigned int arg); + + bool isNull() const; +private: + bool m_null; +}; + +class LIBSAMPLE_API Pen +{ +public: + enum { EmptyCtor, EnumCtor, ColorCtor, CopyCtor }; + + Pen(); + Pen(SampleNamespace::Option option); + Pen(const Color& color); + Pen(const Pen& pen); + + int ctorType(); +private: + int m_ctor; +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/photon.cpp b/sources/shiboken2/tests/libsample/photon.cpp new file mode 100644 index 000000000..debc9f116 --- /dev/null +++ b/sources/shiboken2/tests/libsample/photon.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "photon.h" + +namespace Photon +{ +const ClassType Base::staticType; +int callCalculateForValueDuplicatorPointer(ValueDuplicator* value) +{ + return value->calculate(); +} +int callCalculateForValueDuplicatorReference(ValueDuplicator& value) +{ + return value.calculate(); +} +int countValueIdentities(const std::list& values) +{ + return values.size(); +} +int countValueDuplicators(const std::list >& values) +{ + return values.size(); +} +} // namespace Photon diff --git a/sources/shiboken2/tests/libsample/photon.h b/sources/shiboken2/tests/libsample/photon.h new file mode 100644 index 000000000..d8b1be423 --- /dev/null +++ b/sources/shiboken2/tests/libsample/photon.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 PHOTON_H +#define PHOTON_H + +#include +#include "libsamplemacros.h" + +// This namespace and classes simulate +// situations found in Qt's phonon module. + +namespace Photon +{ + +enum ClassType { + BaseType = 0, + IdentityType = 1, + DuplicatorType = 2 +}; + +class LIBSAMPLE_API Base +{ +public: + explicit Base(int value) : m_value(value) {} + virtual ~Base() {} + inline void setValue(int value) { m_value = value; } + inline int value() const { return m_value; } + + template bool isType() { return type() == T::staticType; } + bool isType(ClassType t) { return type() == t; } + + virtual ClassType type() const { return BaseType; }; + static const ClassType staticType = BaseType; + +protected: + int m_value; +}; + +template +class LIBSAMPLE_API TemplateBase : public Base +{ +public: + explicit TemplateBase(int value) : Base(value) {} + inline int multiplicator() const { return (int)CLASS_TYPE; } + inline int calculate() const { return m_value * ((int)CLASS_TYPE); } + static inline ClassType classType() { return CLASS_TYPE; } + + inline int sumValueUsingPointer(TemplateBase* other) const { return m_value + other->m_value; } + inline int sumValueUsingReference(TemplateBase& other) const { return m_value + other.m_value; } + + inline std::list > getListOfThisTemplateBase() + { + std::list > objs; + objs.push_back(*this); + objs.push_back(*this); + return objs; + } + + static inline TemplateBase* passPointerThrough(TemplateBase* obj) { return obj; } + + virtual ClassType type() const { return CLASS_TYPE; } + static const ClassType staticType = CLASS_TYPE; +}; + +#if defined _WIN32 || defined __CYGWIN__ +template class LIBSAMPLE_API TemplateBase; +template class LIBSAMPLE_API TemplateBase; +#endif + +typedef TemplateBase ValueIdentity; +typedef TemplateBase ValueDuplicator; + +LIBSAMPLE_API int callCalculateForValueDuplicatorPointer(ValueDuplicator* value); +LIBSAMPLE_API int callCalculateForValueDuplicatorReference(ValueDuplicator& value); +LIBSAMPLE_API int countValueIdentities(const std::list& values); +LIBSAMPLE_API int countValueDuplicators(const std::list >& values); + +// This simulates an internal error (SEGV) caused by 'noexcept' in +// boost::intrusive_ptr before support for 'noexcept' was added. The ENTIRE +// code below is needed to trigger the exception; it isn't seen with just a +// 'noexcept' following a declaration. +// +// NOTE: For reasons that should be fairly obvious, this test unfortunately can +// only be "run" when building in C++11 mode. +#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) +# define PHOTON_NOEXCEPT noexcept +#else +# define PHOTON_NOEXCEPT +#endif +class Pointer +{ +public: + Pointer() PHOTON_NOEXCEPT : px(0) {} + Pointer(int* p) : px(p) {} + + void reset() PHOTON_NOEXCEPT { Pointer().swap(*this); } + + int* get() const PHOTON_NOEXCEPT { return px; } + int& operator*() const { return *px; } + + void swap(Pointer& rhs) PHOTON_NOEXCEPT + { + int* tmp = px; + px = rhs.px; + rhs.px = tmp; + } + +private: + int* px; +}; + +} // namespace Photon + +#endif // PHOTON_H diff --git a/sources/shiboken2/tests/libsample/point.cpp b/sources/shiboken2/tests/libsample/point.cpp new file mode 100644 index 000000000..30275393b --- /dev/null +++ b/sources/shiboken2/tests/libsample/point.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "point.h" + +using namespace std; + +Point::Point(int x, int y) : m_x(x), m_y(y) +{ +} + +Point::Point(double x, double y) : m_x(x), m_y(y) +{ +} + +void +Point::midpoint(const Point& other, Point* midpoint) const +{ + if (!midpoint) + return; + midpoint->setX((m_x + other.m_x) / 2.0); + midpoint->setY((m_y + other.m_y) / 2.0); +} + +Point* +Point::copy() const +{ + Point* pt = new Point(); + pt->m_x = m_x; + pt->m_y = m_y; + return pt; +} + +void +Point::show() +{ + cout << "(x: " << m_x << ", y: " << m_y << ")"; +} + +bool +Point::operator==(const Point& other) +{ + return m_x == other.m_x && m_y == other.m_y; +} + +Point +Point::operator+(const Point& other) +{ + return Point(m_x + other.m_x, m_y + other.m_y); +} + +Point +Point::operator-(const Point& other) +{ + return Point(m_x - other.m_x, m_y - other.m_y); +} + +Point& +Point::operator+=(Point &other) +{ + m_x += other.m_x; + m_y += other.m_y; + return *this; +} + +Point& +Point::operator-=(Point &other) +{ + m_x -= other.m_x; + m_y -= other.m_y; + return *this; +} + +Point +operator*(const Point& pt, double mult) +{ + return Point(pt.m_x * mult, pt.m_y * mult); +} + +Point +operator*(const Point& pt, int mult) +{ + return Point(((int) pt.m_x) * mult, ((int) pt.m_y) * mult); +} + +Point +operator*(double mult, const Point& pt) +{ + return Point(pt.m_x * mult, pt.m_y * mult); +} + +Point +operator*(int mult, const Point& pt) +{ + return Point(((int) pt.m_x) * mult, ((int) pt.m_y) * mult); +} + +Point +operator-(const Point& pt) +{ + return Point(-pt.m_x, -pt.m_y); +} + +bool +operator!(const Point& pt) +{ + return (pt.m_x == 0.0 && pt.m_y == 0.0); +} + +Point +Point::operator/(int operand) +{ + return Point(m_x/operand, m_y/operand); +} + +Complex +transmutePointIntoComplex(const Point& point) +{ + Complex cpx(point.x(), point.y()); + return cpx; +} + +Point +transmuteComplexIntoPoint(const Complex& cpx) +{ + Point pt(cpx.real(), cpx.imag()); + return pt; +} + diff --git a/sources/shiboken2/tests/libsample/point.h b/sources/shiboken2/tests/libsample/point.h new file mode 100644 index 000000000..9416d6ddf --- /dev/null +++ b/sources/shiboken2/tests/libsample/point.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 POINT_H +#define POINT_H + +#include "complex.h" +#include + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Point +{ +public: + Point(int x = 0, int y = 0); + Point(double x, double y); + ~Point() {} + + inline double x() const { return m_x; } + inline double y() const { return m_y; } + + inline void setX(double x) { m_x = x; } + inline void setY(double y) { m_y = y; } + inline void setXAsUint(unsigned int x) { m_x = x; } + inline void setYAsUint(unsigned int y) { m_y = y; } + + // This method could simply return the midpoint, + // but the interesting part of the test is to set the + // result in the pointer argument. + void midpoint(const Point& other, Point* midpoint) const; + + Point* copy() const; + + inline const Point& getConstReferenceToSelf() const { return *this; } + inline const Point* getSelf() const { return this; } + + // The != operator is not implemented for the purpose of testing + // for the absense of the __ne__ method in the Python binding. + bool operator==(const Point& other); + + Point operator+(const Point& other); + Point operator-(const Point& other); + Point operator/(int operand); + + friend LIBSAMPLE_API Point operator*(const Point& pt, double mult); + friend LIBSAMPLE_API Point operator*(const Point& pt, int mult); + friend LIBSAMPLE_API Point operator*(double mult, const Point& pt); + friend LIBSAMPLE_API Point operator*(int mult, const Point& pt); + friend LIBSAMPLE_API Point operator-(const Point& pt); + friend LIBSAMPLE_API bool operator!(const Point& pt); + + Point& operator+=(Point &other); + Point& operator-=(Point &other); + + void show(); + +private: + double m_x; + double m_y; +}; + +LIBSAMPLE_API Point operator*(const Point& pt, double mult); +LIBSAMPLE_API Point operator*(const Point& pt, int mult); +LIBSAMPLE_API Point operator*(double mult, const Point& pt); +LIBSAMPLE_API Point operator*(int mult, const Point& pt); +LIBSAMPLE_API Point operator-(const Point& pt); +LIBSAMPLE_API bool operator!(const Point& pt); + +LIBSAMPLE_API Complex transmutePointIntoComplex(const Point& point); +LIBSAMPLE_API Point transmuteComplexIntoPoint(const Complex& cpx); + +LIBSAMPLE_API Point operator*(const Point& pt, double multiplier); + +#endif // POINT_H diff --git a/sources/shiboken2/tests/libsample/pointerholder.h b/sources/shiboken2/tests/libsample/pointerholder.h new file mode 100644 index 000000000..84e709d38 --- /dev/null +++ b/sources/shiboken2/tests/libsample/pointerholder.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 POINTERHOLDER_H +#define POINTERHOLDER_H + +#include "libsamplemacros.h" + +class PointerHolder +{ +public: + explicit PointerHolder(void* ptr) : m_pointer(ptr) {} + ~PointerHolder() {} + inline void* pointer() const { return m_pointer; } +private: + void* m_pointer; +}; + +#endif // POINTERHOLDER_H + diff --git a/sources/shiboken2/tests/libsample/pointf.cpp b/sources/shiboken2/tests/libsample/pointf.cpp new file mode 100644 index 000000000..0719bdb87 --- /dev/null +++ b/sources/shiboken2/tests/libsample/pointf.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "pointf.h" + +using namespace std; + +PointF::PointF(const Point& point) : m_x(point.x()), m_y(point.y()) +{ +} + +PointF::PointF(double x, double y) : m_x(x), m_y(y) +{ +} + +void +PointF::midpoint(const PointF& other, PointF* midpoint) const +{ + if (!midpoint) + return; + midpoint->setX((m_x + other.m_x) / 2.0); + midpoint->setY((m_y + other.m_y) / 2.0); +} + +void +PointF::show() +{ + cout << "(x: " << m_x << ", y: " << m_y << ")"; +} + +bool +PointF::operator==(const PointF& other) +{ + return m_x == other.m_x && m_y == other.m_y; +} + +PointF +PointF::operator+(const PointF& other) +{ + return PointF(m_x + other.m_x, m_y + other.m_y); +} + +PointF +PointF::operator-(const PointF& other) +{ + return PointF(m_x - other.m_x, m_y - other.m_y); +} + +PointF& +PointF::operator+=(PointF &other) +{ + m_x += other.m_x; + m_y += other.m_y; + return *this; +} + +PointF& +PointF::operator-=(PointF &other) +{ + m_x -= other.m_x; + m_y -= other.m_y; + return *this; +} + +PointF +operator*(const PointF& pt, double mult) +{ + return PointF(pt.m_x * mult, pt.m_y * mult); +} + +PointF +operator*(const PointF& pt, int mult) +{ + return PointF(((int) pt.m_x) * mult, ((int) pt.m_y) * mult); +} + +PointF +operator*(double mult, const PointF& pt) +{ + return PointF(pt.m_x * mult, pt.m_y * mult); +} + +PointF +operator*(int mult, const PointF& pt) +{ + return PointF(((int) pt.m_x) * mult, ((int) pt.m_y) * mult); +} + +PointF +operator-(const PointF& pt) +{ + return PointF(-pt.m_x, -pt.m_y); +} + +bool +operator!(const PointF& pt) +{ + return (pt.m_x == 0.0 && pt.m_y == 0.0); +} + diff --git a/sources/shiboken2/tests/libsample/pointf.h b/sources/shiboken2/tests/libsample/pointf.h new file mode 100644 index 000000000..c80739fea --- /dev/null +++ b/sources/shiboken2/tests/libsample/pointf.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 POINTF_H +#define POINTF_H + +#include "point.h" +#include + +#include "libsamplemacros.h" + +class LIBSAMPLE_API PointF +{ +public: + PointF(const Point& point); + PointF(double x = 0.0, double y = 0.0); + ~PointF() {} + + inline double x() const { return m_x; } + inline double y() const { return m_y; } + + inline void setX(double x) { m_x = x; } + inline void setY(double y) { m_y = y; } + + // This method could simply return the midpoint, + // but the interesting part of the test is to set the + // result in the pointer argument. + void midpoint(const PointF& other, PointF* midpoint) const; + + // The != operator is not implemented for the purpose of testing + // for the absence of the __ne__ method in the Python binding. + bool operator==(const PointF& other); + + PointF operator+(const PointF& other); + PointF operator-(const PointF& other); + + friend LIBSAMPLE_API PointF operator*(const PointF& pt, double mult); + friend LIBSAMPLE_API PointF operator*(const PointF& pt, int mult); + friend LIBSAMPLE_API PointF operator*(double mult, const PointF& pt); + friend LIBSAMPLE_API PointF operator*(int mult, const PointF& pt); + friend LIBSAMPLE_API PointF operator-(const PointF& pt); + friend LIBSAMPLE_API bool operator!(const PointF& pt); + + PointF& operator+=(PointF &other); + PointF& operator-=(PointF &other); + + void show(); + +private: + double m_x; + double m_y; +}; + +LIBSAMPLE_API PointF operator*(const PointF& pt, double mult); +LIBSAMPLE_API PointF operator*(const PointF& pt, int mult); +LIBSAMPLE_API PointF operator*(double mult, const PointF& pt); +LIBSAMPLE_API PointF operator*(int mult, const PointF& pt); +LIBSAMPLE_API PointF operator-(const PointF& pt); +LIBSAMPLE_API bool operator!(const PointF& pt); + +LIBSAMPLE_API PointF operator*(const PointF& pt, double multiplier); + +#endif // POINTF_H diff --git a/sources/shiboken2/tests/libsample/polygon.cpp b/sources/shiboken2/tests/libsample/polygon.cpp new file mode 100644 index 000000000..cb553a75c --- /dev/null +++ b/sources/shiboken2/tests/libsample/polygon.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "polygon.h" + +using namespace std; + +Polygon::Polygon(double x, double y) +{ + m_points.push_back(Point(x, y)); +} + +Polygon::Polygon(Point point) +{ + m_points.push_back(point); +} + +Polygon::Polygon(PointList points) +{ + m_points = points; +} + +void +Polygon::addPoint(Point point) +{ + m_points.push_back(point); +} + +Polygon +Polygon::doublePolygonScale(Polygon polygon) +{ + Polygon result; + for(PointList::const_iterator piter = result.points().begin(); piter != result.points().end(); piter++) + result.addPoint((*piter) * 2.0); + return result; +} + +void +Polygon::stealOwnershipFromPython(Point* point) +{ + delete point; +} + +void +Polygon::stealOwnershipFromPython(Polygon* polygon) +{ + delete polygon; +} + diff --git a/sources/shiboken2/tests/libsample/polygon.h b/sources/shiboken2/tests/libsample/polygon.h new file mode 100644 index 000000000..5e0769e0f --- /dev/null +++ b/sources/shiboken2/tests/libsample/polygon.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 POLYGON_H +#define POLYGON_H + +#include +#include "point.h" + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Polygon +{ +public: + typedef std::list PointList; + + Polygon() {} + Polygon(double x, double y); + Polygon(Point point); + Polygon(PointList points); + ~Polygon() {} + + void addPoint(Point point); + + inline const PointList& points() const { return m_points; } + + // This method intentionally receives and returns copies of a Polygon object. + static Polygon doublePolygonScale(Polygon polygon); + + // This method invalidates the argument to be used for Polygon(Point) implicit conversion. + static void stealOwnershipFromPython(Point* point); + + // This method invalidates the argument to be used in a call to doublePolygonScale(Polygon). + static void stealOwnershipFromPython(Polygon* polygon); + +private: + PointList m_points; +}; + +#endif // POLYGON_H + diff --git a/sources/shiboken2/tests/libsample/privatector.h b/sources/shiboken2/tests/libsample/privatector.h new file mode 100644 index 000000000..4f4699761 --- /dev/null +++ b/sources/shiboken2/tests/libsample/privatector.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 PRIVATECTOR_H +#define PRIVATECTOR_H + +#include "libsamplemacros.h" + +class PrivateCtor +{ +public: + inline static PrivateCtor* instance() + { + static PrivateCtor self; + self.m_instanciations++; + return &self; + } + + inline int instanceCalls() + { + return m_instanciations; + } + +private: + int m_instanciations; + + PrivateCtor() : m_instanciations(0) {} +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/privatedtor.h b/sources/shiboken2/tests/libsample/privatedtor.h new file mode 100644 index 000000000..a0c4d4769 --- /dev/null +++ b/sources/shiboken2/tests/libsample/privatedtor.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 PRIVATEDTOR_H +#define PRIVATEDTOR_H + +#include "libsamplemacros.h" + +class PrivateDtor +{ +public: + inline static PrivateDtor* instance() + { + static PrivateDtor self; + self.m_instanciations++; + return &self; + } + + inline int instanceCalls() + { + return m_instanciations; + } + +protected: + inline int protectedInstanceCalls() { return m_instanciations; } + +private: + int m_instanciations; + + PrivateDtor() : m_instanciations(0) {} + PrivateDtor(const PrivateDtor&) {} + ~PrivateDtor() {} +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/protected.cpp b/sources/shiboken2/tests/libsample/protected.cpp new file mode 100644 index 000000000..08c9fd065 --- /dev/null +++ b/sources/shiboken2/tests/libsample/protected.cpp @@ -0,0 +1,32 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "protected.h" + +int ProtectedVirtualDestructor::dtor_called = 0; + diff --git a/sources/shiboken2/tests/libsample/protected.h b/sources/shiboken2/tests/libsample/protected.h new file mode 100644 index 000000000..c33bdf4b2 --- /dev/null +++ b/sources/shiboken2/tests/libsample/protected.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 PROTECTED_H +#define PROTECTED_H + +#include "libsamplemacros.h" +#include "objecttype.h" +#include "point.h" +#include +#include + +class LIBSAMPLE_API ProtectedNonPolymorphic +{ +public: + explicit ProtectedNonPolymorphic(const char *name) : m_name(name) {} + ~ProtectedNonPolymorphic() {} + + inline const char* publicName() { return m_name.c_str(); } + + inline static ProtectedNonPolymorphic* create() { return new ProtectedNonPolymorphic("created"); } + +protected: + inline const char* protectedName() { return m_name.c_str(); } + inline int protectedSum(int a0, int a1) { return a0 + a1; } + inline int modifiedProtectedSum(int a0, int a1) { return a0 + a1; } + inline static const char* protectedStatic() { return "protectedStatic"; } + inline const char* dataTypeName(void *data = 0) const { return "pointer"; } + inline const char* dataTypeName(int data) const { return "integer"; } + +private: + std::string m_name; +}; + +class LIBSAMPLE_API ProtectedPolymorphic +{ +public: + explicit ProtectedPolymorphic(const char *name) : m_name(name) {} + virtual ~ProtectedPolymorphic() {} + + inline static ProtectedPolymorphic* create() { return new ProtectedPolymorphic("created"); } + inline const char* publicName() { return m_name.c_str(); } + inline const char* callProtectedName() { return protectedName(); } + +protected: + virtual const char* protectedName() { return m_name.c_str(); } + +private: + std::string m_name; +}; + +class LIBSAMPLE_API ProtectedPolymorphicDaughter : public ProtectedPolymorphic +{ +public: + explicit ProtectedPolymorphicDaughter(const char *name) : ProtectedPolymorphic(name) {} + inline static ProtectedPolymorphicDaughter* create() { return new ProtectedPolymorphicDaughter("created"); } +}; + +class LIBSAMPLE_API ProtectedPolymorphicGrandDaughter: public ProtectedPolymorphicDaughter +{ +public: + explicit ProtectedPolymorphicGrandDaughter(const char *name) : ProtectedPolymorphicDaughter(name) {} + inline static ProtectedPolymorphicGrandDaughter* create() { return new ProtectedPolymorphicGrandDaughter("created"); } +}; + +class LIBSAMPLE_API ProtectedVirtualDestructor +{ +public: + ProtectedVirtualDestructor() {} + inline static ProtectedVirtualDestructor* create() { return new ProtectedVirtualDestructor(); } + inline static int dtorCalled() { return dtor_called; } + inline static void resetDtorCounter() { dtor_called = 0; } +protected: + virtual ~ProtectedVirtualDestructor() { dtor_called++; } +private: + static int dtor_called; +}; + +class LIBSAMPLE_API ProtectedEnumClass +{ +public: + ProtectedEnumClass() {} + virtual ~ProtectedEnumClass() {} + enum PublicEnum { + PublicItem0, + PublicItem1 + }; +protected: + enum ProtectedEnum { + ProtectedItem0, + ProtectedItem1 + }; + ProtectedEnum callProtectedEnumMethod(ProtectedEnum in) { return protectedEnumMethod(in); } + inline PublicEnum callPublicEnumMethod(PublicEnum in) { return publicEnumMethod(in); } + + virtual ProtectedEnum protectedEnumMethod(ProtectedEnum in) { return in; } + virtual PublicEnum publicEnumMethod(PublicEnum in) { return in; } +}; + + +class LIBSAMPLE_API ProtectedProperty +{ +public: + ProtectedProperty() + : protectedValueTypeProperty(Point(0, 0)), + protectedProperty(0), + protectedEnumProperty(Event::NO_EVENT), + protectedValueTypePointerProperty(0), + protectedObjectTypeProperty(0) + {} +protected: + // This is deliberately the first member to test wrapper registration + // for value type members sharing the same memory address. + Point protectedValueTypeProperty; + int protectedProperty; + std::list protectedContainerProperty; + Event::EventType protectedEnumProperty; + Point* protectedValueTypePointerProperty; + ObjectType* protectedObjectTypeProperty; +}; + +LIBSAMPLE_API inline ProtectedProperty* createProtectedProperty() { + return new ProtectedProperty; +} + +#endif // PROTECTED_H diff --git a/sources/shiboken2/tests/libsample/rect.h b/sources/shiboken2/tests/libsample/rect.h new file mode 100644 index 000000000..b7ce6e890 --- /dev/null +++ b/sources/shiboken2/tests/libsample/rect.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 RECT_H +#define RECT_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Rect +{ +public: + Rect() + { + m_left = m_top = 0; + m_right = m_bottom = -1; + } + Rect(int left, int top, int right, int bottom) + : m_left(left), m_top(top), m_right(right), m_bottom(bottom) { } + ~Rect() {} + inline int left() const { return m_left; } + inline int top() const { return m_top; } + inline int right() const { return m_right; } + inline int bottom() const { return m_bottom; } +private: + int m_left; + int m_top; + int m_right; + int m_bottom; +}; + +class LIBSAMPLE_API RectF +{ +public: + RectF() + { + m_left = m_top = 0; + m_right = m_bottom = -1; + } + RectF(int left, int top, int right, int bottom) + : m_left(left), m_top(top), m_right(right), m_bottom(bottom) { } + RectF(const Rect& other) + { + m_left = other.left(); + m_top = other.top(); + m_right = other.right(); + m_bottom = other.bottom(); + } + ~RectF() {} + inline double left() const { return m_left; } + inline double top() const { return m_top; } + inline double right() const { return m_right; } + inline double bottom() const { return m_bottom; } +private: + double m_left; + double m_top; + double m_right; + double m_bottom; +}; + +#endif // RECT_H + diff --git a/sources/shiboken2/tests/libsample/reference.cpp b/sources/shiboken2/tests/libsample/reference.cpp new file mode 100644 index 000000000..31a11a8ae --- /dev/null +++ b/sources/shiboken2/tests/libsample/reference.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "reference.h" + +using namespace std; + +void +Reference::show() const +{ + cout << "Reference.objId: " << m_objId << ", address: " << this; +} + +int +Reference::usesReferenceVirtual(Reference& r, int inc) +{ + return r.m_objId + inc; +} + +int +Reference::usesConstReferenceVirtual(const Reference& r, int inc) +{ + return r.m_objId + inc; +} + +int +Reference::callUsesReferenceVirtual(Reference& r, int inc) +{ + return usesReferenceVirtual(r, inc); +} + +int +Reference::callUsesConstReferenceVirtual(const Reference& r, int inc) +{ + return usesConstReferenceVirtual(r, inc); +} + +void +Reference::alterReferenceIdVirtual(Reference& r) +{ + r.setObjId(r.objId() * Reference::multiplier()); +} + +void +Reference::callAlterReferenceIdVirtual(Reference& r) +{ + alterReferenceIdVirtual(r); +} + +ObjTypeReference::~ObjTypeReference() +{ +} diff --git a/sources/shiboken2/tests/libsample/reference.h b/sources/shiboken2/tests/libsample/reference.h new file mode 100644 index 000000000..4ec8ee7fd --- /dev/null +++ b/sources/shiboken2/tests/libsample/reference.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 REFERENCE_H +#define REFERENCE_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Reference +{ +public: + explicit Reference(int objId = -1) + : m_objId(objId) {} + virtual ~Reference() {} + + inline int objId() { return m_objId; } + inline void setObjId(int objId) { m_objId = objId; } + + inline static int usesReference(Reference& r) { return r.m_objId; } + inline static int usesConstReference(const Reference& r) { return r.m_objId; } + + virtual int usesReferenceVirtual(Reference& r, int inc); + virtual int usesConstReferenceVirtual(const Reference& r, int inc); + + int callUsesReferenceVirtual(Reference& r, int inc); + int callUsesConstReferenceVirtual(const Reference& r, int inc); + + virtual void alterReferenceIdVirtual(Reference& r); + void callAlterReferenceIdVirtual(Reference& r); + + void show() const; + + inline static int multiplier() { return 10; } + + virtual Reference& returnMyFirstArg(Reference& ref) { return ref; } + virtual Reference& returnMySecondArg(int a, Reference& ref) { return ref; } + + // nonsense operator to test if Shiboken is ignoring dereference operators. + int operator*() { return m_objId; } +private: + int m_objId; +}; + +class LIBSAMPLE_API ObjTypeReference +{ +public: + ObjTypeReference() {} + ObjTypeReference(const ObjTypeReference&) {} + virtual ~ObjTypeReference(); + virtual ObjTypeReference& returnMyFirstArg(ObjTypeReference& ref) { return ref; } + virtual ObjTypeReference& returnMySecondArg(int a, ObjTypeReference& ref) { return ref; } + virtual ObjTypeReference& justAPureVirtualFunc(ObjTypeReference& ref) = 0; +}; + +#endif // REFERENCE_H + diff --git a/sources/shiboken2/tests/libsample/removednamespaces.h b/sources/shiboken2/tests/libsample/removednamespaces.h new file mode 100644 index 000000000..4520b6a27 --- /dev/null +++ b/sources/shiboken2/tests/libsample/removednamespaces.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 REMOVEDNAMESPACE_H +#define REMOVEDNAMESPACE_H + +#include "libsamplemacros.h" + +namespace RemovedNamespace1 +{ + +enum RemovedNamespace1_Enum { + RemovedNamespace1_Enum_Value0 +}; + +enum { + RemovedNamespace1_AnonymousEnum_Value0 +}; + +namespace RemovedNamespace2 { + enum RemovedNamespace2_Enum { + RemovedNamespace2_Enum_Value0 + }; +} + +} + +namespace UnremovedNamespace +{ +namespace RemovedNamespace3 +{ + enum RemovedNamespace3_Enum { + RemovedNamespace3_Enum_Value0 + }; + + enum { + RemovedNamespace3_AnonymousEnum_Value0 + }; +} +} + +#endif // REMOVEDNAMESPACE_H + diff --git a/sources/shiboken2/tests/libsample/sample.cpp b/sources/shiboken2/tests/libsample/sample.cpp new file mode 100644 index 000000000..fa1e1fda3 --- /dev/null +++ b/sources/shiboken2/tests/libsample/sample.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "sample.h" + +sample::sample::sample(int value) : m_value(value) +{ +} + +int sample::sample::value() const +{ + return m_value; +} + diff --git a/sources/shiboken2/tests/libsample/sample.h b/sources/shiboken2/tests/libsample/sample.h new file mode 100644 index 000000000..46e3d0d1a --- /dev/null +++ b/sources/shiboken2/tests/libsample/sample.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 SAMPLE_H +#define SAMPLE_H + +#include "libsamplemacros.h" + +// namespace with the same name of the current package to try to mess up with the generator +namespace sample +{ + // to increase the mess we add a class with the same name of the package/namespace + class LIBSAMPLE_API sample + { + public: + sample(int value = 0); + int value() const; + private: + int m_value; + }; +} + +#endif diff --git a/sources/shiboken2/tests/libsample/samplenamespace.cpp b/sources/shiboken2/tests/libsample/samplenamespace.cpp new file mode 100644 index 000000000..1fc6dff40 --- /dev/null +++ b/sources/shiboken2/tests/libsample/samplenamespace.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include +#include +#include "samplenamespace.h" + +using namespace std; + +namespace SampleNamespace +{ + +OutValue +enumInEnumOut(InValue in) +{ + OutValue retval; + switch(in) { + case ZeroIn: + retval = ZeroOut; + break; + case OneIn: + retval = OneOut; + break; + case TwoIn: + retval = TwoOut; + break; + default: + retval = (OutValue) -1; + } + return retval; +} + +Option +enumArgumentWithDefaultValue(Option opt) +{ + return opt; +} + +int +getNumber(Option opt) +{ + int retval; + switch(opt) { + case RandomNumber: + retval = rand() % 100; + break; + case UnixTime: + retval = (int) time(0); + break; + default: + retval = 0; + } + return retval; +} + +void +doSomethingWithArray(const unsigned char* data, unsigned int size, const char* format) +{ + // This function does nothing in fact. + // It is here as a dummy copy of QPixmap.loadFromData method + // to check compilation issues, i.e. if it compiles, it's ok. +} + +int +enumItemAsDefaultValueToIntArgument(int value) +{ + return value; +} + +void +forceDecisorSideA(ObjectType* object) +{ +} + +void +forceDecisorSideA(const Point& pt, const Str& text, ObjectType* object) +{ +} + +void +forceDecisorSideB(int a, ObjectType* object) +{ +} + +void +forceDecisorSideB(int a, const Point& pt, const Str& text, ObjectType* object) +{ +} + +double +passReferenceToValueType(const Point& point, double multiplier) +{ + return (point.x() + point.y()) * multiplier; +} + +int +passReferenceToObjectType(const ObjectType& obj, int multiplier) +{ + return obj.objectName().size() * multiplier; +} + +} // namespace SampleNamespace diff --git a/sources/shiboken2/tests/libsample/samplenamespace.h b/sources/shiboken2/tests/libsample/samplenamespace.h new file mode 100644 index 000000000..3ce410941 --- /dev/null +++ b/sources/shiboken2/tests/libsample/samplenamespace.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 SAMPLENAMESPACE_H +#define SAMPLENAMESPACE_H + +#include +#include "libsamplemacros.h" +#include "str.h" +#include "point.h" +#include "objecttype.h" + +// Anonymous global enum +enum { + AnonymousGlobalEnum_Value0, + AnonymousGlobalEnum_Value1 +}; + +// Invisible namespace +namespace Invisible +{ + +enum EnumOnNamespace { + Option1 = 1, + Option2 = 2, + Option3 = 3 +}; + +}; + +namespace SampleNamespace +{ + +enum Option { + None_, + RandomNumber, + UnixTime +}; + +enum InValue { + ZeroIn, + OneIn, + TwoIn +}; + +enum OutValue { + ZeroOut, + OneOut, + TwoOut +}; + +// Anonymous non-global enum. +// This counts as a class enum, since C++ namespaces +// are represented as classes in Python. +enum { + AnonymousClassEnum_Value0, + AnonymousClassEnum_Value1 +}; + +LIBSAMPLE_API OutValue enumInEnumOut(InValue in); + +LIBSAMPLE_API Option enumArgumentWithDefaultValue(Option opt = UnixTime); + +LIBSAMPLE_API int getNumber(Option opt); + +inline double powerOfTwo(double num) { + return num * num; +} + +LIBSAMPLE_API void doSomethingWithArray(const unsigned char* data, unsigned int size, const char* format = 0); + +LIBSAMPLE_API int enumItemAsDefaultValueToIntArgument(int value = ZeroIn); + +class SomeClass +{ +public: + class SomeInnerClass + { + public: + class OkThisIsRecursiveEnough + { + public: + virtual ~OkThisIsRecursiveEnough() {} + enum NiceEnum { + NiceValue1, NiceValue2 + }; + + inline int someMethod(SomeInnerClass*) { return 0; } + virtual OkThisIsRecursiveEnough* someVirtualMethod(OkThisIsRecursiveEnough* arg) { return arg; } + }; + protected: + enum ProtectedEnum { + ProtectedItem0, + ProtectedItem1 + }; + }; + struct SomeOtherInnerClass { + std::list someInnerClasses; + }; +protected: + enum ProtectedEnum { + ProtectedItem0, + ProtectedItem1 + }; +}; + +class DerivedFromNamespace : public SomeClass::SomeInnerClass::OkThisIsRecursiveEnough +{ +public: + // FIXME Uncomment this when the fix for MSVC is available + // only to cause namespace confusion +// enum SampleNamespace { +// }; + virtual OkThisIsRecursiveEnough* someVirtualMethod(OkThisIsRecursiveEnough* arg) { return arg; } + inline OkThisIsRecursiveEnough* methodReturningTypeFromParentScope() { return 0; } +}; + +// The combination of the following two overloaded methods could trigger a +// problematic behaviour on the overload decisor, if it isn't working properly. +LIBSAMPLE_API void forceDecisorSideA(ObjectType* object = 0); +LIBSAMPLE_API void forceDecisorSideA(const Point& pt, const Str& text, ObjectType* object = 0); + +// The combination of the following two overloaded methods could trigger a +// problematic behaviour on the overload decisor, if it isn't working properly. +// This is a variation of forceDecisorSideB. +LIBSAMPLE_API void forceDecisorSideB(int a, ObjectType* object = 0); +LIBSAMPLE_API void forceDecisorSideB(int a, const Point& pt, const Str& text, ObjectType* object = 0); + +// Add a new signature on type system with only a Point value as parameter. +LIBSAMPLE_API double passReferenceToValueType(const Point& point, double multiplier); +// Add a new signature on type system with only a ObjectType pointer as parameter. +LIBSAMPLE_API int passReferenceToObjectType(const ObjectType& obj, int multiplier); + +} // namespace SampleNamespace + +#endif // SAMPLENAMESPACE_H + diff --git a/sources/shiboken2/tests/libsample/sbkdate.cpp b/sources/shiboken2/tests/libsample/sbkdate.cpp new file mode 100644 index 000000000..e823521ec --- /dev/null +++ b/sources/shiboken2/tests/libsample/sbkdate.cpp @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "sbkdate.h" + +SbkDate::SbkDate(int d, int m, int y) : m_d(d), m_m(m), m_y(y) +{ +} + +int SbkDate::day() const +{ + return m_d; +} + +int SbkDate::month() const +{ + return m_m; +} + +int SbkDate::year() const +{ + return m_y; +} diff --git a/sources/shiboken2/tests/libsample/sbkdate.h b/sources/shiboken2/tests/libsample/sbkdate.h new file mode 100644 index 000000000..7d0893cbb --- /dev/null +++ b/sources/shiboken2/tests/libsample/sbkdate.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 SBKDATE_H +#define SBKDATE_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API SbkDate +{ +public: + SbkDate(int d, int m, int y); + + int day() const; + int month() const; + int year() const; + +private: + int m_d; + int m_m; + int m_y; +}; + +#endif // SBKDATE_H + diff --git a/sources/shiboken2/tests/libsample/simplefile.cpp b/sources/shiboken2/tests/libsample/simplefile.cpp new file mode 100644 index 000000000..bdbd3d1f5 --- /dev/null +++ b/sources/shiboken2/tests/libsample/simplefile.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include +#include +#include "simplefile.h" + +class SimpleFile_p +{ +public: + SimpleFile_p(const char* filename) : m_descriptor(0), m_size(0) + { + m_filename = strdup(filename); + } + + ~SimpleFile_p() + { + free(m_filename); + } + + char* m_filename; + FILE* m_descriptor; + long m_size; +}; + +SimpleFile::SimpleFile(const char* filename) +{ + p = new SimpleFile_p(filename); +} + +SimpleFile::~SimpleFile() +{ + close(); + delete p; +} + +const char* SimpleFile::filename() +{ + return p->m_filename; +} + +long SimpleFile::size() +{ + return p->m_size; +} + +bool +SimpleFile::open() +{ + if ((p->m_descriptor = fopen(p->m_filename, "rb")) == 0) + return false; + + fseek(p->m_descriptor, 0, SEEK_END); + p->m_size = ftell(p->m_descriptor); + rewind(p->m_descriptor); + + return true; +} + +void +SimpleFile::close() +{ + if (p->m_descriptor) { + fclose(p->m_descriptor); + p->m_descriptor = 0; + } +} + +bool +SimpleFile::exists() const +{ + std::ifstream ifile(p->m_filename); + return !ifile.fail(); +} + +bool +SimpleFile::exists(const char* filename) +{ + std::ifstream ifile(filename); + return !ifile.fail(); +} + diff --git a/sources/shiboken2/tests/libsample/simplefile.h b/sources/shiboken2/tests/libsample/simplefile.h new file mode 100644 index 000000000..bae3b9998 --- /dev/null +++ b/sources/shiboken2/tests/libsample/simplefile.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 SIMPLEFILE_H +#define SIMPLEFILE_H + +#include "libsamplemacros.h" +#include + +class SimpleFile_p; + +class LIBSAMPLE_API SimpleFile +{ +public: + explicit SimpleFile(const char* filename); + ~SimpleFile(); + + const char* filename(); + long size(); + bool open(); + void close(); + + bool exists() const; + static bool exists(const char* filename); + +private: + SimpleFile_p *p; +}; + +#endif // SIMPLEFILE_H + diff --git a/sources/shiboken2/tests/libsample/size.cpp b/sources/shiboken2/tests/libsample/size.cpp new file mode 100644 index 000000000..1faf5dfb2 --- /dev/null +++ b/sources/shiboken2/tests/libsample/size.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "size.h" + +using namespace std; + +void +Size::show() const +{ + cout << "(width: " << m_width << ", height: " << m_height << ")"; +} + diff --git a/sources/shiboken2/tests/libsample/size.h b/sources/shiboken2/tests/libsample/size.h new file mode 100644 index 000000000..433aba770 --- /dev/null +++ b/sources/shiboken2/tests/libsample/size.h @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 SIZE_H +#define SIZE_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Size +{ +public: + Size(double width = 0.0, double height = 0.0) : m_width(width), m_height(height) {} + ~Size() {} + + inline double width() { return m_width; } + inline void setWidth(double width) { m_width = width; } + inline double height() { return m_height; } + inline void setHeight(double height) { m_height = height; } + + inline double calculateArea() const { return m_width * m_height; } + + // Comparison Operators + inline bool operator==(const Size& other) + { + return m_width == other.m_width && m_height == other.m_height; + } + + inline bool operator<(const Size& other) + { + return calculateArea() < other.calculateArea(); + } + + inline bool operator>(const Size& other) + { + // On some x86 hardware and compiler combinations, floating point + // comparisons may fail due to a hardware bug. One workaround is to + // simplify comparison expressions by putting partial results in + // variables. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323#c109 + // for details. + double a = calculateArea(); + double b = other.calculateArea(); + return a > b; + } + + inline bool operator<=(const Size& other) + { + // See comments for operator>() + double a = calculateArea(); + double b = other.calculateArea(); + return a <= b; + } + + inline bool operator>=(const Size& other) + { + return calculateArea() >= other.calculateArea(); + } + + inline bool operator<(double area) { return calculateArea() < area; } + inline bool operator>(double area) { return calculateArea() > area; } + inline bool operator<=(double area) { return calculateArea() <= area; } + inline bool operator>=(double area) { return calculateArea() >= area; } + + // Arithmetic Operators + inline Size& operator+=(const Size& s) + { + m_width += s.m_width; + m_height += s.m_height; + return *this; + } + + inline Size& operator-=(const Size& s) + { + m_width -= s.m_width; + m_height -= s.m_height; + return *this; + } + + inline Size& operator*=(double mult) + { + m_width *= mult; + m_height *= mult; + return *this; + } + + inline Size& operator/=(double div) + { + m_width /= div; + m_height /= div; + return *this; + } + + // TODO: add ++size, size++, --size, size-- + + // External operators + friend inline bool operator!=(const Size&, const Size&); + friend inline const Size operator+(const Size&, const Size&); + friend inline const Size operator-(const Size&, const Size&); + friend inline const Size operator*(const Size&, double); + friend inline const Size operator*(double, const Size&); + friend inline const Size operator/(const Size&, double); + + friend inline bool operator<(double, const Size&); + friend inline bool operator>(double, const Size&); + friend inline bool operator<=(double, const Size&); + friend inline bool operator>=(double, const Size&); + + void show() const; + +private: + double m_width; + double m_height; +}; + +// Comparison Operators +inline bool operator!=(const Size& s1, const Size& s2) +{ + return s1.m_width != s2.m_width || s1.m_height != s2.m_height; +} + +inline bool operator<(double area, const Size& s) +{ + return area < s.calculateArea(); +} + +inline bool operator>(double area, const Size& s) +{ + return area > s.calculateArea(); +} + +inline bool operator<=(double area, const Size& s) +{ + return area <= s.calculateArea(); +} + +inline bool operator>=(double area, const Size& s) +{ + return area >= s.calculateArea(); +} + +// Arithmetic Operators +inline const Size operator+(const Size& s1, const Size& s2) +{ + return Size(s1.m_width + s2.m_width, s1.m_height + s2.m_height); +} + +inline const Size operator-(const Size& s1, const Size& s2) +{ + return Size(s1.m_width - s2.m_width, s1.m_height - s2.m_height); +} + +inline const Size operator*(const Size& s, double mult) +{ + return Size(s.m_width * mult, s.m_height * mult); +} + +inline const Size operator*(double mult, const Size& s) +{ + return Size(s.m_width * mult, s.m_height * mult); +} + +inline const Size operator/(const Size& s, double div) +{ + return Size(s.m_width / div, s.m_height / div); +} + +typedef double real; +typedef unsigned short ushort; +class LIBSAMPLE_API SizeF +{ +public: + SizeF(real width, real height) : m_width(width), m_height(height) {} + real width() { return m_width; } + real height() { return m_height; } + static inline ushort passTypedefOfUnsignedShort(ushort value) { return value; } +private: + real m_width; + real m_height; +}; + +#endif // SIZE_H + diff --git a/sources/shiboken2/tests/libsample/sometime.cpp b/sources/shiboken2/tests/libsample/sometime.cpp new file mode 100644 index 000000000..3038e26ca --- /dev/null +++ b/sources/shiboken2/tests/libsample/sometime.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "sometime.h" +#include + +void +Time::setTime() +{ + m_hour = 0; + m_minute = 0; + m_second = 0; + m_msec = 0; + m_is_null = true; +} + +void +Time::setTime(int h, int m, int s, int ms) +{ + m_hour = h; + m_minute = m; + m_second = s; + m_msec = ms; + m_is_null = false; +} + + +Time::NumArgs +Time::somethingCompletelyDifferent() +{ + return ZeroArgs; +} + +Time::NumArgs +Time::somethingCompletelyDifferent(int h, int m, ImplicitConv ic, ObjectType* type) +{ + if (type) + return FourArgs; + if (ic.ctorEnum() == ImplicitConv::CtorThree && ic.objId() == -1) + return TwoArgs; + return ThreeArgs; +} + +Str +Time::toString() const +{ + if (m_is_null) + return Str(); + char buffer[13]; + sprintf(buffer, "%02d:%02d:%02d.%03d", m_hour, m_minute, m_second, m_msec); + return Str(buffer); +} + +bool +Time::operator==(const Time& other) const +{ + return m_hour == other.m_hour + && m_minute == other.m_minute + && m_second == other.m_second + && m_msec == other.m_msec + && m_is_null == other.m_is_null; +} + +bool +Time::operator!=(const Time& other) const +{ + return !operator==(other); +} + +Time::operator Str() const +{ + return Time::toString(); +} + diff --git a/sources/shiboken2/tests/libsample/sometime.h b/sources/shiboken2/tests/libsample/sometime.h new file mode 100644 index 000000000..5f2ccf88a --- /dev/null +++ b/sources/shiboken2/tests/libsample/sometime.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 SOMETIME_H +#define SOMETIME_H + +#include "libsamplemacros.h" +#include "str.h" +#include "implicitconv.h" +#include "objecttype.h" + +class LIBSAMPLE_API Time +{ +public: + enum NumArgs { + ZeroArgs, + TwoArgs, + ThreeArgs, + FourArgs + }; + + Time() + : m_hour(0), m_minute(0), m_second(0), m_msec(0), m_is_null(true) + {} + Time(int h, int m, int s = 0, int ms = 0) + : m_hour(h), m_minute(m), m_second(s), m_msec(ms), m_is_null(false) + {} + + ~Time() {} + + inline bool isNull() const { return m_is_null; } + + inline int hour() const { return m_hour; } + inline int minute() const { return m_minute; } + inline int second() const { return m_second; } + inline int msec() const { return m_msec; } + + void setTime(); + void setTime(int h, int m, int s = 0, int ms = 0); + + // This one is completely different from the other methods in this class, + // it was added to give the overload decisor a really hard time with + // an value-type with implicit conversion and a default argument, and also + // an object-type, just because I feel like it. + NumArgs somethingCompletelyDifferent(); + NumArgs somethingCompletelyDifferent(int h, int m, + ImplicitConv ic = ImplicitConv::CtorThree, + ObjectType* type = 0); + + Str toString() const; + bool operator==(const Time& other) const; + bool operator!=(const Time& other) const; + + // This cast operator must become an implicit conversion of Str. + operator Str() const; + +private: + int m_hour; + int m_minute; + int m_second; + int m_msec; + + bool m_is_null; +}; + +#endif // SOMETIME_H + diff --git a/sources/shiboken2/tests/libsample/str.cpp b/sources/shiboken2/tests/libsample/str.cpp new file mode 100644 index 000000000..f3be2591e --- /dev/null +++ b/sources/shiboken2/tests/libsample/str.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "str.h" +#include +#include +#include +#include + +using namespace std; + +Str::Str(const Str& s) +{ + init(s.cstring()); +} + +Str::Str(char c) +{ + char str[2] = { c, 0 }; + init(str); +} + +Str::Str(const char* cstr) +{ + init(cstr); +} + +void +Str::init(const char* cstr) +{ + if (cstr) + m_str = cstr; +} + +Str::~Str() +{ +} + +Str +Str::arg(const Str& s) const +{ + size_t idx = m_str.find_first_of("%VAR"); + if (idx == std::string::npos) { + return *this; + } else { + std::string result = m_str; + result.replace(idx, 4, s.m_str); + return result.c_str(); + } +} + +Str& +Str::append(const Str& s) +{ + m_str += s.m_str; + return *this; +} + +Str& +Str::prepend(const Str& s) +{ + m_str = s.m_str + m_str; + return *this; +} + +const char* +Str::cstring() const +{ + return m_str.c_str(); +} + +int +Str::toInt(bool* ok, int base) const +{ + bool my_ok; + int result = 0; + istringstream conv(m_str); + switch (base) { + case 8: + conv >> std::oct >> result; + break; + case 10: + conv >> std::dec >> result; + break; + case 16: + conv >> std::hex >> result; + break; + } + my_ok = istringstream::eofbit & conv.rdstate(); + if (!my_ok) + result = 0; + if (ok) + *ok = my_ok; + return result; +} + +void +Str::show() const +{ + printf("%s", cstring()); +} + +char +Str::get_char(int pos) const +{ + return m_str[pos]; +} + +bool +Str::set_char(int pos, char ch) +{ + m_str[pos] = ch; + return true; +} + +Str Str::operator+(int number) const +{ + ostringstream in; + in << m_str << number; + return in.str().c_str(); +} + +bool Str::operator==(const Str& other) const +{ + return m_str == other.m_str; +} + +Str operator+(int number, const Str& str) +{ + ostringstream in; + in << number << str.m_str; + return in.str().c_str(); +} + +bool Str::operator<(const Str& other) const +{ + return m_str < other.m_str; +} + +unsigned int strHash(const Str& str) +{ + unsigned int result = 0; + const std::string& cppStr = str.m_str; + std::string::const_iterator it = cppStr.begin(); + for (; it != cppStr.end(); ++it) + result = 5 * result + *it; + return result; +} + +void changePStr(PStr* pstr, const char* suffix) +{ + pstr->append(suffix); +} + +void duplicatePStr(PStr* pstr) +{ + if (!pstr) + return; + pstr->append(*pstr); +} diff --git a/sources/shiboken2/tests/libsample/str.h b/sources/shiboken2/tests/libsample/str.h new file mode 100644 index 000000000..9c1e8c0a8 --- /dev/null +++ b/sources/shiboken2/tests/libsample/str.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 STR_H +#define STR_H +#include + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Str +{ +public: + Str(const Str& s); + Str(char c); + Str(const char* cstr = ""); + ~Str(); + + Str arg(const Str& s) const; + + Str& append(const Str& s); + Str& prepend(const Str& s); + + const char* cstring() const; + char get_char(int pos) const; + bool set_char(int pos, char ch); + + int toInt(bool* ok = 0, int base = 10) const; + + void show() const; + + inline int size() const { return m_str.size(); } + + // nonsense operator just to test reverse operators + Str operator+(int number) const; + bool operator==(const Str& other) const; + bool operator<(const Str& other) const; + +private: + void init(const char* cstr); + std::string m_str; + + friend LIBSAMPLE_API Str operator+(int number, const Str& str); + friend LIBSAMPLE_API unsigned int strHash(const Str& str); +}; + +LIBSAMPLE_API Str operator+(int number, const Str& str); +LIBSAMPLE_API unsigned int strHash(const Str& str); + +typedef Str PStr; +LIBSAMPLE_API void changePStr(PStr* pstr, const char* suffix); +LIBSAMPLE_API void duplicatePStr(PStr* pstr = 0); + +#endif // STR_H diff --git a/sources/shiboken2/tests/libsample/strlist.cpp b/sources/shiboken2/tests/libsample/strlist.cpp new file mode 100644 index 000000000..8956110d8 --- /dev/null +++ b/sources/shiboken2/tests/libsample/strlist.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "strlist.h" + +bool +StrList::operator==(const std::list& other) const +{ + if (size() != other.size()) + return false; + StrList::const_iterator this_it = begin(); + StrList::const_iterator other_it = begin(); + while (this_it != end()) { + if (!((*this_it) == (*other_it))) + return false; + ++this_it; + ++other_it; + } + return true; +} + +Str +StrList::join(const Str& sep) const +{ + Str result; + for (StrList::const_iterator it = begin(); it != end(); ++it) { + if (it != begin()) + result.append(sep); + result.append(*it); + } + return result; +} diff --git a/sources/shiboken2/tests/libsample/strlist.h b/sources/shiboken2/tests/libsample/strlist.h new file mode 100644 index 000000000..be908d5d5 --- /dev/null +++ b/sources/shiboken2/tests/libsample/strlist.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 STRLIST_H +#define STRLIST_H + +#include +#include "str.h" + +#include "libsamplemacros.h" + +class LIBSAMPLE_API StrList : public std::list +{ +public: + enum CtorEnum { + NoParamsCtor, + StrCtor, + CopyCtor, + ListOfStrCtor + }; + + inline StrList() : m_ctorUsed(NoParamsCtor) {} + inline explicit StrList(const Str& str) : m_ctorUsed(StrCtor) { push_back(str); } + inline StrList(const StrList& lst) : std::list(lst), m_ctorUsed(CopyCtor) {} + inline StrList(const std::list& lst) : std::list(lst), m_ctorUsed(ListOfStrCtor) {} + + inline void append(Str str) { push_back(str); } + Str join(const Str& sep) const; + + bool operator==(const std::list& other) const; + inline bool operator!=(const std::list& other) const { return !(*this == other); } + + CtorEnum constructorUsed() { return m_ctorUsed; } +private: + CtorEnum m_ctorUsed; +}; + +typedef StrList PStrList; + +#endif // STRLIST_H diff --git a/sources/shiboken2/tests/libsample/templateptr.cpp b/sources/shiboken2/tests/libsample/templateptr.cpp new file mode 100644 index 000000000..571184776 --- /dev/null +++ b/sources/shiboken2/tests/libsample/templateptr.cpp @@ -0,0 +1,33 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "templateptr.h" + +void TemplatePtr::dummy(std::list > & items) +{ +} \ No newline at end of file diff --git a/sources/shiboken2/tests/libsample/templateptr.h b/sources/shiboken2/tests/libsample/templateptr.h new file mode 100644 index 000000000..67e154b1c --- /dev/null +++ b/sources/shiboken2/tests/libsample/templateptr.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TEMPLATEPTR_H +#define TEMPLATEPTR_H + +#include +#include +#include "libsamplemacros.h" +#include "blackbox.h" + +class LIBSAMPLE_API TemplatePtr +{ +public: + void dummy(std::list > & items); +}; + +#endif diff --git a/sources/shiboken2/tests/libsample/transform.cpp b/sources/shiboken2/tests/libsample/transform.cpp new file mode 100644 index 000000000..951e2ca5b --- /dev/null +++ b/sources/shiboken2/tests/libsample/transform.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2013 Kitware, Inc. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "transform.h" + +#ifdef _WIN32 +#include +#include +static inline bool isfinite(double a) { return _finite(a); } +#else +#include +#endif + +using namespace std; + +Point applyHomogeneousTransform( + const Point& in, + double m11, double m12, double m13, + double m21, double m22, double m23, + double m31, double m32, double m33, + bool* okay) +{ + double x = m11 * in.x() + m12 * in.y() + m13; + double y = m21 * in.x() + m22 * in.y() + m23; + double w = m31 * in.x() + m32 * in.y() + m33; + + if (isfinite(w) && fabs(w) > 1e-10) + { + if (okay) + *okay = true; + return Point(x / w, y / w); + } + else + { + if (okay) + *okay = false; + return Point(); + } +} diff --git a/sources/shiboken2/tests/libsample/transform.h b/sources/shiboken2/tests/libsample/transform.h new file mode 100644 index 000000000..fda5b33c5 --- /dev/null +++ b/sources/shiboken2/tests/libsample/transform.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2013 Kitware, Inc. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 TRANSFORM_H +#define TRANSFORM_H + +#include "point.h" + +#include "libsamplemacros.h" + +LIBSAMPLE_API Point +applyHomogeneousTransform( + const Point& in, + double m11, double m12, double m13, + double m21, double m22, double m23, + double m31, double m32, double m33, + bool* okay); + +#endif // TRANSFORM_H diff --git a/sources/shiboken2/tests/libsample/valueandvirtual.h b/sources/shiboken2/tests/libsample/valueandvirtual.h new file mode 100644 index 000000000..54e8114b5 --- /dev/null +++ b/sources/shiboken2/tests/libsample/valueandvirtual.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 VALUEANDVIRTUAL_H +#define VALUEANDVIRTUAL_H + +class ValueAndVirtual +{ +public: + ValueAndVirtual(int id) : m_id(id) {} + ValueAndVirtual(const ValueAndVirtual &other) { m_id = other.m_id; } + + bool operator()(int id, int id2) { return id == id2; } + + inline int id() { return m_id; } + virtual ~ValueAndVirtual() {}; +private: + int m_id; +}; + +#endif // VALUEANDVIRTUAL_H + diff --git a/sources/shiboken2/tests/libsample/virtualmethods.cpp b/sources/shiboken2/tests/libsample/virtualmethods.cpp new file mode 100644 index 000000000..05b854e08 --- /dev/null +++ b/sources/shiboken2/tests/libsample/virtualmethods.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "virtualmethods.h" + +int VirtualDtor::dtor_called = 0; + +double +VirtualMethods::virtualMethod0(Point pt, int val, Complex cpx, bool b) +{ + return (pt.x() * pt.y() * val) + cpx.imag() + ((int) b); +} + +bool +VirtualMethods::createStr(const char* text, Str*& ret) +{ + if (!text) { + ret = 0; + return false; + } + + ret = new Str(text); + return true; +} + +void +VirtualMethods::getMargins(int* left, int* top, int* right, int* bottom) const +{ + *left = m_left; + *top = m_top; + *right = m_right; + *bottom = m_bottom; +} + diff --git a/sources/shiboken2/tests/libsample/virtualmethods.h b/sources/shiboken2/tests/libsample/virtualmethods.h new file mode 100644 index 000000000..5754d0d5d --- /dev/null +++ b/sources/shiboken2/tests/libsample/virtualmethods.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 VIRTUALMETHODS_H +#define VIRTUALMETHODS_H + +#include "point.h" +#include "complex.h" +#include "str.h" + +#include "libsamplemacros.h" +#include "strlist.h" + +class LIBSAMPLE_API VirtualMethods +{ +public: + VirtualMethods(Str name = "VirtualMethods") : m_name(name) + { + m_left = m_top = m_right = m_bottom = 0; + } + virtual ~VirtualMethods() {} + + virtual double virtualMethod0(Point pt, int val, Complex cpx, bool b); + double callVirtualMethod0(Point pt, int val, Complex cpx, bool b) + { + return virtualMethod0(pt, val, cpx, b); + } + + // Binding modification: rename. + virtual int sum0(int a0, int a1, int a2) { return a0 + a1 + a2; } + int callSum0(int a0, int a1, int a2) { return sum0(a0, a1, a2); } + + // Binding modification: set default value for the last argument. + virtual int sum1(int a0, int a1, int a2) { return a0 + a1 + a2; } + int callSum1(int a0, int a1, int a2) { return sum1(a0, a1, a2); } + + // Binding modification: remove the last argument and set a default value for it. + virtual int sum2(int a0, int a1, int a2) { return a0 + a1 + a2; } + int callSum2(int a0, int a1, int a2) { return sum2(a0, a1, a2); } + + // Binding modification: remove the second argument. + virtual int sum3(int a0, int a1, int a2) { return a0 + a1 + a2; } + int callSum3(int a0, int a1, int a2) { return sum3(a0, a1, a2); } + + // Binding modification: remove the second argument and set its default + // value, then inject code on the binding reimplementation of the virtual + // (with a native inject-code) to sum the value of the removed + // argument to the first argument before the method is called. + virtual int sum4(int a0, int a1, int a2) { return a0 + a1 + a2; } + int callSum4(int a0, int a1, int a2) { return sum4(a0, a1, a2); } + + // Binding modification: prepend a string to the results of a Python override. + virtual Str name() { return m_name; } + Str callName() { return name(); } + + // Binding modification: code injection that calls the Python override by itself. + virtual void callMe() {} + void callCallMe() { callMe(); } + + // Passing reference to pointers. + virtual bool createStr(const char* text, Str*& ret); + bool callCreateStr(const char* text, Str*& ret) { return createStr(text, ret); } + + // Return a non-binded method + std::list callStrListToStdList(const StrList& strList) { return strListToStdList(strList); } + virtual std::list strListToStdList(const StrList& strList ) { return strList; } + + void setMargins(int left, int top, int right, int bottom) + { + m_left = left; + m_top = top; + m_right = right; + m_bottom = bottom; + } + virtual void getMargins(int* left, int* top, int* right, int* bottom) const; + void callGetMargins(int* left, int* top, int* right, int* bottom) const + { + getMargins(left, top, right, bottom); + } + + virtual int recursionOnModifiedVirtual(Str arg) const { return 0; } + int callRecursionOnModifiedVirtual(Str arg) const { return recursionOnModifiedVirtual(arg); } + +private: + Str m_name; + int m_left; + int m_top; + int m_right; + int m_bottom; +}; + +class LIBSAMPLE_API VirtualDaughter : public VirtualMethods +{ +public: + VirtualDaughter() : VirtualMethods() {} + VirtualDaughter(Str name) : VirtualMethods(name) {} +}; + +class LIBSAMPLE_API VirtualDtor +{ +public: + VirtualDtor() {} + virtual ~VirtualDtor() { dtor_called++; } + + static VirtualDtor* create() { return new VirtualDtor(); } + static int dtorCalled() { return dtor_called; } + static void resetDtorCounter() { dtor_called = 0; } + +private: + static int dtor_called; +}; + +#endif // VIRTUALMETHODS_H + diff --git a/sources/shiboken2/tests/libsample/voidholder.h b/sources/shiboken2/tests/libsample/voidholder.h new file mode 100644 index 000000000..228bbae3f --- /dev/null +++ b/sources/shiboken2/tests/libsample/voidholder.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 VOIDHOLDER_H +#define VOIDHOLDER_H + +#include "libsamplemacros.h" + +class VoidHolder +{ +public: + explicit VoidHolder(void* ptr = 0) : m_ptr(ptr) {} + ~VoidHolder() {} + inline void* voidPointer() { return m_ptr; } + inline static void* gimmeMeSomeVoidPointer() + { + static void* pointerToSomething = new VoidHolder(); + return pointerToSomething; + } +private: + void* m_ptr; +}; + +#endif // VOIDHOLDER_H + diff --git a/sources/shiboken2/tests/libsmart/CMakeLists.txt b/sources/shiboken2/tests/libsmart/CMakeLists.txt new file mode 100644 index 000000000..66c27cdae --- /dev/null +++ b/sources/shiboken2/tests/libsmart/CMakeLists.txt @@ -0,0 +1,11 @@ +project(libsmart) + +set(libsmart_SRC +smart.cpp +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +add_definitions("-DLIBSMART_BUILD") +add_library(libsmart SHARED ${libsmart_SRC}) +set_property(TARGET libsmart PROPERTY PREFIX "") + diff --git a/sources/shiboken2/tests/libsmart/libsmartmacros.h b/sources/shiboken2/tests/libsmart/libsmartmacros.h new file mode 100644 index 000000000..e4166caff --- /dev/null +++ b/sources/shiboken2/tests/libsmart/libsmartmacros.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 LIB_SMART_MACROS_H +#define LIB_SMART_MACROS_H + +#if defined _WIN32 || defined __CYGWIN__ + #if LIBSMART_BUILD + #define LIB_SMART_API __declspec(dllexport) + #else + #define LIB_SMART_API __declspec(dllimport) + #endif +#else +#if __GNUC__ >= 4 + #define LIB_SMART_API __attribute__ ((visibility("default"))) +#else + #define LIB_SMART_API +#endif +#endif + +#endif diff --git a/sources/shiboken2/tests/libsmart/smart.cpp b/sources/shiboken2/tests/libsmart/smart.cpp new file mode 100644 index 000000000..28c9cf055 --- /dev/null +++ b/sources/shiboken2/tests/libsmart/smart.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "smart.h" + +bool shouldPrint() { + return Registry::getInstance()->shouldPrint(); +} + +Obj::Obj() : m_integer(123), m_internalInteger(new Integer) +{ + Registry::getInstance()->add(this); + if (shouldPrint()) + std::cout << "Object constructor " << this << '\n'; +} + +Obj::~Obj() +{ + Registry::getInstance()->remove(this); + delete m_internalInteger; + if (shouldPrint()) + std::cout << "Object destructor " << this << '\n'; +} + + +void Obj::printObj() { + if (shouldPrint()) { + std::cout << "integer value: " << m_integer + << " internal integer value: " << m_internalInteger->m_int << '\n'; + } +} + + +SharedPtr Obj::giveSharedPtrToObj() +{ + SharedPtr o(new Obj); + return o; +} + +SharedPtr Obj::giveSharedPtrToInteger() +{ + SharedPtr o(new Integer); + return o; +} + +int Obj::takeSharedPtrToObj(SharedPtr pObj) +{ + pObj->printObj(); + return pObj->m_integer; +} + +int Obj::takeSharedPtrToInteger(SharedPtr pInt) +{ + pInt->printInteger(); + return pInt->m_int; +} + +Integer Obj::takeInteger(Integer val) +{ + return val; +} + +Integer::Integer() : m_int(456) +{ + Registry::getInstance()->add(this); + if (shouldPrint()) + std::cout << "Integer constructor " << this << '\n'; +} + +Integer::Integer(const Integer &other) +{ + Registry::getInstance()->add(this); + if (shouldPrint()) + std::cout << "Integer copy constructor " << this << '\n'; + m_int = other.m_int; +} + +Integer &Integer::operator=(const Integer &other) +{ + Registry::getInstance()->add(this); + if (shouldPrint()) + std::cout << "Integer operator= " << this << '\n'; + m_int = other.m_int; + return *this; +} + +Integer::~Integer() +{ + Registry::getInstance()->remove(this); + if (shouldPrint()) + std::cout << "Integer destructor " << this << '\n'; +} + +void Integer::printInteger() +{ + if (shouldPrint()) + std::cout << "Integer value for object " << this << " is " << m_int << '\n'; +} + +Registry *Registry::getInstance() +{ + static Registry registry; + return ®istry; +} + +Registry::Registry() : m_printStuff(false) +{ + +} + +void Registry::add(Obj *p) +{ + m_objects.push_back(p); +} + +void Registry::add(Integer *p) +{ + m_integers.push_back(p); +} + +void Registry::remove(Obj *p) +{ + m_objects.erase(std::remove(m_objects.begin(), m_objects.end(), p), m_objects.end()); +} + +void Registry::remove(Integer *p) +{ + m_integers.erase(std::remove(m_integers.begin(), m_integers.end(), p), m_integers.end()); +} + +int Registry::countObjects() const +{ + return static_cast(m_objects.size()); +} + +int Registry::countIntegers() const +{ + return static_cast(m_integers.size()); +} + +bool Registry::shouldPrint() const +{ + return m_printStuff; +} + +void Registry::setShouldPrint(bool flag) +{ + m_printStuff = flag; +} diff --git a/sources/shiboken2/tests/libsmart/smart.h b/sources/shiboken2/tests/libsmart/smart.h new file mode 100644 index 000000000..c6b0dbbca --- /dev/null +++ b/sources/shiboken2/tests/libsmart/smart.h @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 SMART_H +#define SMART_H + +#include +#include +#include + +#include "libsmartmacros.h" + +// Forward declarations. +template +class SharedPtr; +class Integer; +class Obj; + +LIB_SMART_API bool shouldPrint(); + +// Used to track which C++ objects are alive. +class LIB_SMART_API Registry { +public: + static Registry *getInstance(); + + void add(Obj *p); + void add(Integer *p); + void remove(Obj *p); + void remove(Integer *p); + int countObjects() const; + int countIntegers() const; + bool shouldPrint() const; + void setShouldPrint(bool flag); + +protected: + Registry(); + +private: + bool m_printStuff; + std::vector m_objects; + std::vector m_integers; +}; + +template +class RefData { +public: + RefData(T *ptr) : m_refCount(1), m_heldPtr(ptr) {} + ~RefData() { delete m_heldPtr; } + int inc() { return ++m_refCount; } + int dec() { return --m_refCount; } + int useCount() { return m_refCount; } + int m_refCount; + T *m_heldPtr; +}; + +template +class SharedPtr { +public: + SharedPtr() : m_refData(0) { + if (shouldPrint()) + std::cout << "shared_ptr default constructor " << this << "\n"; + } + + SharedPtr(T *v) + { + if (shouldPrint()) + std::cout << "shared_ptr constructor " << this << " with pointer " << v << "\n"; + if (v) + m_refData = new RefData(v); + } + + SharedPtr(const SharedPtr &other) : m_refData(other.m_refData) + { + if (shouldPrint()) + std::cout << "shared_ptr copy constructor " << this << " with pointer " + << other.m_refData << "\n"; + if (m_refData) + m_refData->inc(); + } + + SharedPtr &operator=(const SharedPtr& other) + { + if (this != &other) { + if (shouldPrint()) + std::cout << "shared_ptr assignment operator " << this << " with pointer " + << other.m_refData << "\n"; + if (m_refData && m_refData->dec() == 0) + delete m_refData; + m_refData = other.m_refData; + if (m_refData) + m_refData->inc(); + } + return *this; + } + + T *data() const + { + if (m_refData) + return m_refData->m_heldPtr; + return 0; + } + + int useCount() const + { + if (m_refData) + return m_refData->useCount(); + return 0; + } + + void dummyMethod1() + { + + } + + T& operator*() const + { + // Crashes if smart pointer is empty (just like std::shared_ptr). + return *(m_refData->m_heldPtr); + } + + T *operator->() const + { + if (m_refData) + return m_refData->m_heldPtr; + return 0; + } + + bool operator!() const + { + return !m_refData || !m_refData->m_heldPtr; + } + + bool isNull() const + { + return !m_refData || !m_refData->m_heldPtr; + } + + operator bool() const + { + return m_refData && m_refData->m_heldPtr; + } + + ~SharedPtr() + { + if (m_refData) { + if (shouldPrint()) + std::cout << "shared_ptr destructor " << this << " remaining refcount " + << m_refData->useCount() - 1 << "\n"; + } + if (m_refData && m_refData->dec() == 0) + delete m_refData; + } + + RefData *m_refData; +}; + +class LIB_SMART_API Integer { +public: + Integer(); + Integer(const Integer &other); + Integer &operator=(const Integer &other); + ~Integer(); + void printInteger(); + int m_int; +}; + +// Couldn't name it Object because it caused some namespace clashes. +class LIB_SMART_API Obj { +public: + Obj(); + virtual ~Obj(); + + void printObj(); + Integer takeInteger(Integer val); + SharedPtr giveSharedPtrToObj(); + SharedPtr giveSharedPtrToInteger(); + int takeSharedPtrToObj(SharedPtr pObj); + int takeSharedPtrToInteger(SharedPtr pInt); + + int m_integer; + Integer *m_internalInteger; +}; + +#endif // SMART_H + diff --git a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt new file mode 100644 index 000000000..fb0b2cc74 --- /dev/null +++ b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt @@ -0,0 +1,38 @@ +project(minimal) + +set(minimal_TYPESYSTEM +${CMAKE_CURRENT_SOURCE_DIR}/typesystem_minimal.xml +) + +set(minimal_SRC +${CMAKE_CURRENT_BINARY_DIR}/minimal/minimal_module_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/minimal/obj_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/minimal/val_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/minimal/listuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/minimal/minbooluser_wrapper.cpp +) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/minimal-binding.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt" @ONLY) + +add_custom_command(OUTPUT ${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} +COMMENT "Running generator for 'minimal' test binding..." +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR} + ${SBK_PYTHON_INCLUDE_DIR} + ${libminimal_SOURCE_DIR} + ${libshiboken_SOURCE_DIR}) +add_library(minimal MODULE ${minimal_SRC}) +set_property(TARGET minimal PROPERTY PREFIX "") +if(WIN32) + set_property(TARGET minimal PROPERTY SUFFIX ".pyd") +endif() +target_link_libraries(minimal + libminimal + ${SBK_PYTHON_LIBRARIES} + libshiboken) diff --git a/sources/shiboken2/tests/minimalbinding/global.h b/sources/shiboken2/tests/minimalbinding/global.h new file mode 100644 index 000000000..93eb38ed5 --- /dev/null +++ b/sources/shiboken2/tests/minimalbinding/global.h @@ -0,0 +1,33 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "obj.h" +#include "val.h" +#include "minbool.h" +#include "listuser.h" +#include "typedef.h" diff --git a/sources/shiboken2/tests/minimalbinding/listuser_test.py b/sources/shiboken2/tests/minimalbinding/listuser_test.py new file mode 100644 index 000000000..d3b7f01e7 --- /dev/null +++ b/sources/shiboken2/tests/minimalbinding/listuser_test.py @@ -0,0 +1,323 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 minimal import ListUser, Val, Obj +from py3kcompat import IS_PY3K + +if IS_PY3K: + import functools + reduce = functools.reduce + + +class ExtListUser(ListUser): + def __init__(self): + ListUser.__init__(self) + + def createIntList(self, num): + return list(range(0, num * 2, 2)) + + def sumIntList(self, intList): + return sum(intList) * 2 + + def createMinBoolList(self, mb1, mb2): + return [not mb1, not mb2] + + def oredMinBoolList(self, minBoolList): + return not reduce(lambda a, b: a|b, minBoolList) + + def createValList(self, num): + return [Val(i) for i in range(0, num * 2, 2)] + + def sumValList(self, valList): + return sum([val.valId() for val in valList]) * 2 + + def createObjList(self, o1, o2): + o1.setObjId(o1.objId() * 2) + o2.setObjId(o2.objId() * 2) + return [o1, o2] + + def sumObjList(self, objList): + return sum([obj.objId() for obj in objList]) * 2 + + def createListOfIntLists(self, num): + return [self.createIntList(num)] * 4 + + def sumListOfIntLists(self, intListList): + return sum([sum(line) for line in intListList]) * 2 + + +class IntListConversionTest(unittest.TestCase): + + def testCreateIntList(self): + num = 4 + lu = ListUser() + lst = lu.createIntList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), int) + self.assertEqual(lst, list(range(num))) + lst = lu.callCreateIntList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), int) + self.assertEqual(lst, list(range(num))) + + def testCreateIntListFromExtendedClass(self): + lu = ExtListUser() + num = 4 + lst = lu.createIntList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), int) + self.assertEqual(lst, list(range(0, num * 2, 2))) + lst = lu.callCreateIntList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), int) + self.assertEqual(lst, list(range(0, num * 2, 2))) + + def testSumIntList(self): + lu = ListUser() + lst = range(4) + self.assertEqual(lu.sumIntList(lst), sum(lst)) + self.assertEqual(lu.callSumIntList(lst), sum(lst)) + + def testSumIntListFromExtendedClass(self): + lu = ExtListUser() + lst = range(4) + self.assertEqual(lu.sumIntList(lst), sum(lst) * 2) + self.assertEqual(lu.callSumIntList(lst), sum(lst) * 2) + + +class MinBoolListConversionTest(unittest.TestCase): + + def testCreateMinBoolList(self): + lu = ListUser() + lst = lu.createMinBoolList(True, False) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), bool) + self.assertEqual(lst, [True, False]) + + lst = lu.callCreateMinBoolList(False, True) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), bool) + self.assertEqual(lst, [False, True]) + + def testCreateMinBoolListFromExtendedClass(self): + lu = ExtListUser() + lst = lu.createMinBoolList(True, False) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), bool) + self.assertEqual(lst, [False, True]) + + lst = lu.callCreateMinBoolList(False, True) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), bool) + self.assertEqual(lst, [True, False]) + + def testOredMinBoolList(self): + lu = ListUser() + lst = [False, False, True] + self.assertTrue(lu.oredMinBoolList(lst)) + self.assertTrue(lu.callOredMinBoolList(lst)) + lst = [False, False, False] + self.assertFalse(lu.oredMinBoolList(lst)) + self.assertFalse(lu.callOredMinBoolList(lst)) + + def testOredMinBoolListFromExtendedClass(self): + lu = ExtListUser() + lst = [False, False, True] + self.assertFalse(lu.oredMinBoolList(lst)) + self.assertFalse(lu.callOredMinBoolList(lst)) + lst = [False, False, False] + self.assertTrue(lu.oredMinBoolList(lst)) + self.assertTrue(lu.callOredMinBoolList(lst)) + + +class ValListConversionTest(unittest.TestCase): + + def testCreateValList(self): + num = 4 + lu = ListUser() + lst = lu.createValList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), Val) + self.assertEqual([val.valId() for val in lst], list(range(num))) + lst = lu.callCreateValList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), Val) + self.assertEqual([val.valId() for val in lst], list(range(num))) + + def testCreateValListFromExtendedClass(self): + lu = ExtListUser() + num = 4 + lst = lu.createValList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), Val) + self.assertEqual([val.valId() for val in lst], list(range(0, num * 2, 2))) + lst = lu.callCreateValList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), Val) + self.assertEqual([val.valId() for val in lst], list(range(0, num * 2, 2))) + + def testSumValList(self): + lu = ListUser() + lst = [Val(i) for i in range(4)] + self.assertEqual(lu.sumValList(lst), sum([val.valId() for val in lst])) + self.assertEqual(lu.callSumValList(lst), sum([val.valId() for val in lst])) + + def testSumValListFromExtendedClass(self): + lu = ExtListUser() + lst = [Val(i) for i in range(4)] + self.assertEqual(lu.sumValList(lst), sum([val.valId() for val in lst]) * 2) + self.assertEqual(lu.callSumValList(lst), sum([val.valId() for val in lst]) * 2) + + +class ObjListConversionTest(unittest.TestCase): + + def testCreateObjList(self): + o1 = Obj(1) + o2 = Obj(2) + lu = ListUser() + lst = lu.createObjList(o1, o2) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), Obj) + self.assertEqual(lst, [o1, o2]) + self.assertEqual([obj.objId() for obj in lst], [1, 2]) + + lst = lu.callCreateObjList(o1, o2) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), Obj) + self.assertEqual(lst, [o1, o2]) + self.assertEqual([obj.objId() for obj in lst], [1, 2]) + + def testCreateObjListFromExtendedClass(self): + o1 = Obj(1) + o2 = Obj(2) + lu = ExtListUser() + lst = lu.createObjList(o1, o2) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), Obj) + self.assertEqual(lst, [o1, o2]) + self.assertEqual([obj.objId() for obj in lst], [2, 4]) + + lst = lu.callCreateObjList(o1, o2) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), Obj) + self.assertEqual(lst, [o1, o2]) + self.assertEqual([obj.objId() for obj in lst], [4, 8]) + + def testSumObjList(self): + lu = ListUser() + lst = [Obj(i) for i in list(range(4))] + self.assertEqual(lu.sumObjList(lst), sum([obj.objId() for obj in lst])) + self.assertEqual(lu.callSumObjList(lst), sum([obj.objId() for obj in lst])) + + def testSumObjListFromExtendedClass(self): + lu = ExtListUser() + lst = [Obj(i) for i in list(range(4))] + self.assertEqual(lu.sumObjList(lst), sum([obj.objId() for obj in lst]) * 2) + self.assertEqual(lu.callSumObjList(lst), sum([obj.objId() for obj in lst]) * 2) + + +class ListOfIntListConversionTest(unittest.TestCase): + + def testCreateListOfIntLists(self): + num = 4 + lu = ListUser() + lst = lu.createListOfIntLists(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), list) + self.assertEqual(i, list(range(num))) + for j in i: + self.assertEqual(type(j), int) + self.assertEqual(lst, [list(range(num))] * 4) + + def testCreateListOfIntListsFromExtendedClass(self): + num = 4 + lu = ExtListUser() + lst = lu.createListOfIntLists(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), list) + self.assertEqual(i, list(range(0, num * 2, 2))) + for j in i: + self.assertEqual(type(j), int) + self.assertEqual(lst, [list(range(0, num * 2, 2))] * 4) + + def testSumListIntLists(self): + lu = ListUser() + lst = [range(4)] * 4 + self.assertEqual(lu.sumListOfIntLists(lst), sum([sum(line) for line in [range(4)] * 4])) + self.assertEqual(lu.callSumListOfIntLists(lst), sum([sum(line) for line in [range(4)] * 4])) + + def testSumListOfIntListsFromExtendedClass(self): + lu = ExtListUser() + lst = [range(4)] * 4 + self.assertEqual(lu.sumListOfIntLists(lst), sum([sum(line) for line in [range(4)] * 4]) * 2) + self.assertEqual(lu.callSumListOfIntLists(lst), sum([sum(line) for line in [range(4)] * 4]) * 2) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/minimalbinding/minbool_test.py b/sources/shiboken2/tests/minimalbinding/minbool_test.py new file mode 100644 index 000000000..b7830a79b --- /dev/null +++ b/sources/shiboken2/tests/minimalbinding/minbool_test.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 minimal import MinBoolUser + +class DerivedMinBoolUser (MinBoolUser): + def returnMyselfVirtual(self): + return MinBoolUser() + +class MinBoolTest(unittest.TestCase): + + def testMinBoolUser(self): + mbuTrue = MinBoolUser() + mbuFalse = MinBoolUser() + mbuTrue.setMinBool(True) + self.assertEqual(mbuFalse.minBool(), False) + self.assertEqual(mbuTrue.minBool(), True) + self.assertEqual(mbuTrue.callInvertedMinBool(), False) + + self.assertEqual(mbuTrue.minBool() == True, True) + self.assertEqual(False == mbuFalse.minBool(), True) + self.assertEqual(mbuTrue.minBool() == mbuFalse.minBool(), False) + + self.assertEqual(mbuFalse.minBool() != True, True) + self.assertEqual(True != mbuFalse.minBool(), True) + self.assertEqual(mbuTrue.minBool() != mbuFalse.minBool(), True) + + def testVirtuals(self): + dmbu = DerivedMinBoolUser() + self.assertEqual(dmbu.invertedMinBool(), True) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/minimalbinding/minimal-binding.txt.in b/sources/shiboken2/tests/minimalbinding/minimal-binding.txt.in new file mode 100644 index 000000000..85b139676 --- /dev/null +++ b/sources/shiboken2/tests/minimalbinding/minimal-binding.txt.in @@ -0,0 +1,15 @@ +[generator-project] + +generator-set = shiboken + +header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h +typesystem-file = @minimal_TYPESYSTEM@ + +output-directory = @CMAKE_CURRENT_BINARY_DIR@ + +include-path = @libminimal_SOURCE_DIR@ + +typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@ + +enable-parent-ctor-heuristic +use-isnull-as-nb_nonzero diff --git a/sources/shiboken2/tests/minimalbinding/obj_test.py b/sources/shiboken2/tests/minimalbinding/obj_test.py new file mode 100644 index 000000000..bf00f1c92 --- /dev/null +++ b/sources/shiboken2/tests/minimalbinding/obj_test.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 minimal import Obj + +class ExtObj(Obj): + def __init__(self, objId): + Obj.__init__(self, objId) + self.virtual_method_called = False + + def virtualMethod(self, val): + self.virtual_method_called = True + return not Obj.virtualMethod(self, val) + + def passObjectType(self, obj): + obj.setObjId(obj.objId() + 1) + return obj + + def passObjectTypeReference(self, obj): + obj.setObjId(obj.objId() + 1) + return obj + + +class ObjTest(unittest.TestCase): + + def testNormalMethod(self): + objId = 123 + obj = Obj(objId) + self.assertEqual(obj.objId(), objId) + + def testNormalMethodFromExtendedClass(self): + objId = 123 + obj = ExtObj(objId) + self.assertEqual(obj.objId(), objId) + + def testVirtualMethod(self): + obj = Obj(0) + even_number = 8 + self.assertEqual(obj.virtualMethod(even_number), obj.callVirtualMethod(even_number)) + + def testVirtualMethodFromExtendedClass(self): + obj = ExtObj(0) + even_number = 8 + self.assertEqual(obj.virtualMethod(even_number), obj.callVirtualMethod(even_number)) + self.assertTrue(obj.virtual_method_called) + + def testPassObjectType(self): + obj = Obj(0) + self.assertEqual(obj, obj.passObjectType(obj)) + self.assertEqual(obj, obj.callPassObjectType(obj)) + + def testPassObjectTypeNone(self): + obj = Obj(0) + self.assertEqual(None, obj.passObjectType(None)) + self.assertEqual(None, obj.callPassObjectType(None)) + + def testPassObjectTypeReference(self): + obj = Obj(0) + self.assertEqual(obj, obj.passObjectTypeReference(obj)) + self.assertEqual(obj, obj.callPassObjectTypeReference(obj)) + + def testPassObjectTypeFromExtendedClass(self): + obj = ExtObj(0) + self.assertEqual(obj.objId(), 0) + sameObj = obj.passObjectType(obj) + self.assertEqual(obj, sameObj) + self.assertEqual(sameObj.objId(), 1) + sameObj = obj.callPassObjectType(obj) + self.assertEqual(obj, sameObj) + self.assertEqual(sameObj.objId(), 2) + + def testPassObjectTypeReferenceFromExtendedClass(self): + obj = ExtObj(0) + self.assertEqual(obj.objId(), 0) + sameObj = obj.passObjectTypeReference(obj) + self.assertEqual(obj, sameObj) + self.assertEqual(sameObj.objId(), 1) + sameObj = obj.callPassObjectTypeReference(obj) + self.assertEqual(obj, sameObj) + self.assertEqual(sameObj.objId(), 2) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/minimalbinding/typedef_test.py b/sources/shiboken2/tests/minimalbinding/typedef_test.py new file mode 100644 index 000000000..62df9cbea --- /dev/null +++ b/sources/shiboken2/tests/minimalbinding/typedef_test.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 minimal import * +from py3kcompat import IS_PY3K + +try: + import numpy as np +except ImportError as e: + print(e) + np = None + + +if IS_PY3K: + import functools + reduce = functools.reduce + + +class TypedefTest(unittest.TestCase): + + def setUp(self): + self.the_size = 8 + + def test_arrayFuncInt(self): + none = () + full = range(self.the_size) + self.assertTrue(arrayFuncInt(none), "None is empty, arrayFuncInt should return true") + self.assertFalse(arrayFuncInt(full), "Full is NOT empty, arrayFuncInt should return false") + + self.assertTrue(arrayFuncInt(np.array(none)), "None is empty, arrayFuncInt should return true") + self.assertFalse(arrayFuncInt(np.array(full)), "Full is NOT empty, arrayFuncInt should return false") + + def test_arrayFuncIntTypedef(self): + none = () + full = (1, 2, 3) + self.assertTrue(arrayFuncIntTypedef(none), "None is empty, arrayFuncIntTypedef should return true") + self.assertFalse(arrayFuncIntTypedef(full), "Full is NOT empty, arrayFuncIntTypedef should return false") + + self.assertTrue(arrayFuncIntTypedef(np.array(none)), "None is empty, arrayFuncIntTypedef should return true") + self.assertFalse(arrayFuncIntTypedef(np.array(full)), "Full is NOT empty, arrayFuncIntTypedef should return false") + + def test_arrayFuncIntReturn(self): + none = arrayFuncIntReturn(0) + full = arrayFuncIntReturn(self.the_size) + self.assertTrue((len(none) == 0), "none should be empty") + self.assertTrue((len(full) == self.the_size), "full should have " + str(self.the_size) + " elements") + + def test_arrayFuncIntReturnTypedef(self): + none = arrayFuncIntReturnTypedef(0) + full = arrayFuncIntReturnTypedef(self.the_size) + self.assertTrue((len(none) == 0), "none should be empty") + self.assertTrue((len(full) == self.the_size), "full should have " + str(self.the_size) + " elements") + + def test_arrayFunc(self): + none = () + full = range(self.the_size) + self.assertTrue(arrayFunc(none), "None is empty, arrayFunc should return true") + self.assertFalse(arrayFunc(full), "Full is NOT empty, arrayFunc should return false") + + self.assertTrue(arrayFunc(np.array(none)), "None is empty, arrayFunc should return true") + self.assertFalse(arrayFunc(np.array(full)), "Full is NOT empty, arrayFunc should return false") + + def test_arrayFuncTypedef(self): + none = () + full = (1, 2, 3) + self.assertTrue(arrayFuncTypedef(none), "None is empty, arrayFuncTypedef should return true") + self.assertFalse(arrayFuncTypedef(full), "Full is NOT empty, arrayFuncTypedef should return false") + + self.assertTrue(arrayFuncTypedef(np.array(none)), "None is empty, arrayFuncTypedef should return true") + self.assertFalse(arrayFuncTypedef(np.array(full)), "Full is NOT empty, arrayFuncTypedef should return false") + + def test_arrayFuncReturn(self): + none = arrayFuncReturn(0) + full = arrayFuncReturn(self.the_size) + self.assertTrue((len(none) == 0), "none should be empty") + self.assertTrue((len(full) == self.the_size), "full should have " + str(self.the_size) + " elements") + + def test_arrayFuncReturnTypedef(self): + none = arrayFuncReturnTypedef(0) + full = arrayFuncReturnTypedef(self.the_size) + self.assertTrue((len(none) == 0), "none should be empty") + self.assertTrue((len(full) == self.the_size), "full should have " + str(self.the_size) + " elements") + + +if __name__ == '__main__': + if np != None: + unittest.main() diff --git a/sources/shiboken2/tests/minimalbinding/typesystem_minimal.xml b/sources/shiboken2/tests/minimalbinding/typesystem_minimal.xml new file mode 100644 index 000000000..968b27c53 --- /dev/null +++ b/sources/shiboken2/tests/minimalbinding/typesystem_minimal.xml @@ -0,0 +1,93 @@ + + + + + + + + + + return PyBool_FromLong(%in.value()); + + + + %out = %OUTTYPE(%in == Py_True); + + + + + + + + + + PyObject* %out = PyList_New((int) %in.size()); + %INTYPE::const_iterator it = %in.begin(); + for (int idx = 0; it != %in.end(); ++it, ++idx) { + %INTYPE_0 cppItem(*it); + PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem)); + } + return %out; + + + + Shiboken::AutoDecRef seq(PySequence_Fast(%in, 0)); + for (int i = 0; i < PySequence_Fast_GET_SIZE(seq.object()); i++) { + PyObject* pyItem = PySequence_Fast_GET_ITEM(seq.object(), i); + %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem); + %out.push_back(cppItem); + } + + + + + + + + + + + + + + + + + %INTYPE::size_type vectorSize = %in.size(); + PyObject* %out = PyList_New((int) vectorSize); + for (%INTYPE::size_type idx = 0; idx < vectorSize; ++idx) { + %INTYPE_0 cppItem(%in[idx]); + PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem)); + } + return %out; + + + + Shiboken::AutoDecRef seq(PySequence_Fast(%in, 0)); + int vectorSize = PySequence_Fast_GET_SIZE(seq.object()); + %out.reserve(vectorSize); + for (int idx = 0; idx < vectorSize; ++idx ) { + PyObject* pyItem = PySequence_Fast_GET_ITEM(seq.object(), idx); + %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem); + %out.push_back(cppItem); + } + + + + + + + + + + + + + + + + + + + + diff --git a/sources/shiboken2/tests/minimalbinding/val_test.py b/sources/shiboken2/tests/minimalbinding/val_test.py new file mode 100644 index 000000000..97e4e4778 --- /dev/null +++ b/sources/shiboken2/tests/minimalbinding/val_test.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 minimal import Val + + +class ExtVal(Val): + def __init__(self, valId): + Val.__init__(self, valId) + + def passValueType(self, val): + return ExtVal(val.valId() + 1) + + def passValueTypePointer(self, val): + val.setValId(val.valId() + 1) + return val + + def passValueTypeReference(self, val): + val.setValId(val.valId() + 1) + return val + + +class ValTest(unittest.TestCase): + + def testNormalMethod(self): + valId = 123 + val = Val(valId) + self.assertEqual(val.valId(), valId) + + def testPassValueType(self): + val = Val(123) + val1 = val.passValueType(val) + self.assertNotEqual(val, val1) + self.assertEqual(val1.valId(), 123) + val2 = val.callPassValueType(val) + self.assertNotEqual(val, val2) + self.assertEqual(val2.valId(), 123) + + def testPassValueTypePointer(self): + val = Val(0) + self.assertEqual(val, val.passValueTypePointer(val)) + self.assertEqual(val, val.callPassValueTypePointer(val)) + + def testPassValueTypeReference(self): + val = Val(0) + self.assertEqual(val, val.passValueTypeReference(val)) + self.assertEqual(val, val.callPassValueTypeReference(val)) + + def testPassAndReceiveEnumValue(self): + val = Val(0) + self.assertEqual(val.oneOrTheOtherEnumValue(Val.One), Val.Other) + self.assertEqual(val.oneOrTheOtherEnumValue(Val.Other), Val.One) + + def testPassValueTypeFromExtendedClass(self): + val = ExtVal(0) + val1 = val.passValueType(val) + self.assertNotEqual(val, val1) + self.assertEqual(val1.valId(), val.valId() + 1) + val2 = val.callPassValueType(val) + self.assertNotEqual(val, val2) + self.assertEqual(val2.valId(), val.valId() + 1) + + def testPassValueTypePointerFromExtendedClass(self): + val = ExtVal(0) + self.assertEqual(val.valId(), 0) + sameVal = val.passValueTypePointer(val) + self.assertEqual(val, sameVal) + self.assertEqual(sameVal.valId(), 1) + sameVal = val.callPassValueTypePointer(val) + self.assertEqual(val, sameVal) + self.assertEqual(sameVal.valId(), 2) + + def testPassValueTypeReferenceFromExtendedClass(self): + val = ExtVal(0) + self.assertEqual(val.valId(), 0) + sameVal = val.passValueTypeReference(val) + self.assertEqual(val, sameVal) + self.assertEqual(sameVal.valId(), 1) + sameVal = val.callPassValueTypeReference(val) + self.assertEqual(val, sameVal) + self.assertEqual(sameVal.valId(), 2) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/otherbinding/CMakeLists.txt b/sources/shiboken2/tests/otherbinding/CMakeLists.txt new file mode 100644 index 000000000..ac7178e5d --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/CMakeLists.txt @@ -0,0 +1,48 @@ +project(other) + +set(other_TYPESYSTEM +${CMAKE_CURRENT_SOURCE_DIR}/typesystem_other.xml +) + +set(other_SRC +${CMAKE_CURRENT_BINARY_DIR}/other/extendsnoimplicitconversion_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/number_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/otherderived_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/othermultiplederived_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/otherobjecttype_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/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} +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} +COMMENT "Running generator for 'other' test binding..." +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR} + ${SBK_PYTHON_INCLUDE_DIR} + ${libother_SOURCE_DIR} + ${libsample_SOURCE_DIR} + ${libsample_SOURCE_DIR}/.. + ${sample_BINARY_DIR} + ${sample_BINARY_DIR}/sample + ${libshiboken_SOURCE_DIR}) +add_library(other MODULE ${other_SRC}) +set_property(TARGET other PROPERTY PREFIX "") +if(WIN32) + set_property(TARGET other PROPERTY SUFFIX ".pyd") +endif() +target_link_libraries(other + libother + libsample + ${SBK_PYTHON_LIBRARIES} + libshiboken) + +add_dependencies(other sample) + diff --git a/sources/shiboken2/tests/otherbinding/collector_external_operator_test.py b/sources/shiboken2/tests/otherbinding/collector_external_operator_test.py new file mode 100644 index 000000000..328aec837 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/collector_external_operator_test.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Collector shift operators defined in other modules.''' + +import unittest + +from sample import Collector, ObjectType +from other import OtherObjectType + +class CollectorOtherObjectType(unittest.TestCase): + '''Test cases for Collector << OtherObjectType''' + + def testLShiftWithExpectedType(self): + '''Collector << ObjectType # libsample << operator''' + collector = Collector() + obj = ObjectType() + collector << obj + self.assertEqual(collector.items()[0], obj.identifier()) + + def testOtherReversal(self): + '''Collector << OtherObjectType # libother << operator''' + collector = Collector() + obj = OtherObjectType() + collector << obj + self.assertEqual(collector.items()[0], obj.identifier() * 2) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py b/sources/shiboken2/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py new file mode 100755 index 000000000..5c3733dc2 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests calling NoImplicitConversion using a ExtendsNoImplicitConversion parameter, + being that the latter defines a new conversion operator for the former, and this one + has no implicit conversions.''' + +import unittest + +from sample import NoImplicitConversion +from other import ExtendsNoImplicitConversion + +class ConversionOperatorForClassWithoutImplicitConversionsTest(unittest.TestCase): + '''Tests calling NoImplicitConversion constructor using a ExtendsNoImplicitConversion parameter.''' + + def testNoImplicitConversion(self): + '''Basic test to see if the NoImplicitConversion is Ok.''' + obj = NoImplicitConversion(123) + # NoImplicitConversion.receivesNoImplicitConversionByValue(NoImplicitConversion) + self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByValue(obj)) + # NoImplicitConversion.receivesNoImplicitConversionByPointer(NoImplicitConversion*) + self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByPointer(obj)) + # NoImplicitConversion.receivesNoImplicitConversionByReference(NoImplicitConversion&) + self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByReference(obj)) + + def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByValue(self): + '''Gives an ExtendsNoImplicitConversion object to a function expecting a NoImplicitConversion, passing by value.''' + obj = ExtendsNoImplicitConversion(123) + self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByValue(obj)) + + def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByReference(self): + '''Gives an ExtendsNoImplicitConversion object to a function expecting a NoImplicitConversion, passing by reference.''' + obj = ExtendsNoImplicitConversion(123) + self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByReference(obj)) + + def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByPointer(self): + '''Gives an ExtendsNoImplicitConversion object to a function expecting a NoImplicitConversion, passing by pointer. + This should not be accepted, since pointers should not be converted.''' + obj = ExtendsNoImplicitConversion(123) + self.assertRaises(TypeError, NoImplicitConversion.receivesNoImplicitConversionByPointer, obj) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/otherbinding/extended_multiply_operator_test.py b/sources/shiboken2/tests/otherbinding/extended_multiply_operator_test.py new file mode 100755 index 000000000..4acc53024 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/extended_multiply_operator_test.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 libsample's Point multiply operator defined in libother module.''' + +import unittest + +from sample import Point +from other import Number + +class PointOperationsWithNumber(unittest.TestCase): + '''Test cases for libsample's Point multiply operator defined in libother module.''' + + def testPointTimesInt(self): + '''sample.Point * int''' + pt1 = Point(2, 7) + num = 3 + pt2 = Point(pt1.x() * num, pt1.y() * num) + self.assertEqual(pt1 * num, pt2) + + def testIntTimesPoint(self): + '''int * sample.Point''' + pt1 = Point(2, 7) + num = 3 + pt2 = Point(pt1.x() * num, pt1.y() * num) + self.assertEqual(num * pt1, pt2) + + def testPointTimesNumber(self): + '''sample.Point * other.Number''' + pt = Point(2, 7) + num = Number(11) + self.assertEqual(pt * num, pt * 11) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/otherbinding/global.h b/sources/shiboken2/tests/otherbinding/global.h new file mode 100644 index 000000000..cc6634ab4 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/global.h @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "../samplebinding/global.h" +#include "extendsnoimplicitconversion.h" +#include "number.h" +#include "otherderived.h" +#include "otherobjecttype.h" +#include "othermultiplederived.h" + diff --git a/sources/shiboken2/tests/otherbinding/module_reload_test.py b/sources/shiboken2/tests/otherbinding/module_reload_test.py new file mode 100644 index 000000000..0f601d1a3 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/module_reload_test.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 os +import sys +import shutil +import unittest + +from py3kcompat import IS_PY3K + +if IS_PY3K: + from imp import reload + +orig_path = os.path.join(os.path.dirname(__file__)) +workdir = os.getcwd() +src = os.path.join(orig_path, 'test_module_template.py') +dst = os.path.join(workdir, 'test_module.py') +shutil.copyfile(src, dst) +sys.path.append(workdir) + +class TestModuleReloading(unittest.TestCase): + + def testModuleReloading(self): + '''Test module reloading with on-the-fly modifications.''' + import test_module + for i in range(3): + oldObject = test_module.obj + self.assertTrue(oldObject is test_module.obj) + reload(test_module) + self.assertFalse(oldObject is test_module.obj) + +if __name__ == "__main__": + unittest.main() diff --git a/sources/shiboken2/tests/otherbinding/new_ctor_operator_test.py b/sources/shiboken2/tests/otherbinding/new_ctor_operator_test.py new file mode 100755 index 000000000..634106cea --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/new_ctor_operator_test.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests calling Str constructor using a Number parameter, being that number defines a cast operator to Str.''' + +import unittest + +from sample import Str +from other import Number + +class NewCtorOperatorTest(unittest.TestCase): + '''Tests calling Str constructor using a Number parameter, being that number defines a cast operator to Str.''' + + def testNumber(self): + '''Basic test to see if the Number class is Ok.''' + value = 123 + num = Number(value) + self.assertEqual(num.value(), value) + + def testStrCtorWithNumberArgument(self): + '''Try to build a Str from 'sample' module with a Number argument from 'other' module.''' + value = 123 + num = Number(value) + string = Str(num) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/otherbinding/objtypehashes_test.py b/sources/shiboken2/tests/otherbinding/objtypehashes_test.py new file mode 100644 index 000000000..753aec1a1 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/objtypehashes_test.py @@ -0,0 +1,53 @@ +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 * +from other import * +import shiboken2 as shiboken + +class TestHashFuncs (unittest.TestCase): + + def testIt(self): + obj1 = HandleHolder() + obj2 = HandleHolder() + + hash1 = hash(obj1) + hash2 = hash(obj2) + self.assertNotEqual(hash1, hash2) + + # Now invalidate the object and test its hash. It shouldn't segfault. + shiboken.invalidate(obj1) + + hash1_2 = hash(obj1) + self.assertEqual(hash1_2, hash1) + + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/otherbinding/other-binding.txt.in b/sources/shiboken2/tests/otherbinding/other-binding.txt.in new file mode 100644 index 000000000..a17b70fc1 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/other-binding.txt.in @@ -0,0 +1,18 @@ +[generator-project] + +generator-set = shiboken + +header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h +typesystem-file = @other_TYPESYSTEM@ + +output-directory = @CMAKE_CURRENT_BINARY_DIR@ + +include-path = @libother_SOURCE_DIR@ +include-path = @libsample_SOURCE_DIR@ +include-path = @libsample_SOURCE_DIR@/.. + +typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@ +typesystem-path = @sample_SOURCE_DIR@ + +enable-parent-ctor-heuristic + diff --git a/sources/shiboken2/tests/otherbinding/otherderived_test.py b/sources/shiboken2/tests/otherbinding/otherderived_test.py new file mode 100644 index 000000000..f6906c88a --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/otherderived_test.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 OtherDerived class''' + +import sys +import unittest + +from sample import Abstract, Derived +from other import OtherDerived, Number + +class Multiple(Derived, Number): + def __init__(self): + Derived.__init__(self, 42) + Number.__init__(self, 42) + + def testCall(self): + return True + +class OtherDeviant(OtherDerived): + def __init__(self): + OtherDerived.__init__(self) + self.pure_virtual_called = False + self.unpure_virtual_called = False + + def pureVirtual(self): + self.pure_virtual_called = True + + def unpureVirtual(self): + self.unpure_virtual_called = True + + def className(self): + return 'OtherDeviant' + +class MultipleTest(unittest.TestCase): + '''Test case for Multiple derived class''' + + def testConstructor(self): + o = Multiple() + self.assertTrue(isinstance(o, Multiple)) + self.assertTrue(isinstance(o, Number)) + self.assertTrue(isinstance(o, Derived)) + del o + + def testMethodCall(self): + o = Multiple() + self.assertTrue(o.id_(), 42) + self.assertTrue(o.value(), 42) + self.assertTrue(o.testCall()) + +class OtherDerivedTest(unittest.TestCase): + '''Test case for OtherDerived class''' + + def testParentClassMethodsAvailability(self): + '''Test if OtherDerived class really inherits its methods from parent.''' + inherited_methods = set(['callPureVirtual', 'callUnpureVirtual', + 'id_', 'pureVirtual', 'unpureVirtual']) + self.assertTrue(inherited_methods.issubset(dir(OtherDerived))) + + def testReimplementedPureVirtualMethodCall(self): + '''Test if a Python override of a implemented pure virtual method is correctly called from C++.''' + d = OtherDeviant() + d.callPureVirtual() + self.assertTrue(d.pure_virtual_called) + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a reimplemented virtual method is correctly called from C++.''' + d = OtherDeviant() + d.callUnpureVirtual() + self.assertTrue(d.unpure_virtual_called) + + def testVirtualMethodCallString(self): + '''Test virtual method call returning string.''' + d = OtherDerived() + self.assertEqual(d.className(), 'OtherDerived') + self.assertEqual(d.getClassName(), 'OtherDerived') + + def testReimplementedVirtualMethodCallReturningString(self): + '''Test if a Python override of a reimplemented virtual method is correctly called from C++.''' + d = OtherDeviant() + self.assertEqual(d.className(), 'OtherDeviant') + self.assertEqual(d.getClassName(), 'OtherDeviant') + + def testCallToMethodWithAbstractArgument(self): + '''Call to method that expects an Abstract argument.''' + objId = 123 + d = OtherDerived(objId) + self.assertEqual(Abstract.getObjectId(d), objId) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/otherbinding/test_module_template.py b/sources/shiboken2/tests/otherbinding/test_module_template.py new file mode 100644 index 000000000..ddde85c2e --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/test_module_template.py @@ -0,0 +1,40 @@ +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +from other import * +from sample import * + + +class MyObjectType(ObjectType): + pass + +class MyOtherObjectType(OtherObjectType): + value = 10 + + +obj = MyObjectType() diff --git a/sources/shiboken2/tests/otherbinding/typediscovery_test.py b/sources/shiboken2/tests/otherbinding/typediscovery_test.py new file mode 100644 index 000000000..507c5be94 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/typediscovery_test.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 type discovery''' + +import unittest + +from sample import Abstract, Base1, Derived, MDerived1, MDerived3, SonOfMDerived1 +from other import OtherMultipleDerived + +class TypeDiscoveryTest(unittest.TestCase): + + def testPureVirtualsOfImpossibleTypeDiscovery(self): + a = Derived.triggerImpossibleTypeDiscovery() + self.assertEqual(type(a), Abstract) + # call some pure virtual method + a.pureVirtual() + + def testAnotherImpossibleTypeDiscovery(self): + a = Derived.triggerAnotherImpossibleTypeDiscovery() + self.assertEqual(type(a), Derived) + + def testMultipleInheritance(self): + obj = OtherMultipleDerived.createObject("Base1"); + self.assertEqual(type(obj), Base1) + obj = OtherMultipleDerived.createObject("MDerived1"); + self.assertEqual(type(obj), MDerived1) + obj = OtherMultipleDerived.createObject("SonOfMDerived1"); + self.assertEqual(type(obj), SonOfMDerived1) + obj = OtherMultipleDerived.createObject("MDerived3"); + self.assertEqual(type(obj), MDerived3) + obj = OtherMultipleDerived.createObject("OtherMultipleDerived"); + self.assertEqual(type(obj), OtherMultipleDerived) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/otherbinding/typesystem_other.xml b/sources/shiboken2/tests/otherbinding/typesystem_other.xml new file mode 100644 index 000000000..63ccdd518 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/typesystem_other.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/sources/shiboken2/tests/otherbinding/usersprimitivefromothermodule_test.py b/sources/shiboken2/tests/otherbinding/usersprimitivefromothermodule_test.py new file mode 100755 index 000000000..06cfce371 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/usersprimitivefromothermodule_test.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests user defined primitive type from a required module.''' + +import unittest +from other import Number + +class UserDefinedPrimitiveTypeFromRequiredModuleTest(unittest.TestCase): + + def testUsersPrimitiveFromRequiredModuleAsArgument(self): + '''static Number Number::fromComplex(Complex)''' + cpx = complex(3.0, 1.2) + number = Number.fromComplex(cpx) + self.assertEqual(number.value(), int(cpx.real)) + + def testUsersPrimitiveFromRequiredModuleAsReturnValue(self): + '''Complex Number::toComplex()''' + number = Number(12) + cpx = number.toComplex() + self.assertEqual(number.value(), int(cpx.real)) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/otherbinding/wrongctor_test.py b/sources/shiboken2/tests/otherbinding/wrongctor_test.py new file mode 100644 index 000000000..61317fe66 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/wrongctor_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 * +from other import * + +class Foo(OtherDerived): + def __init__(self): + Abstract.__init__(self, 2) # this should raise an exception + +class Foo2(ObjectType, OtherDerived): + def __init__(self): + ObjectType.__init__(self) + Abstract.__init__(self, 2) # this should raise an exception + + +class WrongCtorTest(unittest.TestCase): + def testIt(self): + self.assertRaises(TypeError, Foo) + self.assertRaises(TypeError, Foo2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/py3k.py b/sources/shiboken2/tests/py3k.py new file mode 100644 index 000000000..5f2961a6a --- /dev/null +++ b/sources/shiboken2/tests/py3k.py @@ -0,0 +1,2 @@ +def printToFile(f, str): + print(str, file=f) diff --git a/sources/shiboken2/tests/py3kcompat.py b/sources/shiboken2/tests/py3kcompat.py new file mode 100644 index 000000000..45550efb3 --- /dev/null +++ b/sources/shiboken2/tests/py3kcompat.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 sys + +IS_PY3K = sys.version_info[0] == 3 + +if IS_PY3K: + def unicode(s): + return s + + def b(s): + return bytes(s, "UTF8") + + def l(n): + return n + + long = int +else: + def b(s): + return s + + def l(n): + return long(n) + + unicode = unicode + long = long diff --git a/sources/shiboken2/tests/samplebinding/CMakeLists.txt b/sources/shiboken2/tests/samplebinding/CMakeLists.txt new file mode 100644 index 000000000..f897712f4 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/CMakeLists.txt @@ -0,0 +1,145 @@ +project(sample) + +set(sample_TYPESYSTEM +${CMAKE_CURRENT_SOURCE_DIR}/typesystem_sample.xml +) + +set(sample_SRC +${CMAKE_CURRENT_BINARY_DIR}/sample/abstractmodifications_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/abstract_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base1_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base3_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base4_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base5_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base6_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/blackbox_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/bytearray_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/bucket_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/classwithfunctionpointer_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/collector_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/color_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/ctorconvrule_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/cvlistuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/cvvaluetype_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sbkdate_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/derived_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/derived_someinnerclass_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/echo_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/event_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/expression_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/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/intlist_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sortedoverload_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/intwrapper_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/injectcode_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/listuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mapuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived1_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived3_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived4_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived5_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/modelindex_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/modifications_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/modifiedconstructor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/noimplicitconversion_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/nondefaultctor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objectmodel_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttype_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypebyvalue_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypeholder_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypederived_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypelayout_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypeptrlist_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypeoperators_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objectview_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objtypereference_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/oddbooluser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/onlycopy_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/otherbase_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/overload_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/overload2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pairuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pen_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/persistentmodelindex_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/photon_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/photon_base_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueidentity_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueduplicator_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/point_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointerholder_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointf_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointvaluelist_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/polygon_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/primitivestructpointerholder_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/privatector_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/privatedtor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedenumclass_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectednonpolymorphic_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedpolymorphic_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedpolymorphicdaughter_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedpolymorphicgranddaughter_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedproperty_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedvirtualdestructor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/rect_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/rectf_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/reference_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/referentmodelindex_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sample_module_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sample_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sample_sample_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someinnerclass_okthisisrecursiveenough_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someinnerclass_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someotherinnerclass_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_derivedfromnamespace_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/simplefile_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/size_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sizef_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sonofmderived1_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/str_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/strlist_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/time_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/templateptr_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/unremovednamespace_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/virtualdaughter_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/virtualdtor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/virtualmethods_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/voidholder_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/valueandvirtual_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/filter_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/data_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/intersection_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/union_wrapper.cpp +) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sample-binding.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt" @ONLY) + +add_custom_command(OUTPUT ${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} +COMMENT "Running generator for 'sample' test binding..." +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR} + ${SBK_PYTHON_INCLUDE_DIR} + ${libsample_SOURCE_DIR} + ${libshiboken_SOURCE_DIR}) +add_library(sample MODULE ${sample_SRC}) +set_property(TARGET sample PROPERTY PREFIX "") +if(WIN32) + set_property(TARGET sample PROPERTY SUFFIX ".pyd") +endif() +target_link_libraries(sample + libsample + ${SBK_PYTHON_LIBRARIES} + libshiboken) diff --git a/sources/shiboken2/tests/samplebinding/__del___test.py b/sources/shiboken2/tests/samplebinding/__del___test.py new file mode 100644 index 000000000..fd787b5f0 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/__del___test.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 +import sample + +delCalled = False + +class MyObject(sample.ObjectType): + def __del__(self): + global delCalled + delCalled = True + +class TestDel(unittest.TestCase): + def testIt(self): + a = MyObject() + del a + self.assertTrue(delCalled) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/abstract_test.py b/sources/shiboken2/tests/samplebinding/abstract_test.py new file mode 100644 index 000000000..46aad3260 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/abstract_test.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Abstract class''' + +import sys +import unittest + +from sample import Abstract + +class Incomplete(Abstract): + def __init__(self): + Abstract.__init__(self) + +class Concrete(Abstract): + def __init__(self): + Abstract.__init__(self) + self.pure_virtual_called = False + self.unpure_virtual_called = False + + def pureVirtual(self): + self.pure_virtual_called = True + + def pureVirtualReturningVoidPtr(self): + return 42 + + def unpureVirtual(self): + self.unpure_virtual_called = True + + def virtualGettingAEnum(self, enum): + self.virtual_getting_enum = True + + +class AbstractTest(unittest.TestCase): + '''Test case for Abstract class''' + + def testAbstractPureVirtualMethodAvailability(self): + '''Test if Abstract class pure virtual method was properly wrapped.''' + self.assertTrue('pureVirtual' in dir(Abstract)) + + def testAbstractInstanciation(self): + '''Test if instanciation of an abstract class raises the correct exception.''' + self.assertRaises(NotImplementedError, Abstract) + + def testUnimplementedPureVirtualMethodCall(self): + '''Test if calling a pure virtual method raises the correct exception.''' + i = Incomplete() + self.assertRaises(NotImplementedError, i.pureVirtual) + + def testPureVirtualReturningVoidPtrReturnValue(self): + '''Test if a pure virtual method returning void ptr can be properly reimplemented''' + # Note that the semantics of reimplementing the pure virtual method in + # Python and calling it from C++ is undefined until it's decided how to + # cast the Python data types to void pointers + c = Concrete() + self.assertEqual(c.pureVirtualReturningVoidPtr(),42) + + def testReimplementedVirtualMethodCall(self): + '''Test if instanciation of an abstract class raises the correct exception.''' + i = Concrete() + self.assertRaises(NotImplementedError, i.callPureVirtual) + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a virtual method is correctly called from C++.''' + c = Concrete() + c.callUnpureVirtual() + self.assertTrue(c.unpure_virtual_called) + + def testImplementedPureVirtualMethodCall(self): + '''Test if a Python override of a pure virtual method is correctly called from C++.''' + c = Concrete() + c.callPureVirtual() + self.assertTrue(c.pure_virtual_called) + + def testEnumParameterOnVirtualMethodCall(self): + '''testEnumParameterOnVirtualMethodCall''' + c = Concrete() + c.callVirtualGettingEnum(Abstract.Short) + self.assertTrue(c.virtual_getting_enum) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/addedfunction_test.py b/sources/shiboken2/tests/samplebinding/addedfunction_test.py new file mode 100644 index 000000000..1620a5114 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/addedfunction_test.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 added functions.''' + +import unittest +from sample import SampleNamespace, ObjectType, Point + +class TestAddedFunctionsWithSimilarTypes(unittest.TestCase): + '''Adds new signatures very similar to already existing ones.''' + + def testValueTypeReferenceAndValue(self): + '''In C++ we have "function(const ValueType&, double)", + in Python we add "function(ValueType)".''' + point = Point(10, 20) + multiplier = 4.0 + control = (point.x() + point.y()) * multiplier + self.assertEqual(SampleNamespace.passReferenceToValueType(point, multiplier), control) + control = point.x() + point.y() + self.assertEqual(SampleNamespace.passReferenceToValueType(point), control) + + def testObjectTypeReferenceAndPointer(self): + '''In C++ we have "function(const ObjectType&, int)", + in Python we add "function(ValueType)".''' + obj = ObjectType() + obj.setObjectName('sbrubbles') + multiplier = 3.0 + control = len(obj.objectName()) * multiplier + self.assertEqual(SampleNamespace.passReferenceToObjectType(obj, multiplier), control) + control = len(obj.objectName()) + self.assertEqual(SampleNamespace.passReferenceToObjectType(obj), control) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/addedfunction_with_container_args_test.py b/sources/shiboken2/tests/samplebinding/addedfunction_with_container_args_test.py new file mode 100644 index 000000000..da2406698 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/addedfunction_with_container_args_test.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 added functions with nested and multi-argument container types.''' + +import unittest +from sample import sum2d, sumproduct + +class TestAddedFunctionsWithContainerArgs(unittest.TestCase): + '''Tests added functions with nested and multi-argument container types.''' + + def testNestedContainerType(self): + '''Test added function with single-argument containers.''' + values = [[1,2],[3,4,5],[6]] + self.assertEqual(sum2d(values), 21) + + def testMultiArgContainerType(self): + '''Test added function with a two-argument container.''' + values = [(1,2),(3,4),(5,6)] + self.assertEqual(sumproduct(values), 44) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/argumentmodifications_test.py b/sources/shiboken2/tests/samplebinding/argumentmodifications_test.py new file mode 100644 index 000000000..90db99f91 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/argumentmodifications_test.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 method arguments modifications performed as described on typesystem.''' + +import sys +import unittest + +from sample import Modifications, Point + +class ArgumentModificationsTest(unittest.TestCase): + '''Test cases for method arguments modifications performed as described on typesystem.''' + + def setUp(self): + self.mods = Modifications() + + def tearDown(self): + del self.mods + + def testArgRemoval0(self): + '''Tests argument removal modifications on Modifications.argRemoval0.''' + # void [-> PyObject*] argRemoval0(int, bool, int = 123 [removed, new val = 321], int = 456) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = 1, True, 2 + self.assertEqual(self.mods.argRemoval0(a0, a1), (a0, a1, 321, 456)) + self.assertEqual(self.mods.argRemoval0(a0, a1, a2), (a0, a1, 321, a2)) + # the other wasn't modified + # void argRemoval0(int, bool, int, bool) + self.assertEqual(self.mods.argRemoval0(0, False, 0, False), None) + + def testArgRemoval1(self): + '''Tests argument removal modifications on Modifications.argRemoval1.''' + # void [-> PyObject*] argRemoval1(int, bool, Point = Point(1, 2) [removed], Point = Point(3, 4) [removed], int = 333) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = 1, True, 2 + self.assertEqual(self.mods.argRemoval1(a0, a1), (a0, a1, Point(1, 2), Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval1(a0, a1, a2), (a0, a1, Point(1, 2), Point(3, 4), a2)) + # the other wasn't modified + # void argRemoval1(int, bool, int, bool) + self.assertEqual(self.mods.argRemoval1(0, False, 0, False), None) + + def testArgRemoval2(self): + '''Tests argument removal modifications on Modifications.argRemoval2.''' + # void [-> PyObject*] argRemoval2(int, bool, Point = Point(1, 2) [removed], Point = Point(3, 4) [removed], int = 333) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = 1, True, 2 + self.assertEqual(self.mods.argRemoval2(a0, a1), (a0, a1, Point(1, 2), Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval2(a0, a1, a2), (a0, a1, Point(1, 2), Point(3, 4), a2)) + + def testArgRemoval3(self): + '''Tests argument removal modifications on Modifications.argRemoval3.''' + # void [-> PyObject*] argRemoval3(int, Point = Point(1, 2) [removed], bool = true, Point = Point(3, 4) [removed], int = 333) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = 1, True, 2 + self.assertEqual(self.mods.argRemoval3(a0), (a0, Point(1, 2), True, Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval3(a0, a1), (a0, Point(1, 2), a1, Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval3(a0, a1, a2), (a0, Point(1, 2), a1, Point(3, 4), a2)) + + def testArgRemoval4(self): + '''Tests argument removal modifications on Modifications.argRemoval4.''' + # void [-> PyObject*] argRemoval4(int, Point [removed, new val = Point(6, 9)], bool, Point = Point(3, 4) [removed], int = 333) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = 1, True, 2 + self.assertRaises(TypeError, self.mods.argRemoval4, a0) + self.assertEqual(self.mods.argRemoval4(a0, a1), (a0, Point(6, 9), a1, Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval4(a0, a1, a2), (a0, Point(6, 9), a1, Point(3, 4), a2)) + + def testArgRemoval5(self): + '''Tests argument removal modifications on Modifications.argRemoval5.''' + # void [-> PyObject*] argRemoval5(int [removed, new val = 100], bool, + # Point = Point(1, 2) [removed], + # Point = Point(3, 4) [removed], int = 333) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = True, 2, True + self.assertEqual(self.mods.argRemoval5(a0), (100, a0, Point(1, 2), Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval5(a0, a1), (100, a0, Point(1, 2), Point(3, 4), a1)) + # void [-> PyObject*] argRemoval5(int [removed, new val = 200], bool, int, bool) + # code-injection: returns tuple with received parameters plus removed ones + self.assertEqual(self.mods.argRemoval5(a0, a1, a2), (200, a0, a1, a2)) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/bug_554_test.py b/sources/shiboken2/tests/samplebinding/bug_554_test.py new file mode 100644 index 000000000..0bcce92cf --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/bug_554_test.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Unit test for bug#554''' + +from sample import * + +class Bug554: + def crash(self): + class Crasher(ObjectType): + pass + +if __name__ == '__main__': + bug = Bug554() + bug.crash() + + diff --git a/sources/shiboken2/tests/samplebinding/bug_704_test.py b/sources/shiboken2/tests/samplebinding/bug_704_test.py new file mode 100644 index 000000000..6b393f3b1 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/bug_704_test.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 py3kcompat import IS_PY3K + +from sample import ObjectType + + +class NewStyle(object): + def name(self): + return "NewStyle" + +class OldStyle: + def name(self): + return "OldStyle" + +def defineNewStyle(): + class MyObjectNew(ObjectType, NewStyle): + pass + +def defineOldStyle(): + class MyObjectOld(ObjectType, OldStyle): + pass + +class ObjectTypeTest(unittest.TestCase): + '''Test cases to avoid declaring Shiboken classes with multiple inheritance from old style classes.''' + + def testObjectTypeNewStype(self): + defineNewStyle() + + def testObjectTypeOldStype(self): + # Py 3k doesn't have old style classes + if not IS_PY3K: + self.assertRaises(TypeError, defineOldStyle) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp b/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp new file mode 100644 index 000000000..39fb8d353 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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$ +** +****************************************************************************/ + +#if PY_VERSION_HEX < 0x03000000 +// ByteArray buffer protocol functions +// See: http://www.python.org/dev/peps/pep-3118/ +extern "C" { +static Py_ssize_t SbkByteArray_segcountproc(PyObject* self, Py_ssize_t* lenp) +{ + if (lenp) + *lenp = self->ob_type->tp_as_sequence->sq_length(self); + return 1; +} +static Py_ssize_t SbkByteArray_readbufferproc(PyObject* self, Py_ssize_t segment, void** ptrptr) +{ + if (segment || !Shiboken::Object::isValid(self)) + return -1; + + ByteArray* cppSelf = %CONVERTTOCPP[ByteArray*](self); + *ptrptr = reinterpret_cast(const_cast(cppSelf->data())); + return cppSelf->size(); +} +PyBufferProcs SbkByteArrayBufferProc = { + /*bf_getreadbuffer*/ &SbkByteArray_readbufferproc, + /*bf_getwritebuffer*/ (writebufferproc)&SbkByteArray_readbufferproc, + /*bf_getsegcount*/ &SbkByteArray_segcountproc, + /*bf_getcharbuffer*/ (charbufferproc)&SbkByteArray_readbufferproc +}; +} +#endif diff --git a/sources/shiboken2/tests/samplebinding/bytearray_test.py b/sources/shiboken2/tests/samplebinding/bytearray_test.py new file mode 100644 index 000000000..0e8039469 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/bytearray_test.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 os.path import isdir +from sample import ByteArray +from py3kcompat import b + + +class ByteArrayBufferProtocolTest(unittest.TestCase): + '''Tests ByteArray implementation of Python buffer protocol.''' + + def testByteArrayBufferProtocol(self): + # Tests ByteArray implementation of Python buffer protocol using the os.path.isdir + # function which an unicode object or other object implementing the Python buffer protocol. + isdir(str(ByteArray('/tmp'))) + + +class ByteArrayConcatenationOperatorTest(unittest.TestCase): + '''Test cases for ByteArray concatenation with '+' operator.''' + + def testConcatByteArrayAndPythonString(self): + # Test concatenation of a ByteArray with a Python string, in this order. + ba = ByteArray('foo') + result = ba + '\x00bar' + self.assertEqual(type(result), ByteArray) + self.assertEqual(result, 'foo\x00bar') + + def testConcatPythonStringAndByteArray(self): + # Test concatenation of a Python string with a ByteArray, in this order. + concat_python_string_add_qbytearray_worked = True + ba = ByteArray('foo') + result = 'bar\x00' + ba + self.assertEqual(type(result), ByteArray) + self.assertEqual(result, 'bar\x00foo') + + +class ByteArrayOperatorEqual(unittest.TestCase): + '''TestCase for operator ByteArray == ByteArray.''' + + def testDefault(self): + # ByteArray() == ByteArray() + obj1 = ByteArray() + obj2 = ByteArray() + self.assertEqual(obj1, obj2) + + def testSimple(self): + # ByteArray(some_string) == ByteArray(some_string) + string = 'egg snakes' + self.assertEqual(ByteArray(string), ByteArray(string)) + + def testPyString(self): + # ByteArray(string) == string + string = 'my test string' + self.assertEqual(ByteArray(string), string) + + def testQString(self): + # ByteArray(string) == string + string = 'another test string' + self.assertEqual(ByteArray(string), string) + + +class ByteArrayOperatorAt(unittest.TestCase): + '''TestCase for operator ByteArray[]''' + + def testInRange(self): + # ByteArray[x] where x is a valid index. + string = 'abcdefgh' + obj = ByteArray(string) + for i in range(len(string)): + self.assertEqual(obj[i], b(string[i])) + + def testInRangeReverse(self): + # ByteArray[x] where x is a valid index (reverse order). + string = 'abcdefgh' + obj = ByteArray(string) + for i in range(len(string)-1, 0, -1): + self.assertEqual(obj[i], b(string[i])) + + def testOutOfRange(self): + # ByteArray[x] where x is out of index. + string = '1234567' + obj = ByteArray(string) + self.assertRaises(IndexError, lambda :obj[len(string)]) + + def testNullStrings(self): + ba = ByteArray('\x00') + self.assertEqual(ba.at(0), '\x00') + self.assertEqual(ba[0], b('\x00')) + + +class ByteArrayOperatorLen(unittest.TestCase): + '''Test case for __len__ operator of ByteArray''' + + def testBasic(self): + '''ByteArray __len__''' + self.assertEqual(len(ByteArray()), 0) + self.assertEqual(len(ByteArray('')), 0) + self.assertEqual(len(ByteArray(' ')), 1) + self.assertEqual(len(ByteArray('yabadaba')), 8) + + +class ByteArrayAndPythonStr(unittest.TestCase): + '''Test case for __str__ operator of ByteArray''' + + def testStrOperator(self): + '''ByteArray __str__''' + self.assertEqual(ByteArray().__str__(), '') + self.assertEqual(ByteArray('').__str__(), '') + self.assertEqual(ByteArray('aaa').__str__(), 'aaa') + + def testPythonStrAndNull(self): + s1 = b('123\000321') + ba = ByteArray(s1) + s2 = ba.data() + self.assertEqual(s1, s2) + self.assertEqual(type(s1), type(s2)) + self.assertEqual(s1, ba) + self.assertNotEqual(type(s1), type(ba)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/child_return_test.py b/sources/shiboken2/tests/samplebinding/child_return_test.py new file mode 100644 index 000000000..30859dc5a --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/child_return_test.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''The BlackBox class has cases of ownership transference between C++ and Python.''' + +import sys +import unittest + +from sample import * + +class ReturnOfChildTest(unittest.TestCase): + '''The BlackBox class has cases of ownership transference between C++ and Python.''' + + def testKillParentKeepingChild(self): + '''Ownership transference from Python to C++ and back again.''' + o1 = ObjectType.createWithChild() + child = o1.children()[0] + del o1 + self.assertRaises(RuntimeError, child.objectName) + + def testKillParentKeepingChild2(self): + '''Ownership transference from Python to C++ and back again.''' + o1 = ObjectType.createWithChild() + child = o1.findChild("child") + del o1 + self.assertRaises(RuntimeError, child.objectName) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/class_fields_test.py b/sources/shiboken2/tests/samplebinding/class_fields_test.py new file mode 100644 index 000000000..0a2491cf2 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/class_fields_test.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Simple test case for accessing the exposed C++ class fields.''' + +from sys import getrefcount +import unittest + +from sample import Derived, Point, ObjectType + +class TestAccessingCppFields(unittest.TestCase): + '''Simple test case for accessing the exposed C++ class fields.''' + + def testAccessingPrimitiveTypeField(self): + '''Reads and writes a primitive type (in this case an 'int') field.''' + d = Derived() + self.assertEqual(type(d.primitiveField), int) + + # attribution + old_value = d.primitiveField + new_value = 2255 + d.primitiveField = new_value + self.assertEqual(d.primitiveField, new_value) + self.assertNotEqual(d.primitiveField, old_value) + + # attribution with a convertible type + value = 1.2 + d.primitiveField = value + self.assertEqual(d.primitiveField, int(value)) + + # attribution with invalid type + self.assertRaises(TypeError, lambda : setattr(d, 'primitiveField', None)) + + def testAccessingUsersPrimitiveTypeField(self): + '''Reads and writes an user's primitive type (in this case an 'Complex') field.''' + d = Derived() + self.assertEqual(type(d.userPrimitiveField), complex) + + # attribution + old_value = d.userPrimitiveField + new_value = complex(1.1, 2.2) + d.userPrimitiveField = new_value + self.assertEqual(d.userPrimitiveField, new_value) + self.assertNotEqual(d.userPrimitiveField, old_value) + + # attribution with invalid type + self.assertRaises(TypeError, lambda : setattr(d, 'userPrimitiveField', None)) + + def testAccessingValueTypeField(self): + '''Reads and writes a value type (in this case a 'Point') field.''' + d = Derived() + self.assertEqual(type(d.valueTypeField), Point) + + # attribution + old_value = d.valueTypeField + new_value = Point(-10, 537) + d.valueTypeField = new_value + self.assertEqual(d.valueTypeField, new_value) + + #object modify + d.valueTypeField.setX(10) + d.valueTypeField.setY(20) + self.assertEqual(d.valueTypeField.x(), 10) + self.assertEqual(d.valueTypeField.y(), 20) + + # attribution with invalid type + self.assertRaises(TypeError, lambda : setattr(d, 'valueTypeField', 123)) + + def testAccessingObjectTypeField(self): + '''Reads and writes a object type (in this case an 'ObjectType') field.''' + d = Derived() + + # attribution + old_value = d.objectTypeField + new_value = ObjectType() + d.objectTypeField = new_value + self.assertEqual(d.objectTypeField, new_value) + self.assertNotEqual(d.objectTypeField, old_value) + + # attribution with a convertible type + value = None + d.objectTypeField = value + self.assertEqual(d.objectTypeField, value) + + # attribution with invalid type + self.assertRaises(TypeError, lambda : setattr(d, 'objectTypeField', 123)) + + def testRefCountingAccessingObjectTypeField(self): + '''Accessing a object type field should respect the reference counting rules.''' + d = Derived() + + # attributing object to instance's field should increase its reference count + o1 = ObjectType() + refcount1 = getrefcount(o1) + d.objectTypeField = o1 + self.assertEqual(d.objectTypeField, o1) + self.assertEqual(getrefcount(d.objectTypeField), refcount1 + 1) + + # attributing a new object to instance's field should decrease the previous object's reference count + o2 = ObjectType() + refcount2 = getrefcount(o2) + d.objectTypeField = o2 + self.assertEqual(d.objectTypeField, o2) + self.assertEqual(getrefcount(o1), refcount1) + self.assertEqual(getrefcount(d.objectTypeField), refcount2 + 1) + + def testRefCountingOfReferredObjectAfterDeletingReferrer(self): + '''Deleting the object referring to other object should decrease the reference count of the referee.''' + d = Derived() + o = ObjectType() + refcount = getrefcount(o) + d.objectTypeField = o + self.assertEqual(getrefcount(o), refcount + 1) + del d + self.assertEqual(getrefcount(o), refcount) + + def testStaticField(self): + self.assertEqual(Derived.staticPrimitiveField, 0) + + def testAccessingUnsignedIntBitField(self): + d = Derived() + + # attribution + old_value = d.bitField + new_value = 1 + d.bitField= new_value + self.assertEqual(d.bitField, new_value) + self.assertNotEqual(d.bitField, old_value) + + # attribution with a convertible type + value = 1.2 + d.bitField = value + self.assertEqual(d.bitField, int(value)) + + # attribution with invalid type + self.assertRaises(TypeError, lambda : setattr(d, 'bitField', None)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/collector_test.py b/sources/shiboken2/tests/samplebinding/collector_test.py new file mode 100644 index 000000000..cbd6326e6 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/collector_test.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Collector class' shift operators.''' + +import sys +import unittest + +from sample import Collector, IntWrapper, ObjectType + + +class CollectorTest(unittest.TestCase): + '''Test cases for Collector class' shift operators.''' + + def testLShiftOperatorSingleUse(self): + '''Test case for using the Collector.__lshift__ operator just one time.''' + collector = Collector() + collector << 13 + self.assertEqual(collector.size(), 1) + self.assertEqual(collector.items(), [13]) + + def testLShiftOperatorMultipleUses(self): + '''Test case for using the Collector.__lshift__ operator many times in the same line.''' + collector = Collector() + collector << 2 << 3 << 5 << 7 << 11 + self.assertEqual(collector.size(), 5) + self.assertEqual(collector.items(), [2, 3, 5, 7, 11]) + +class CollectorExternalOperator(unittest.TestCase): + '''Test cases for external operators of Collector''' + + def testLShiftExternal(self): + '''Collector external operator''' + collector = Collector() + collector << IntWrapper(5) + self.assertEqual(collector.size(), 1) + self.assertEqual(collector.items(), [5]) + + +class CollectorObjectType(unittest.TestCase): + '''Test cases for Collector ObjectType''' + + def testBasic(self): + '''Collector << ObjectType # greedy collector''' + collector = Collector() + obj = ObjectType() + collector << obj + self.assertEqual(collector.items()[0], obj.identifier()) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/complex_test.py b/sources/shiboken2/tests/samplebinding/complex_test.py new file mode 100644 index 000000000..3a14f4d15 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/complex_test.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Complex class''' + +import sys +import unittest + +import sample +from sample import Point + +class ComplexTest(unittest.TestCase): + '''Test case for conversions between C++ Complex class to Python complex class''' + + def testFunctionReturningComplexObject(self): + '''Test function returning a C++ Complex object.''' + cpx = sample.transmutePointIntoComplex(Point(5.0, 2.3)) + self.assertEqual(cpx, complex(5.0, 2.3)) + + def testFunctionReceivingComplexObjectAsArgument(self): + '''Test function returning a C++ Complex object.''' + pt = sample.transmuteComplexIntoPoint(complex(1.2, 3.4)) + # these assertions intentionally avoids to test the == operator, + # it should have its own test cases. + self.assertEqual(pt.x(), 1.2) + self.assertEqual(pt.y(), 3.4) + + def testComplexList(self): + '''Test list of C++ Complex objects conversion to a list of Python complex objects.''' + # the global function gimmeComplexList() is expected to return a list + # containing the following Complex values: [0j, 1.1+2.2j, 1.3+2.4j] + cpxlist = sample.gimmeComplexList() + self.assertEqual(cpxlist, [complex(), complex(1.1, 2.2), complex(1.3, 2.4)]) + + def testSumComplexPair(self): + '''Test sum of a tuple containing two complex objects.''' + cpx1 = complex(1.2, 3.4) + cpx2 = complex(5.6, 7.8) + self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), cpx1 + cpx2) + + def testUsingTuples(self): + cpx1, cpx2 = (1.2, 3.4), (5.6, 7.8) + self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), sample.sumComplexPair((complex(*cpx1), complex(*cpx2)))) + cpx1, cpx2 = (1, 3), (5, 7) + self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), sample.sumComplexPair((complex(*cpx1), complex(*cpx2)))) + cpx1, cpx2 = (1.2, 3), (5.6, 7) + self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), sample.sumComplexPair((complex(*cpx1), complex(*cpx2)))) + cpx1, cpx2 = (1, 2, 3), (4, 5, 7) + self.assertRaises(TypeError, sample.sumComplexPair, (cpx1, cpx2)) + cpx1, cpx2 = ('1', '2'), ('4', '5') + self.assertRaises(TypeError, sample.sumComplexPair, (cpx1, cpx2)) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/conversion_operator_test.py b/sources/shiboken2/tests/samplebinding/conversion_operator_test.py new file mode 100644 index 000000000..01ac102e8 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/conversion_operator_test.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 implicit conversion generated by conversion operator.''' + +import unittest + +from sample import Time, StrList + +class ConversionOperatorTest(unittest.TestCase): + '''Test cases for implicit conversion generated by conversion operator.''' + + def testConversionOperator(self): + '''Time defined an conversion operator for Str, so passing a Time object to a method expecting a Str should work.''' + t = Time(1, 2, 3) + t_str = t.toString() + sl = StrList() + + # StrList.append expects a Str object. + sl.append(t) + + self.assertEqual(len(sl), 1) + self.assertEqual(sl[0], t_str) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/copy_test.py b/sources/shiboken2/tests/samplebinding/copy_test.py new file mode 100644 index 000000000..09c8e4cbc --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/copy_test.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 deep copy of objects''' + +import copy +import unittest + +try: + import cPickle as pickle +except ImportError: + import pickle + + +from sample import Point + + +class SimpleCopy(unittest.TestCase): + '''Simple copy of objects''' + + def testCopy(self): + point = Point(0.1, 2.4) + new_point = copy.copy(point) + + self.assertTrue(point is not new_point) + self.assertEqual(point, new_point) + + +class DeepCopy(unittest.TestCase): + '''Deep copy with shiboken objects''' + + def testDeepCopy(self): + '''Deep copy of value types''' + point = Point(3.1, 4.2) + new_point = copy.deepcopy([point])[0] + + self.assertTrue(point is not new_point) + self.assertEqual(point, new_point) + + +class PicklingTest(unittest.TestCase): + '''Support pickling''' + + def testSimple(self): + '''Simple pickling and unpickling''' + + point = Point(10.2, 43.5) + + data = pickle.dumps(point) + new_point = pickle.loads(data) + + self.assertEqual(point, new_point) + self.assertTrue(point is not new_point) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/ctorconvrule_test.py b/sources/shiboken2/tests/samplebinding/ctorconvrule_test.py new file mode 100644 index 000000000..d1ebdc9d3 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ctorconvrule_test.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 proper generation of constructor altered by conversion-rule tag.''' + +import unittest + +from sample import CtorConvRule + +class TestCtorConvRule(unittest.TestCase): + '''Simple test case for CtorConvRule''' + + def testCtorConvRule(self): + '''Test CtorConvRule argument modification through conversion-rule tag.''' + value = 123 + obj = CtorConvRule(value) + self.assertEqual(obj.value(), value + 1) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/cyclic_test.py b/sources/shiboken2/tests/samplebinding/cyclic_test.py new file mode 100644 index 000000000..e92b3605f --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/cyclic_test.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 ObjectType +from sample import ObjectView +from sample import ObjectModel + + + +class ObjTest(unittest.TestCase): + + def test_cyclic_dependency_withParent(self): + """Create 2 objects with a cyclic dependency, so that they can + only be removed by the garbage collector, and then invoke the + garbage collector in a different thread. + """ + import gc + + class CyclicChildObject(ObjectType): + def __init__(self, parent): + super(CyclicChildObject, self).__init__(parent) + self._parent = parent + + class CyclicObject(ObjectType): + def __init__(self): + super(CyclicObject, self).__init__() + CyclicChildObject(self) + + # turn off automatic garbage collection, to be able to trigger it + # at the 'right' time + gc.disable() + alive = lambda :sum(isinstance(o, CyclicObject) for o in gc.get_objects() ) + + # + # first proof that the wizard is only destructed by the garbage + # collector + # + cycle = CyclicObject() + self.assertTrue(alive()) + del cycle + self.assertTrue(alive()) + gc.collect() + self.assertFalse(alive()) + + def test_cyclic_dependency_withKeepRef(self): + """Create 2 objects with a cyclic dependency, so that they can + only be removed by the garbage collector, and then invoke the + garbage collector in a different thread. + """ + import gc + + class CyclicChildObject(ObjectView): + def __init__(self, model): + super(CyclicChildObject, self).__init__(None) + self.setModel(model) + + class CyclicObject(ObjectModel): + def __init__(self): + super(CyclicObject, self).__init__() + self._view = CyclicChildObject(self) + + # turn off automatic garbage collection, to be able to trigger it + # at the 'right' time + gc.disable() + alive = lambda :sum(isinstance(o, CyclicObject) for o in gc.get_objects() ) + + # + # first proof that the wizard is only destructed by the garbage + # collector + # + cycle = CyclicObject() + self.assertTrue(alive()) + del cycle + self.assertTrue(alive()) + gc.collect() + self.assertFalse(alive()) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/date_test.py b/sources/shiboken2/tests/samplebinding/date_test.py new file mode 100644 index 000000000..800774a57 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/date_test.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 python conversions types ''' + +import sys +import unittest +from datetime import date + +from sample import SbkDate + +class DateConversionTest(unittest.TestCase): + + def testConstructorWithDateObject(self): + pyDate = date(2010, 12, 12) + cDate = SbkDate(pyDate) + self.assertTrue(cDate.day(), pyDate.day) + self.assertTrue(cDate.month(), pyDate.month) + self.assertTrue(cDate.year(), pyDate.year) + + def testToPythonFunction(self): + cDate = SbkDate(2010, 12, 12) + pyDate = cDate.toPython() + self.assertTrue(cDate.day(), pyDate.day) + self.assertTrue(cDate.month(), pyDate.month) + self.assertTrue(cDate.year(), pyDate.year) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/decisor_test.py b/sources/shiboken2/tests/samplebinding/decisor_test.py new file mode 100644 index 000000000..33f41b9ff --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/decisor_test.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 the method overload decisor.''' + +import unittest + +from sample import SampleNamespace, Point, ObjectType, ObjectModel + +class DecisorTest(unittest.TestCase): + '''Test cases for the method overload decisor.''' + + def testCallWithInvalidParametersSideA(self): + '''Call a method missing with the last argument missing. + This can trigger the bug #262, which means using an argument + not provided by the user.''' + pt = Point() + self.assertRaises(TypeError, SampleNamespace.forceDecisorSideA, pt) + + def testCallWithInvalidParametersSideB(self): + '''Same as the previous test, but with an integer as first argument, + just to complicate things for the overload method decisor.''' + pt = Point() + self.assertRaises(TypeError, SampleNamespace.forceDecisorSideB, 1, pt) + + def testDecideCallWithInheritance(self): + '''Call methods overloads that receive parent and inheritor classes' instances.''' + objecttype = ObjectType() + objectmodel = ObjectModel() + self.assertEqual(ObjectModel.receivesObjectTypeFamily(objecttype), ObjectModel.ObjectTypeCalled) + self.assertNotEqual(ObjectModel.receivesObjectTypeFamily(objecttype), ObjectModel.ObjectModelCalled) + self.assertEqual(ObjectModel.receivesObjectTypeFamily(objectmodel), ObjectModel.ObjectModelCalled) + self.assertNotEqual(ObjectModel.receivesObjectTypeFamily(objectmodel), ObjectModel.ObjectTypeCalled) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/delete_test.py b/sources/shiboken2/tests/samplebinding/delete_test.py new file mode 100644 index 000000000..bc20ea234 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/delete_test.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 +import sample +import shiboken2 as shiboken + +class DeleteTest(unittest.TestCase): + def testNonCppWrapperClassDelete(self): + """Would segfault when shiboken.delete called on obj not created from + Python """ + obj = sample.ObjectType() + child = obj.createChild(None) + shiboken.delete(child) + assert not shiboken.isValid(child) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/deprecated_test.py b/sources/shiboken2/tests/samplebinding/deprecated_test.py new file mode 100644 index 000000000..6c850cd10 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/deprecated_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 warnings +import unittest + +from sample import ObjectType + +class TestDeprecatedCall(unittest.TestCase): + def testCallWithError(self): + o = ObjectType() + warnings.simplefilter('error') + self.assertRaises(DeprecationWarning, o.deprecatedFunction) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/derived_test.py b/sources/shiboken2/tests/samplebinding/derived_test.py new file mode 100644 index 000000000..b19835fef --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/derived_test.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Derived class''' + +import sys +import unittest + +import sample +from sample import Abstract, Derived, OverloadedFuncEnum + +class Deviant(Derived): + def __init__(self): + Derived.__init__(self) + self.pure_virtual_called = False + self.unpure_virtual_called = False + + def pureVirtual(self): + self.pure_virtual_called = True + + def unpureVirtual(self): + self.unpure_virtual_called = True + + def className(self): + return 'Deviant' + +class DerivedTest(unittest.TestCase): + '''Test case for Derived class''' + + def testParentClassMethodsAvailability(self): + '''Test if Derived class really inherits its methods from parent.''' + inherited_methods = set(['callPureVirtual', 'callUnpureVirtual', + 'id_', 'pureVirtual', 'unpureVirtual']) + self.assertTrue(inherited_methods.issubset(dir(Derived))) + + def testOverloadedMethodCall(self): + '''Test if the correct overloaded method is being called.''' + derived = Derived() + + result = derived.overloaded(1, 2) + self.assertEqual(type(result), OverloadedFuncEnum) + self.assertEqual(result, sample.OverloadedFunc_ii) + + result = derived.overloaded(3) + self.assertEqual(type(result), OverloadedFuncEnum) + self.assertEqual(result, sample.OverloadedFunc_ii) + + result = derived.overloaded(4.4) + self.assertEqual(type(result), OverloadedFuncEnum) + self.assertEqual(result, sample.OverloadedFunc_d) + + def testOtherOverloadedMethodCall(self): + '''Another test to check overloaded method calling, just to double check.''' + derived = Derived() + + result = derived.otherOverloaded(1, 2, True, 3.3) + self.assertEqual(type(result), Derived.OtherOverloadedFuncEnum) + self.assertEqual(result, sample.Derived.OtherOverloadedFunc_iibd) + + result = derived.otherOverloaded(1, 2.2) + self.assertEqual(type(result), Derived.OtherOverloadedFuncEnum) + self.assertEqual(result, Derived.OtherOverloadedFunc_id) + + def testOverloadedMethodCallWithDifferentNumericTypes(self): + '''Test if the correct overloaded method accepts a different numeric type as argument.''' + derived = Derived() + result = derived.overloaded(1.1, 2.2) + self.assertEqual(type(result), OverloadedFuncEnum) + self.assertEqual(result, sample.OverloadedFunc_ii) + + def testOverloadedMethodCallWithWrongNumberOfArguments(self): + '''Test if a call to an overloaded method with the wrong number of arguments raises an exception.''' + derived = Derived() + self.assertRaises(TypeError, derived.otherOverloaded, 1, 2, True) + + def testReimplementedPureVirtualMethodCall(self): + '''Test if a Python override of a implemented pure virtual method is correctly called from C++.''' + d = Deviant() + d.callPureVirtual() + self.assertTrue(d.pure_virtual_called) + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a reimplemented virtual method is correctly called from C++.''' + d = Deviant() + d.callUnpureVirtual() + self.assertTrue(d.unpure_virtual_called) + + def testVirtualMethodCallString(self): + '''Test virtual method call returning string.''' + d = Derived() + self.assertEqual(d.className(), 'Derived') + self.assertEqual(d.getClassName(), 'Derived') + + def testReimplementedVirtualMethodCallReturningString(self): + '''Test if a Python override of a reimplemented virtual method is correctly called from C++.''' + d = Deviant() + self.assertEqual(d.className(), 'Deviant') + self.assertEqual(d.getClassName(), 'Deviant') + + def testSingleArgument(self): + '''Test singleArgument call.''' + d = Derived() + self.assertTrue(d.singleArgument(False)) + self.assertTrue(not d.singleArgument(True)) + + def testMethodCallWithDefaultValue(self): + '''Test method call with default value.''' + d = Derived() + self.assertEqual(d.defaultValue(3), 3.1) + self.assertEqual(d.defaultValue(), 0.1) + + def testCallToMethodWithAbstractArgument(self): + '''Call to method that expects an Abstract argument.''' + objId = 123 + d = Derived(objId) + self.assertEqual(Abstract.getObjectId(d), objId) + + def testObjectCreationWithParentType(self): + '''Derived class creates an instance of itself in C++ and returns it as a pointer to its ancestor Abstract.''' + obj = Derived.createObject() + self.assertEqual(type(obj), Derived) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/duck_punching_test.py b/sources/shiboken2/tests/samplebinding/duck_punching_test.py new file mode 100644 index 000000000..fd60a96af --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/duck_punching_test.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 virtual methods.''' + +import types +import unittest +from py3kcompat import IS_PY3K + +from sample import VirtualMethods, SimpleFile, Point + +def MethodTypeCompat(func, instance): + if IS_PY3K: + return types.MethodType(func, instance) + else: + return types.MethodType(func, instance, type(instance)) + +class Duck(VirtualMethods): + def __init__(self): + VirtualMethods.__init__(self) + +class Monkey(SimpleFile): + def __init__(self, filename): + SimpleFile.__init__(self, filename) + +class DuckPunchingTest(unittest.TestCase): + '''Test case for duck punching (aka "monkey patching").''' + + def setUp(self): + self.multiplier = 2.0 + self.duck_method_called = False + self.call_counter = 0 + + def testMonkeyPatchOnVirtualMethod(self): + '''Injects new 'virtualMethod0' on a VirtualMethods instance and makes C++ call it.''' + vm = VirtualMethods() + pt, val, cpx, b = Point(1.1, 2.2), 4, complex(3.3, 4.4), True + + result1 = vm.virtualMethod0(pt, val, cpx, b) + result2 = vm.callVirtualMethod0(pt, val, cpx, b) + self.assertEqual(result1, result2) + self.assertEqual(result1, VirtualMethods.virtualMethod0(vm, pt, val, cpx, b)) + + def myVirtualMethod0(obj, pt, val, cpx, b): + self.duck_method_called = True + return VirtualMethods.virtualMethod0(obj, pt, val, cpx, b) * self.multiplier + vm.virtualMethod0 = MethodTypeCompat(myVirtualMethod0, vm) + + result1 = vm.callVirtualMethod0(pt, val, cpx, b) + self.assertTrue(self.duck_method_called) + + result2 = vm.virtualMethod0(pt, val, cpx, b) + self.assertEqual(result1, result2) + self.assertEqual(result1, VirtualMethods.virtualMethod0(vm, pt, val, cpx, b) * self.multiplier) + + # This is done to decrease the refcount of the vm object + # allowing the object wrapper to be deleted before the + # BindingManager. This is useful when compiling Shiboken + # for debug, since the BindingManager destructor has an + # assert that checks if the wrapper mapper is empty. + vm.virtualMethod0 = None + + def testMonkeyPatchOnVirtualMethodWithInheritance(self): + '''Injects new 'virtualMethod0' on an object that inherits from VirtualMethods and makes C++ call it.''' + duck = Duck() + pt, val, cpx, b = Point(1.1, 2.2), 4, complex(3.3, 4.4), True + + result1 = duck.virtualMethod0(pt, val, cpx, b) + result2 = duck.callVirtualMethod0(pt, val, cpx, b) + self.assertEqual(result1, result2) + self.assertEqual(result1, VirtualMethods.virtualMethod0(duck, pt, val, cpx, b)) + + def myVirtualMethod0(obj, pt, val, cpx, b): + self.duck_method_called = True + return VirtualMethods.virtualMethod0(obj, pt, val, cpx, b) * self.multiplier + duck.virtualMethod0 = MethodTypeCompat(myVirtualMethod0, duck) + + result1 = duck.callVirtualMethod0(pt, val, cpx, b) + self.assertTrue(self.duck_method_called) + + result2 = duck.virtualMethod0(pt, val, cpx, b) + self.assertEqual(result1, result2) + self.assertEqual(result1, VirtualMethods.virtualMethod0(duck, pt, val, cpx, b) * self.multiplier) + + duck.virtualMethod0 = None + + def testMonkeyPatchOnMethodWithStaticAndNonStaticOverloads(self): + '''Injects new 'exists' on a SimpleFile instance and makes C++ call it.''' + simplefile = SimpleFile('foobar') + + # Static 'exists' + simplefile.exists('sbrubbles') + self.assertFalse(self.duck_method_called) + # Non-static 'exists' + simplefile.exists() + self.assertFalse(self.duck_method_called) + + def myExists(obj): + self.duck_method_called = True + return False + simplefile.exists = MethodTypeCompat(myExists, simplefile) + + # Static 'exists' was overridden by the monkey patch, which accepts 0 arguments + self.assertRaises(TypeError, simplefile.exists, 'sbrubbles') + # Monkey patched exists + simplefile.exists() + self.assertTrue(self.duck_method_called) + + simplefile.exists = None + + def testMonkeyPatchOnMethodWithStaticAndNonStaticOverloadsWithInheritance(self): + '''Injects new 'exists' on an object that inherits from SimpleFile and makes C++ call it.''' + monkey = Monkey('foobar') + + # Static 'exists' + monkey.exists('sbrubbles') + self.assertFalse(self.duck_method_called) + # Non-static 'exists' + monkey.exists() + self.assertFalse(self.duck_method_called) + + def myExists(obj): + self.duck_method_called = True + return False + monkey.exists = MethodTypeCompat(myExists, monkey) + + # Static 'exists' was overridden by the monkey patch, which accepts 0 arguments + self.assertRaises(TypeError, monkey.exists, 'sbrubbles') + # Monkey patched exists + monkey.exists() + self.assertTrue(self.duck_method_called) + + monkey.exists = None + + def testForInfiniteRecursion(self): + def myVirtualMethod0(obj, pt, val, cpx, b): + self.call_counter += 1 + return VirtualMethods.virtualMethod0(obj, pt, val, cpx, b) + vm = VirtualMethods() + vm.virtualMethod0 = MethodTypeCompat(myVirtualMethod0, vm) + pt, val, cpx, b = Point(1.1, 2.2), 4, complex(3.3, 4.4), True + vm.virtualMethod0(pt, val, cpx, b) + self.assertEqual(self.call_counter, 1) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/echo_test.py b/sources/shiboken2/tests/samplebinding/echo_test.py new file mode 100644 index 000000000..1b0b6a2cc --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/echo_test.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 with const char* as argument''' + +import unittest + +from sample import Echo + +class TestEcho(unittest.TestCase): + '''Simple test case for Echo.echo''' + + def testEcho(self): + '''Test function added with const char * as arg''' + x = 'Foobar' + y = Echo().echo(x) + self.assertEqual(x, y) + + def testCallOperator(self): + e = Echo() + self.assertEqual(e("Hello", 3), "Hello3"); +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/enum_test.py b/sources/shiboken2/tests/samplebinding/enum_test.py new file mode 100644 index 000000000..6468d3cc4 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/enum_test.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Python representation of C++ enums.''' + +import os +import sys +import unittest + +import sample +from sample import SampleNamespace, ObjectType, Event +from py3kcompat import IS_PY3K, b + +def createTempFile(): + if sys.version_info >= (2, 6): + import tempfile + return tempfile.SpooledTemporaryFile(mode='rw') + else: + return os.tmpfile() + +class EnumTest(unittest.TestCase): + '''Test case for Python representation of C++ enums.''' + + def testEnumRepr(self): + enum = SampleNamespace.Option(1) + self.assertEqual(eval(repr(enum)), enum) + + enum = SampleNamespace.Option(999) + self.assertEqual(eval(repr(enum)), enum) + + def testHashability(self): + self.assertEqual(hash(SampleNamespace.TwoIn), hash(SampleNamespace.TwoOut)) + self.assertNotEqual(hash(SampleNamespace.TwoIn), hash(SampleNamespace.OneIn)) + + def testEnumValuesInsideEnum(self): + '''Enum values should be accessible inside the enum as well as outside.''' + for value_name in SampleNamespace.Option.values: + enum_item1 = getattr(SampleNamespace.Option, value_name) + enum_item2 = getattr(SampleNamespace, value_name) + self.assertEqual(enum_item1, enum_item2) + + def testPassingIntegerOnEnumArgument(self): + '''Tries to use an integer in place of an enum argument.''' + self.assertRaises(TypeError, SampleNamespace.getNumber, 1) + + def testBuildingEnumFromIntegerValue(self): + '''Tries to build the proper enum using an integer.''' + SampleNamespace.getNumber(SampleNamespace.Option(1)) + + def testBuildingEnumWithDefaultValue(self): + '''Enum constructor with default value''' + enum = SampleNamespace.Option() + self.assertEqual(enum, SampleNamespace.None_) + + def testEnumConversionToAndFromPython(self): + '''Conversion of enum objects from Python to C++ back again.''' + enumout = SampleNamespace.enumInEnumOut(SampleNamespace.TwoIn) + self.assertTrue(enumout, SampleNamespace.TwoOut) + self.assertEqual(repr(enumout), repr(SampleNamespace.TwoOut)) + + def testEnumConstructorWithTooManyParameters(self): + '''Calling the constructor of non-extensible enum with the wrong number of parameters.''' + self.assertRaises(TypeError, SampleNamespace.InValue, 13, 14) + + def testEnumConstructorWithNonNumberParameter(self): + '''Calling the constructor of non-extensible enum with a string.''' + self.assertRaises(TypeError, SampleNamespace.InValue, '1') + + def testEnumItemAsDefaultValueToIntArgument(self): + '''Calls function with an enum item as default value to an int argument.''' + self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(), SampleNamespace.ZeroIn) + self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(SampleNamespace.ZeroOut), SampleNamespace.ZeroOut) + self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(123), 123) + + def testAnonymousGlobalEnums(self): + '''Checks availability of anonymous global enum items.''' + self.assertEqual(sample.AnonymousGlobalEnum_Value0, 0) + self.assertEqual(sample.AnonymousGlobalEnum_Value1, 1) + + def testAnonymousClassEnums(self): + '''Checks availability of anonymous class enum items.''' + self.assertEqual(SampleNamespace.AnonymousClassEnum_Value0, 0) + self.assertEqual(SampleNamespace.AnonymousClassEnum_Value1, 1) + + def testEnumTpPrintImplementation(self): + '''Without SbkEnum.tp_print 'print' returns the enum represented as an int.''' + tmpfile = createTempFile() + if IS_PY3K: + from py3k import printToFile + printToFile(tmpfile, Event.ANY_EVENT) + else: + sys.stdout = tmpfile + print(Event.ANY_EVENT) + sys.stdout = sys.__stdout__ + tmpfile.seek(0) + text = tmpfile.read().strip() + tmpfile.close() + self.assertEqual(text, str(Event.ANY_EVENT)) + self.assertEqual(text, repr(Event.ANY_EVENT)) + + def testEnumArgumentWithDefaultValue(self): + '''Option enumArgumentWithDefaultValue(Option opt = UnixTime);''' + self.assertEqual(SampleNamespace.enumArgumentWithDefaultValue(), SampleNamespace.UnixTime) + self.assertEqual(SampleNamespace.enumArgumentWithDefaultValue(SampleNamespace.RandomNumber), SampleNamespace.RandomNumber) + + +class MyEvent(Event): + def __init__(self): + Event.__init__(self, Event.EventType(999)) + +class OutOfBoundsTest(unittest.TestCase): + def testValue(self): + e = MyEvent() + self.assertEqual(repr(e.eventType()), 'sample.Event.EventType(999)') + + def testNoneName(self): + e = MyEvent() + t = e.eventType() + self.assertEqual(t.name, None) + +class EnumOverloadTest(unittest.TestCase): + '''Test case for overloads involving enums''' + + def testWithInt(self): + '''Overload with Enums and ints with default value''' + o = ObjectType() + + self.assertEqual(o.callWithEnum('', Event.ANY_EVENT, 9), 81) + self.assertEqual(o.callWithEnum('', 9), 9) + +class EnumOperators(unittest.TestCase): + '''Test case for operations on enums''' + + def testInequalitySameObject(self): + self.assertFalse(Event.ANY_EVENT != Event.ANY_EVENT) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/enumfromremovednamespace_test.py b/sources/shiboken2/tests/samplebinding/enumfromremovednamespace_test.py new file mode 100644 index 000000000..820e21f7c --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/enumfromremovednamespace_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 + +import sample + +class TestEnumFromRemovedNamespace(unittest.TestCase): + def testEnumPromotedToGlobal(self): + sample.RemovedNamespace1_Enum + sample.RemovedNamespace1_Enum_Value0 + sample.RemovedNamespace1_AnonymousEnum_Value0 + sample.RemovedNamespace2_Enum + sample.RemovedNamespace2_Enum_Value0 + + def testEnumPromotedToUpperNamespace(self): + sample.UnremovedNamespace + sample.UnremovedNamespace.RemovedNamespace3_Enum + sample.UnremovedNamespace.RemovedNamespace3_Enum_Value0 + sample.UnremovedNamespace.RemovedNamespace3_AnonymousEnum_Value0 + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/event_loop_call_virtual_test.py b/sources/shiboken2/tests/samplebinding/event_loop_call_virtual_test.py new file mode 100644 index 000000000..d8ed028c4 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/event_loop_call_virtual_test.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Simple event loop dispatcher test.''' + +import time +import unittest +from random import random + +from sample import ObjectType, Event + + +class NoOverride(ObjectType): + + pass + + +class Override(ObjectType): + + def __init__(self): + ObjectType.__init__(self) + self.called = False + + def event(self, event): + self.called = True + return True + + +class TestEventLoop(unittest.TestCase): + + def testEventLoop(self): + '''Calling virtuals in a event loop''' + objs = [ObjectType(), NoOverride(), Override()] + + evaluated = ObjectType.processEvent(objs, + Event(Event.BASIC_EVENT)) + + self.assertEqual(evaluated, 3) + self.assertTrue(objs[2].called) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/event_loop_thread_test.py b/sources/shiboken2/tests/samplebinding/event_loop_thread_test.py new file mode 100644 index 000000000..8211ecd15 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/event_loop_thread_test.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 time +import threading +import unittest +from random import random + +from sample import ObjectType, Event + + +class Producer(ObjectType): + + def __init__(self): + ObjectType.__init__(self) + self.data = None + self.read = False + + def event(self, event): + self.data = random() + + while not self.read: + time.sleep(0.01) + + return True + + +class Collector(threading.Thread): + + def __init__(self, objects): + threading.Thread.__init__(self) + self.max_runs = len(objects) + self.objects = objects + self.data = [] + + def run(self): + i = 0 + while i < self.max_runs: + if self.objects[i].data is not None: + self.data.append(self.objects[i].data) + self.objects[i].read = True + i += 1 + time.sleep(0.01) + + +class TestEventLoopWithThread(unittest.TestCase): + '''Communication between a python thread and an simple + event loop in C++''' + + def testBasic(self): + '''Allowing threads and calling virtuals from C++''' + number = 10 + objs = [Producer() for x in range(number)] + thread = Collector(objs) + + thread.start() + + evaluated = ObjectType.processEvent(objs, + Event(Event.BASIC_EVENT)) + + thread.join() + + producer_data = [x.data for x in objs] + self.assertEqual(evaluated, number) + self.assertEqual(producer_data, thread.data) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/filter_test.py b/sources/shiboken2/tests/samplebinding/filter_test.py new file mode 100644 index 000000000..eb84a932c --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/filter_test.py @@ -0,0 +1,45 @@ +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Data, Intersection, Union + +class TestFilters(unittest.TestCase): + + def testAnd(self): + + f1 = Data(Data.Name, "joe") + f2 = Union() + + inter = f1 & f2 + + self.assertEqual(type(inter), Intersection) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/global.h b/sources/shiboken2/tests/samplebinding/global.h new file mode 100644 index 000000000..d273de961 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/global.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "abstract.h" +#include "blackbox.h" +#include "bytearray.h" +#include "bucket.h" +#include "collector.h" +#include "complex.h" +#include "ctorconvrule.h" +#include "cvlist.h" +#include "sbkdate.h" +#include "derived.h" +#include "echo.h" +#include "functions.h" +#include "implicitconv.h" +#include "overloadsort.h" +#include "handle.h" +#include "injectcode.h" +#include "list.h" +#include "listuser.h" +#include "mapuser.h" +#include "modelindex.h" +#include "modifications.h" +#include "modified_constructor.h" +#include "multiple_derived.h" +#include "noimplicitconversion.h" +#include "nondefaultctor.h" +#include "objectmodel.h" +#include "objecttype.h" +#include "objecttypebyvalue.h" +#include "objecttypeholder.h" +#include "objecttypelayout.h" +#include "objecttypeoperators.h" +#include "objectview.h" +#include "oddbool.h" +#include "onlycopy.h" +#include "overload.h" +#include "pairuser.h" +#include "pen.h" +#include "photon.h" +#include "point.h" +#include "pointf.h" +#include "pointerholder.h" +#include "polygon.h" +#include "privatector.h" +#include "privatedtor.h" +#include "protected.h" +#include "rect.h" +#include "reference.h" +#include "removednamespaces.h" +#include "sample.h" +#include "samplenamespace.h" +#include "simplefile.h" +#include "size.h" +#include "str.h" +#include "strlist.h" +#include "sometime.h" +#include "templateptr.h" +#include "transform.h" +#include "virtualmethods.h" +#include "voidholder.h" +#include "valueandvirtual.h" +#include "expression.h" +#include "filter.h" diff --git a/sources/shiboken2/tests/samplebinding/handleholder_test.py b/sources/shiboken2/tests/samplebinding/handleholder_test.py new file mode 100644 index 000000000..6d945e499 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/handleholder_test.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 case for a class that holds a unknown handle object. + Test case for BUG #1105. +''' + +import unittest + +from sample import HandleHolder + +class HandleHolderTest(unittest.TestCase): + def testCreation(self): + holder = HandleHolder(HandleHolder.createHandle()) + holder2 = HandleHolder(HandleHolder.createHandle()) + self.assertEqual(holder.compare(holder2), False) + + def testTransfer(self): + holder = HandleHolder() + holder2 = HandleHolder(holder.handle()) + self.assertTrue(holder.compare(holder2)) + + def testUseDefinedType(self): + holder = HandleHolder(8) + holder2 = HandleHolder(holder.handle2()) + self.assertTrue(holder.compare2(holder2)) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/hashabletype_test.py b/sources/shiboken2/tests/samplebinding/hashabletype_test.py new file mode 100644 index 000000000..069824ca7 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/hashabletype_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 __hash__''' + +import unittest + +from sample import * + +class HashableTest(unittest.TestCase): + + def testStrHash(self): + h = {} + s = Str("Hi") + h[s] = 2 + self.assertTrue(h.get(s), 2) + + def testObjectTypeHash(self): + h = {} + o = ObjectType() + h[o] = 2 + self.assertTrue(h.get(o), 2) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/ignorederefop_test.py b/sources/shiboken2/tests/samplebinding/ignorederefop_test.py new file mode 100644 index 000000000..dc3fe8b13 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ignorederefop_test.py @@ -0,0 +1,38 @@ +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 * + +class TestLackOfDereferenceOperators (unittest.TestCase): + def testIf(self): + r = Reference() + self.assertFalse(hasattr(r, "__mul__")) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/implicitconv_numerical_test.py b/sources/shiboken2/tests/samplebinding/implicitconv_numerical_test.py new file mode 100644 index 000000000..3fe66e30c --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/implicitconv_numerical_test.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 case for inplicit converting C++ numeric types.''' + +import unittest +import sys +import sample +from py3kcompat import IS_PY3K, l, long + +# Hardcode the limits of the underlying C-types depending on architecture and memory +# model (taking MSVC using LLP64 into account). +cIntMin = -2147483648 +cIntMax = 2147483647 +cLongMin = cIntMin +cLongMax = cIntMax +maxRepresentableInt = sys.maxsize if IS_PY3K else sys.maxint +is64bitArchitecture = maxRepresentableInt > 2**32 +if is64bitArchitecture and sys.platform != 'win32': + cLongMin = -9223372036854775808 + cLongMax = 9223372036854775807 + +class NumericTester(unittest.TestCase): + '''Helper class for numeric comparison testing''' + + def check_value(self, source, expected, callback, desired_type=None): + result = callback(source) + self.assertEqual(result, expected) + + if desired_type: + self.assertEqual(type(result), desired_type) + + +class FloatImplicitConvert(NumericTester): + '''Test case for implicit converting C++ numeric types.''' + + def testFloatAsInt(self): + '''Float as Int''' + self.check_value(3.14, 3, sample.acceptInt, int) + self.assertRaises(OverflowError, sample.acceptInt, cIntMax + 400) + + def testFloatAsLong(self): + '''Float as Long''' + #C++ longs are python ints for us + self.check_value(3.14, 3, sample.acceptLong, int) + self.assertRaises(OverflowError, sample.acceptLong, cLongMax + 400) + + def testFloatAsUInt(self): + '''Float as unsigned Int''' + self.check_value(3.14, 3, sample.acceptUInt, long) + self.assertRaises(OverflowError, sample.acceptUInt, -3.14) + + def testFloatAsULong(self): + '''Float as unsigned Long''' + #FIXME Breaking with SystemError "bad argument to internal function" + self.check_value(3.14, 3, sample.acceptULong, long) + self.assertRaises(OverflowError, sample.acceptULong, -3.14) + + def testFloatAsDouble(self): + '''Float as double''' + self.check_value(3.14, 3.14, sample.acceptDouble, float) + + +class IntImplicitConvert(NumericTester): + '''Test case for implicit converting C++ numeric types.''' + + def testIntAsInt(self): + '''Int as Int''' + self.check_value(3, 3, sample.acceptInt, int) + + def testIntAsLong(self): + '''Int as Long''' + self.check_value(3, 3, sample.acceptLong, int) + + # cLongMax goes here as CPython implements int as a C long + self.check_value(cLongMax, cLongMax, sample.acceptLong, int) + self.check_value(cLongMin, cLongMin, sample.acceptLong, int) + + def testIntAsUInt(self): + '''Int as unsigned Int''' + self.check_value(3, 3, sample.acceptUInt, long) + self.assertRaises(OverflowError, sample.acceptUInt, -3) + + def testIntAsULong(self): + '''Int as unsigned Long''' + self.check_value(3, 3, sample.acceptULong, long) + self.assertRaises(OverflowError, sample.acceptULong, -3) + + def testFloatAsDouble(self): + '''Float as double''' + self.check_value(3.14, 3.14, sample.acceptDouble, float) + + +class LongImplicitConvert(NumericTester): + '''Test case for implicit converting C++ numeric types.''' + + def testLongAsInt(self): + '''Long as Int''' + self.check_value(l(24224), 24224, sample.acceptInt, int) + self.assertRaises(OverflowError, sample.acceptInt, cIntMax + 20) + + def testLongAsLong(self): + '''Long as Long''' + self.check_value(l(2405), 2405, sample.acceptLong, int) + self.assertRaises(OverflowError, sample.acceptLong, cLongMax + 20) + + def testLongAsUInt(self): + '''Long as unsigned Int''' + self.check_value(l(260), 260, sample.acceptUInt, long) + self.assertRaises(OverflowError, sample.acceptUInt, -42) + + def testLongAsULong(self): + '''Long as unsigned Long''' + self.check_value(l(128), 128, sample.acceptULong, long) + self.assertRaises(OverflowError, sample.acceptULong, l(-334)) + + def testLongAsDouble(self): + '''Float as double''' + self.check_value(l(42), 42, sample.acceptDouble, float) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/implicitconv_test.py b/sources/shiboken2/tests/samplebinding/implicitconv_test.py new file mode 100644 index 000000000..a94151d80 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/implicitconv_test.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 implicit conversions''' + +import unittest + +from sample import ImplicitConv, ObjectType + +class ImplicitConvTest(unittest.TestCase): + '''Test case for implicit conversions''' + + def testImplicitConversions(self): + '''Test if overloaded function call decisor takes implicit conversions into account.''' + ic = ImplicitConv.implicitConvCommon(ImplicitConv()) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorNone) + + ic = ImplicitConv.implicitConvCommon(3) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorOne) + self.assertEqual(ic.objId(), 3) + + ic = ImplicitConv.implicitConvCommon(ImplicitConv.CtorThree) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorThree) + + obj = ObjectType() + ic = ImplicitConv.implicitConvCommon(obj) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorObjectTypeReference) + + ic = ImplicitConv.implicitConvCommon(42.42) + self.assertEqual(ic.value(), 42.42) + + ic = ImplicitConv(None) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorPrimitiveType) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/inheritanceandscope_test.py b/sources/shiboken2/tests/samplebinding/inheritanceandscope_test.py new file mode 100755 index 000000000..a8ede0548 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/inheritanceandscope_test.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 finding scope in cases involving inheritance.''' + +import unittest + +from sample import SampleNamespace + +class ScopeAndInheritanceTest(unittest.TestCase): + '''Test cases for finding scope in cases involving inheritance.''' + + def testMethodCorrectlyWrapper(self): + '''A method returning a type declared in the scope of the method's + class parent must be found and the method correctly exported.''' + meth = getattr(SampleNamespace.DerivedFromNamespace, 'methodReturningTypeFromParentScope') + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/injectcode_test.py b/sources/shiboken2/tests/samplebinding/injectcode_test.py new file mode 100644 index 000000000..99847f891 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/injectcode_test.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 std::list container conversions''' + +import unittest +from sample import InjectCode + +class MyInjectCode(InjectCode): + def __init__(self): + InjectCode.__init__(self) + self.multiplier = 2 + + def arrayMethod(self, values): + return self.multiplier * sum(values) + +class InjectCodeTest(unittest.TestCase): + + def testTypeNativeBeginning_TypeTargetBeginning(self): + ic = InjectCode() + self.assertEqual(str(ic), "Hi! I'm the inject code dummy class.") + + def testFunctionTargetBeginning_FunctionTargetEnd(self): + ic = InjectCode() + ret = ic.simpleMethod1(2, 1) + self.assertEqual(ret, "4end") + ret = ic.simpleMethod1(4, 2) + self.assertEqual(ret, "7end") + + def testFunctionTargetBeginning(self): + ic = InjectCode() + ret = ic.simpleMethod2() + self.assertEqual(ret, "_end") + + def testArgsModification(self): + ic = InjectCode() + ret = ic.overloadedMethod(["1", "2", "3", "4"]) + self.assertEqual(ret, "1234") + ret = ic.overloadedMethod(2, 0.5) + self.assertEqual(ret, "2.5") + ret = ic.overloadedMethod(6, True) + self.assertEqual(ret, "6true") + + def testArgsModification2(self): + ic = InjectCode() + ret = ic.simpleMethod3(["1", "2", "3", "4"]) + self.assertEqual(ret, "1234") + + def testArgumentRemovalAndArgumentTypeModification(self): + '''A method has its first argument removed and the second modified.''' + ic = InjectCode() + values = (1, 2, 3, 4, 5) + result = ic.arrayMethod(values) + self.assertEqual(result, sum(values)) + + def testCallVirtualMethodWithArgumentRemovalAndArgumentTypeModification(self): + '''A virtual method has its first argument removed and the second modified.''' + ic = InjectCode() + values = (1, 2, 3, 4, 5) + result = ic.callArrayMethod(values) + self.assertEqual(result, sum(values)) + + def testCallReimplementedVirtualMethodWithArgumentRemovalAndArgumentTypeModification(self): + '''Calls a reimplemented virtual method that had its first argument removed and the second modified.''' + ic = MyInjectCode() + values = (1, 2, 3, 4, 5) + result = ic.callArrayMethod(values) + self.assertEqual(result, ic.multiplier * sum(values)) + + def testUsageOfTypeSystemCheckVariableOnPrimitiveType(self): + '''When the sequence item is convertible to an integer -1 is returned, or -2 if its not convertible.''' + ic = InjectCode() + values = (1, 2, 3, 4, '5', 6.7) + result = ic.arrayMethod(values) + + fixedValues = [v for v in values if isinstance(v, int)]\ + + [-1 for v in values if isinstance(v, float)]\ + + [-2 for v in values if not isinstance(v, int) and not isinstance(v, float)] + self.assertEqual(result, sum(fixedValues)) + + +class IntArrayTest(unittest.TestCase): + '''Test case for converting python sequence to int array''' + + def testBasic(self): + '''Shiboken::sequenceToIntArray - basic case''' + args = [1, 2, 3, 4] + ic = InjectCode() + self.assertEqual(sum(args) + len(args), ic.sumArrayAndLength(args)) + + def testEmpty(self): + '''Shiboken::sequenceToIntArray - empty sequence''' + args = [] + ic = InjectCode() + self.assertEqual(sum(args) + len(args), ic.sumArrayAndLength(args)) + + def testWithZero(self): + '''Shiboken::sequenceToIntArray - count only up to zero''' + args = [1, 2, 0, 3] + ic = InjectCode() + self.assertEqual(sum([1, 2]) + len([1, 2]), ic.sumArrayAndLength(args)) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/innerclass_test.py b/sources/shiboken2/tests/samplebinding/innerclass_test.py new file mode 100644 index 000000000..0df636857 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/innerclass_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Derived + +class TestInnerClass(unittest.TestCase): + def testInstaciate(self): + d = Derived.SomeInnerClass() + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/intlist_test.py b/sources/shiboken2/tests/samplebinding/intlist_test.py new file mode 100644 index 000000000..6d21ef053 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/intlist_test.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 IntList + +class IntListTest(unittest.TestCase): + + def testAutoFunctionsToBaseList(self): + lst = IntList() + self.assertEqual(len(lst), 0) + lst.append(10) + self.assertEqual(lst[0], 10) + lst.append(20) + self.assertEqual(lst[1], 20) + lst.append(30) + self.assertEqual(lst[2], 30) + lst[1] = 25 + self.assertEqual(lst[0], 10) + self.assertEqual(lst[1], 25) + self.assertEqual(lst[2], 30) + self.assertEqual(len(lst), 3) + + def testIntListCtor_NoParams(self): + '''IntList constructor receives no parameter.''' + il = IntList() + self.assertEqual(len(il), 0) + self.assertEqual(il.constructorUsed(), IntList.NoParamsCtor) + + def testIntListCtor_int(self): + '''IntList constructor receives an integer.''' + value = 123 + il = IntList(value) + self.assertEqual(len(il), 1) + self.assertEqual(il[0], value) + self.assertEqual(il.constructorUsed(), IntList.IntCtor) + + def testIntListCtor_IntList(self): + '''IntList constructor receives an IntList object.''' + il1 = IntList(123) + il2 = IntList(il1) + self.assertEqual(len(il1), len(il2)) + for i in range(len(il1)): + self.assertEqual(il1[i], il2[i]) + self.assertEqual(il2.constructorUsed(), IntList.CopyCtor) + + def testIntListCtor_ListOfInts(self): + '''IntList constructor receives an integer list.''' + ints = [123, 456] + il = IntList(ints) + self.assertEqual(len(il), len(ints)) + for i in range(len(il)): + self.assertEqual(il[i], ints[i]) + self.assertEqual(il.constructorUsed(), IntList.ListOfIntCtor) + + def testIntListAttributeTypeCheck(self): + '''Attribute values to IntList.''' + il = IntList([0, 1, 2]) + self.assertEqual(len(il), 3) + il[0] = 123 + self.assertEqual(len(il), 3) + self.assertEqual(il[0], 123) + il[1] = 432.1 + self.assertEqual(len(il), 3) + self.assertEqual(il[1], int(432.1)) + self.assertRaises(TypeError, il.__setitem__, 2, '78') + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/invalid_virtual_return_test.py b/sources/shiboken2/tests/samplebinding/invalid_virtual_return_test.py new file mode 100644 index 000000000..f160f1e07 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/invalid_virtual_return_test.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 case for returning invalid types in a virtual function''' + +import unittest +from sample import ObjectModel, ObjectType, ObjectView + +import warnings + + +class MyObject(ObjectType): + pass + + +class ListModelWrong(ObjectModel): + + def __init__(self, parent=None): + ObjectModel.__init__(self, parent) + self.obj = 0 + + def data(self): + warnings.simplefilter('error') + # Shouldn't segfault. Must set TypeError + return self.obj + + +class ModelWrongReturnTest(unittest.TestCase): + + def testWrongTypeReturn(self): + model = ListModelWrong() + view = ObjectView(model) + self.assertRaises(RuntimeWarning, view.getRawModelData) # calls model.data() + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/keep_reference_test.py b/sources/shiboken2/tests/samplebinding/keep_reference_test.py new file mode 100644 index 000000000..a8f63f6df --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/keep_reference_test.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 case for objects that keep references to other object without owning them (e.g. model/view relationships).''' + +import unittest +from sys import getrefcount + +from sample import ObjectModel, ObjectView + +class TestKeepReference(unittest.TestCase): + '''Test case for objects that keep references to other object without owning them (e.g. model/view relationships).''' + + def testReferenceCounting(self): + '''Tests reference count of model-like object referred by view-like objects.''' + model1 = ObjectModel() + refcount1 = getrefcount(model1) + view1 = ObjectView() + view1.setModel(model1) + self.assertEqual(getrefcount(view1.model()), refcount1 + 1) + + view2 = ObjectView() + view2.setModel(model1) + self.assertEqual(getrefcount(view2.model()), refcount1 + 2) + + model2 = ObjectModel() + view2.setModel(model2) + self.assertEqual(getrefcount(view1.model()), refcount1 + 1) + + def testReferenceCountingWhenDeletingReferrer(self): + '''Tests reference count of model-like object referred by deceased view-like object.''' + model = ObjectModel() + refcount1 = getrefcount(model) + view = ObjectView() + view.setModel(model) + self.assertEqual(getrefcount(view.model()), refcount1 + 1) + + del view + self.assertEqual(getrefcount(model), refcount1) + + def testReferreedObjectSurvivalAfterContextEnd(self): + '''Model-like object assigned to a view-like object must survive after get out of context.''' + def createModelAndSetToView(view): + model = ObjectModel() + model.setObjectName('created model') + view.setModel(model) + view = ObjectView() + createModelAndSetToView(view) + model = view.model() + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/list_test.py b/sources/shiboken2/tests/samplebinding/list_test.py new file mode 100644 index 000000000..22cb4c04b --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/list_test.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 std::list container conversions''' + +import unittest + +from sample import ListUser, Point, PointF + +class ExtendedListUser(ListUser): + def __init__(self): + ListUser.__init__(self) + self.create_list_called = False + + def createList(self): + self.create_list_called = True + return [2, 3, 5, 7, 13] + +class ListConversionTest(unittest.TestCase): + '''Test case for std::list container conversions''' + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a virtual method is correctly called from C++.''' + lu = ExtendedListUser() + lst = lu.callCreateList() + self.assertTrue(lu.create_list_called) + self.assertEqual(type(lst), list) + for item in lst: + self.assertEqual(type(item), int) + + def testPrimitiveConversionInsideContainer(self): + '''Test primitive type conversion inside conversible std::list container.''' + cpx0 = complex(1.2, 3.4) + cpx1 = complex(5.6, 7.8) + lst = ListUser.createComplexList(cpx0, cpx1) + self.assertEqual(type(lst), list) + for item in lst: + self.assertEqual(type(item), complex) + self.assertEqual(lst, [cpx0, cpx1]) + + def testSumListIntegers(self): + '''Test method that sums a list of integer values.''' + lu = ListUser() + lst = [3, 5, 7] + result = lu.sumList(lst) + self.assertEqual(result, sum(lst)) + + def testSumListFloats(self): + '''Test method that sums a list of float values.''' + lu = ListUser() + lst = [3.3, 4.4, 5.5] + result = lu.sumList(lst) + self.assertEqual(result, sum(lst)) + + def testConversionInBothDirections(self): + '''Test converting a list from Python to C++ and back again.''' + lu = ListUser() + lst = [3, 5, 7] + lu.setList(lst) + result = lu.getList() + self.assertEqual(result, lst) + + def testConversionInBothDirectionsWithSimilarContainer(self): + '''Test converting a tuple, instead of the expected list, from Python to C++ and back again.''' + lu = ListUser() + lst = (3, 5, 7) + lu.setList(lst) + result = lu.getList() + self.assertNotEqual(result, lst) + self.assertEqual(result, list(lst)) + + def testConversionOfListOfObjectsPassedAsArgument(self): + '''Calls method with a Python list of wrapped objects to be converted to a C++ list.''' + mult = 3 + pts0 = (Point(1.0, 2.0), Point(3.3, 4.4), Point(5, 6)) + pts1 = (Point(1.0, 2.0), Point(3.3, 4.4), Point(5, 6)) + ListUser.multiplyPointList(pts1, mult) + for pt0, pt1 in zip(pts0, pts1): + self.assertEqual(pt0.x() * mult, pt1.x()) + self.assertEqual(pt0.y() * mult, pt1.y()) + + def testConversionOfInvalidLists(self): + mult = 3 + pts = (Point(1.0, 2.0), 3, Point(5, 6)) + self.assertRaises(TypeError, ListUser.multiplyPointList, pts, mult) + + def testOverloadMethodReceivingRelatedContainerTypes(self): + self.assertEqual(ListUser.ListOfPointF, ListUser.listOfPoints([PointF()])) + self.assertEqual(ListUser.ListOfPoint, ListUser.listOfPoints([Point()])) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/lock_test.py b/sources/shiboken2/tests/samplebinding/lock_test.py new file mode 100644 index 000000000..35bf5149d --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/lock_test.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python + +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Simple test with a blocking C++ method that should allow python + threads to run.''' + +import unittest +import threading + +from sample import Bucket + + +class Unlocker(threading.Thread): + + def __init__(self, bucket): + threading.Thread.__init__(self) + self.bucket = bucket + + def run(self): + while not self.bucket.locked(): + pass + + self.bucket.unlock() + + +class MyBucket(Bucket): + + def __init__(self): + Bucket.__init__(self) + + def virtualBlockerMethod(self): + self.lock() + return True + + +class TestLockUnlock(unittest.TestCase): + + def testBasic(self): + '''Locking in C++ and releasing in a python thread''' + bucket = Bucket() + unlocker = Unlocker(bucket) + + unlocker.start() + bucket.lock() + unlocker.join() + + def testVirtualBlocker(self): + '''Same as the basic case but blocker method is a C++ virtual called from C++.''' + bucket = Bucket() + unlocker = Unlocker(bucket) + + unlocker.start() + result = bucket.callVirtualBlockerMethodButYouDontKnowThis() + unlocker.join() + self.assertTrue(result) + + def testReimplementedVirtualBlocker(self): + '''Same as the basic case but blocker method is a C++ virtual reimplemented in Python and called from C++.''' + mybucket = MyBucket() + unlocker = Unlocker(mybucket) + + unlocker.start() + result = mybucket.callVirtualBlockerMethodButYouDontKnowThis() + unlocker.join() + self.assertTrue(result) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/map_test.py b/sources/shiboken2/tests/samplebinding/map_test.py new file mode 100644 index 000000000..18cefd857 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/map_test.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 std::map container conversions''' + +import unittest + +from sample import MapUser + +class ExtendedMapUser(MapUser): + def __init__(self): + MapUser.__init__(self) + self.create_map_called = False + + def createMap(self): + self.create_map_called = True + return {'two' : (complex(2.2, 2.2), 2), + 'three' : (complex(3.3, 3.3), 3), + 'five' : (complex(5.5, 5.5), 5), + 'seven' : (complex(7.7, 7.7), 7)} + +class MapConversionTest(unittest.TestCase): + '''Test case for std::map container conversions''' + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a virtual method is correctly called from C++.''' + mu = ExtendedMapUser() + map_ = mu.callCreateMap() + self.assertTrue(mu.create_map_called) + self.assertEqual(type(map_), dict) + for key, value in map_.items(): + self.assertEqual(type(key), str) + self.assertEqual(type(value[0]), complex) + self.assertEqual(type(value[1]), int) + + def testConversionInBothDirections(self): + '''Test converting a map from Python to C++ and back again.''' + mu = MapUser() + map_ = {'odds' : [2, 4, 6], 'evens' : [3, 5, 7], 'primes' : [3, 4, 6]} + mu.setMap(map_) + result = mu.getMap() + self.assertEqual(result, map_) + + def testConversionMapIntKeyValueTypeValue(self): + '''C++ signature: MapUser::passMapIntValueType(const std::map&)''' + mu = MapUser() + map_ = {0 : 'string'} + result = mu.passMapIntValueType(map_) + self.assertEqual(map_, result) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/metaclass_test.py b/sources/shiboken2/tests/samplebinding/metaclass_test.py new file mode 100644 index 000000000..972a2f17d --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/metaclass_test.py @@ -0,0 +1,61 @@ +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +from sample import * +import unittest + +class MetaA(type): + pass + +class A(object): + __metaclass__ = MetaA + +MetaB = type(Point) +B = Point + +class MetaC(MetaA, MetaB): + pass +class C(A, B): + __metaclass__ = MetaC + +class D(C): + pass + +class TestMetaClass(unittest.TestCase): + def testIt(self): + w1 = C() # works + w1.setX(1) + w1.setY(2) + + w2 = D() # should work! + w2.setX(3) + w2.setY(4) + + w3 = w1 + w2 + self.assertEqual(w3.x(), 4) + self.assertEqual(w3.y(), 6) diff --git a/sources/shiboken2/tests/samplebinding/mi_virtual_methods_test.py b/sources/shiboken2/tests/samplebinding/mi_virtual_methods_test.py new file mode 100644 index 000000000..0905dead9 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/mi_virtual_methods_test.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 virtual methods in multiple inheritance scenarios''' + +import unittest + +from sample import VirtualMethods, ObjectType, Event + + +class ImplementsNone(ObjectType, VirtualMethods): + '''Implements no virtual methods''' + + def __init__(self): + ObjectType.__init__(self) + VirtualMethods.__init__(self) + + +class ImplementsBoth(ObjectType, VirtualMethods): + '''Implements ObjectType.event and VirtualMethods.sum1''' + + def __init__(self): + ObjectType.__init__(self) + VirtualMethods.__init__(self) + self.event_processed = False + + def event(self, event): + self.event_processed = True + return True + + def sum1(self, arg0, arg1, arg2): + return (arg0 + arg1 + arg2) * 2 + + +class CppVirtualTest(unittest.TestCase): + '''Virtual method defined in c++ called from C++''' + + def testCpp(self): + '''C++ calling C++ virtual method in multiple inheritance scenario''' + obj = ImplementsNone() + self.assertTrue(ObjectType.processEvent([obj], Event(Event.BASIC_EVENT))) + self.assertRaises(AttributeError, getattr, obj, 'event_processed') + + self.assertEqual(obj.callSum0(1, 2, 3), 6) + + +class PyVirtualTest(unittest.TestCase): + '''Virtual method reimplemented in python called from C++''' + + def testEvent(self): + '''C++ calling Python reimplementation of virtual in multiple inheritance''' + obj = ImplementsBoth() + self.assertTrue(ObjectType.processEvent([obj], Event(Event.BASIC_EVENT))) + self.assertTrue(obj.event_processed) + + self.assertEqual(obj.callSum1(1, 2, 3), 12) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/mixed_mi_test.py b/sources/shiboken2/tests/samplebinding/mixed_mi_test.py new file mode 100644 index 000000000..b6268cf2c --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/mixed_mi_test.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 multiple inheritance in mixed Python/C++ scenarios''' + +import unittest + +from sample import ObjectType + + +class Base(object): + '''Base Python class''' + + def __init__(self): + self.name = '' + + def pythonName(self): + return self.name + + def setPythonName(self, name): + self.name = name + + +class Child(Base, ObjectType): + '''Dummy class with mixed parents''' + + def __init__(self): + Base.__init__(self) + ObjectType.__init__(self) + + +class MixedInheritanceTest(unittest.TestCase): + + def testMixed(self): + '''Mixed Python/C++ multiple inheritance''' + obj = Child() + + obj.setObjectName('aaa') + self.assertEqual(obj.objectName(), 'aaa') + + obj.setPythonName('python') + self.assertEqual(obj.pythonName(), 'python') + + +if __name__ == '__main__': + unittest.main() + + diff --git a/sources/shiboken2/tests/samplebinding/modelindex_test.py b/sources/shiboken2/tests/samplebinding/modelindex_test.py new file mode 100644 index 000000000..5dd7d3bc7 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/modelindex_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 ModelIndex, ReferentModelIndex, PersistentModelIndex + +class TestCastOperator(unittest.TestCase): + + def testCastOperatorReturningValue(self): + index = PersistentModelIndex() + index.setValue(123) + self.assertEqual(index.value(), 123) + self.assertEqual(index.value(), ModelIndex.getValue(index)) + + def testCastOperatorReturningReference(self): + index = ReferentModelIndex() + index.setValue(123) + self.assertEqual(index.value(), 123) + self.assertEqual(index.value(), ModelIndex.getValue(index)) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/modelview_test.py b/sources/shiboken2/tests/samplebinding/modelview_test.py new file mode 100644 index 000000000..081de303d --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/modelview_test.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 case for objects that keep references to other object without owning them (e.g. model/view relationships).''' + +import unittest +from sample import ObjectModel, ObjectType, ObjectView + + +object_name = 'test object' + +class MyObject(ObjectType): + pass + +class ListModelKeepsReference(ObjectModel): + def __init__(self, parent=None): + ObjectModel.__init__(self, parent) + self.obj = MyObject() + self.obj.setObjectName(object_name) + + def data(self): + return self.obj + +class ListModelDoesntKeepsReference(ObjectModel): + def data(self): + obj = MyObject() + obj.setObjectName(object_name) + return obj + + +class ModelViewTest(unittest.TestCase): + + def testListModelDoesntKeepsReference(self): + model = ListModelDoesntKeepsReference() + view = ObjectView(model) + obj = view.getRawModelData() + self.assertEqual(type(obj), MyObject) + self.assertEqual(obj.objectName(), object_name) + + def testListModelKeepsReference(self): + model = ListModelKeepsReference() + view = ObjectView(model) + obj = view.getRawModelData() + self.assertEqual(type(obj), MyObject) + self.assertEqual(obj.objectName(), object_name) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/modifications_test.py b/sources/shiboken2/tests/samplebinding/modifications_test.py new file mode 100644 index 000000000..44748dc8c --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/modifications_test.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 method modifications performed as described on type system. ''' + +import unittest + +from sample import Modifications, Point, ByteArray + +class ExtModifications(Modifications): + def __init__(self): + Modifications.__init__(self) + self.multiplier = 3.0 + self.increment = 10.0 + + def name(self): + return 'ExtModifications' + + def differenceOfPointCoordinates(self, point): + ok, res = Modifications.differenceOfPointCoordinates(self, point) + return ok, res * self.multiplier + self.increment + + +class ModificationsTest(unittest.TestCase): + '''Test cases for method modifications performed as described on type system. ''' + + def setUp(self): + self.mods = Modifications() + + def tearDown(self): + del self.mods + + def testClassMembersAvailability(self): + '''Test if Modified class really have the expected members.''' + expected_members = set(['OverloadedModFunc', 'OverloadedNone', + 'Overloaded_ibiP', 'Overloaded_ibib', + 'Overloaded_ibid', 'Overloaded_ibii', + 'calculateArea', 'doublePlus', 'increment', + 'multiplyPointCoordsPlusValue', 'name', + 'pointToPair', 'overloaded', 'power', + 'timesTen']) + self.assertTrue(expected_members.issubset(dir(Modifications))) + + def testRenamedMethodAvailability(self): + '''Test if Modification class really have renamed the 'className' virtual method to 'name'.''' + self.assertTrue('className' not in dir(Modifications)) + self.assertTrue('name' in dir(Modifications)) + + def testReimplementationOfRenamedVirtualMethod(self): + '''Test if class inheriting from Modification class have the reimplementation of renamed virtual method called.''' + em = ExtModifications() + self.assertEqual(self.mods.name(), 'Modifications') + self.assertEqual(em.name(), 'ExtModifications') + + def testRegularMethodRenaming(self): + '''Test if Modifications::cppMultiply was correctly renamed to calculateArea.''' + self.assertTrue('cppMultiply' not in dir(Modifications)) + self.assertTrue('calculateArea' in dir(Modifications)) + self.assertEqual(self.mods.calculateArea(3, 6), 3 * 6) + + def testRegularMethodRemoval(self): + '''Test if 'Modifications::exclusiveCppStuff' was removed from Python bindings.''' + self.assertTrue('exclusiveCppStuff' not in dir(Modifications)) + + def testArgumentRemoval(self): + '''Test if second argument of Modifications::doublePlus(int, int) was removed.''' + self.assertRaises(TypeError, self.mods.doublePlus, 3, 7) + self.assertEqual(self.mods.doublePlus(7), 14) + + def testDefaultValueRemoval(self): + '''Test if default value was removed from first argument of Modifications::increment(int).''' + self.assertRaises(TypeError, self.mods.increment) + self.assertEqual(self.mods.increment(7), 8) + + def testDefaultValueReplacement(self): + '''Test if default values for both arguments of Modifications::power(int, int) were modified.''' + # original default values: int power(int base = 1, int exponent = 0); + self.assertNotEqual(self.mods.power(4), 1) + # modified default values: int power(int base = 2, int exponent = 1); + self.assertEqual(self.mods.power(), 2) + self.assertEqual(self.mods.power(3), 3) + self.assertEqual(self.mods.power(5, 3), 5**3) + + def testSetNewDefaultValue(self): + '''Test if default value was correctly set to 10 for first argument of Modifications::timesTen(int).''' + self.assertEqual(self.mods.timesTen(7), 70) + self.assertEqual(self.mods.timesTen(), 100) + + def testArgumentRemovalAndReturnTypeModificationWithTypesystemTemplates1(self): + '''Test modifications to method signature and return value using type system templates (case 1).''' + result, ok = self.mods.pointToPair(Point(2, 5)) + self.assertEqual(type(ok), bool) + self.assertEqual(type(result), tuple) + self.assertEqual(len(result), 2) + self.assertEqual(type(result[0]), float) + self.assertEqual(type(result[1]), float) + self.assertEqual(result[0], 2.0) + self.assertEqual(result[1], 5.0) + + def testArgumentRemovalAndReturnTypeModificationWithTypesystemTemplates2(self): + '''Test modifications to method signature and return value using type system templates (case 2).''' + result, ok = self.mods.multiplyPointCoordsPlusValue(Point(2, 5), 4.1) + self.assertEqual(type(ok), bool) + self.assertEqual(type(result), float) + self.assertEqual(result, 14.1) + + def testOverloadedMethodModifications(self): + '''Tests modifications to an overloaded method''' + # overloaded(int, bool[removed], int, double) + self.assertEqual(self.mods.overloaded(1, 2, 3.1), Modifications.Overloaded_ibid) + # overloaded(int, bool, int[removed,default=321], int) + self.assertEqual(self.mods.overloaded(1, True, 2), Modifications.Overloaded_ibii) + # the others weren't modified + self.assertEqual(self.mods.overloaded(1, True, 2, False), Modifications.Overloaded_ibib) + self.assertEqual(self.mods.overloaded(1, False, 2, Point(3, 4)), Modifications.Overloaded_ibiP) + self.assertRaises(TypeError, self.mods.overloaded, 1, True, Point(2, 3), Point(4, 5)) + self.assertEqual(self.mods.over(1, True, Point(2, 3), Point(4, 5)), Modifications.Overloaded_ibPP) + + def testPointArrayModification(self): + points = (Point(1, 1), Point(2, 2)) + summedPoint = Point(1, 1) + Point(2, 2) + self.assertEqual(self.mods.sumPointArray(points), summedPoint) + + def testTypeSystemVariableReplacementInFunctionModification(self): + ba = ByteArray('12345') + self.assertEqual(self.mods.getSize(ba), len(ba)) + self.assertEqual(self.mods.getSize(ba, 20), 20) + + def testNoNulPointerTag(self): + point = Point(12, 34) + self.assertEqual(self.mods.sumPointCoordinates(point), 12 + 34) + self.assertRaises(TypeError, self.mods.sumPointCoordinates, None) + + def testNonConversionRuleForArgumentWithDefaultValue(self): + status, obj = self.mods.nonConversionRuleForArgumentWithDefaultValue() + self.assertTrue(status) + self.assertEqual(obj, self.mods.getObject()) + self.assertEqual(obj.objectName(), 'MyObject') + + def testInjectCodeWithConversionVariableForUserPrimitive(self): + self.assertTrue(Modifications.invertBoolean(False)) + self.assertFalse(Modifications.invertBoolean(True)) + + def testConversionRuleForReturnType(self): + x, y = 11, 2 + diff = float(abs(x - y)) + point = Point(x, y) + + ok, res = self.mods.differenceOfPointCoordinates(point) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, diff) + + ok, res = self.mods.callDifferenceOfPointCoordinates(point) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, diff) + + ok, res = self.mods.differenceOfPointCoordinates(None) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, 0.0) + + ok, res = self.mods.callDifferenceOfPointCoordinates(None) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, 0.0) + + def testConversionRuleForReturnTypeOnExtendedClass(self): + x, y = 11, 2 + diff = float(abs(x - y)) + point = Point(x, y) + em = ExtModifications() + + ok, res = em.differenceOfPointCoordinates(point) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, diff * em.multiplier + em.increment) + + ok, res = em.callDifferenceOfPointCoordinates(point) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, diff * em.multiplier + em.increment) + + ok, res = em.differenceOfPointCoordinates(None) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, em.increment) + + ok, res = em.callDifferenceOfPointCoordinates(None) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, em.increment) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/modified_constructor_test.py b/sources/shiboken2/tests/samplebinding/modified_constructor_test.py new file mode 100644 index 000000000..859f89452 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/modified_constructor_test.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests cases for ConstructorWithModifiedArgument class.''' + +import sys +import unittest + +from sample import * + + +class ConstructorWithModifiedArgumentTest(unittest.TestCase): + '''Test cases for ConstructorWithModifiedArgument class.''' + + def testConstructorWithModifiedArgument(self): + sampleClass = ModifiedConstructor("10") + self.assertTrue(sampleClass.retrieveValue(), 10) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/modifiedvirtualmethods_test.py b/sources/shiboken2/tests/samplebinding/modifiedvirtualmethods_test.py new file mode 100644 index 000000000..3121a9cc2 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/modifiedvirtualmethods_test.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 modified virtual methods.''' + +import unittest + +from sample import VirtualMethods, Str + +class ExtendedVirtualMethods(VirtualMethods): + def __init__(self): + VirtualMethods.__init__(self) + self.name_called = False + self.sum0_called = False + self.sum1_called = False + self.sum2_called = False + self.sum3_called = False + self.sum4_called = False + self.sumThree_called = False + self.callMe_called = 0 + self.multiplier = 12345 + + def sum0(self, a0, a1, a2): + self.sum0_called = True + return VirtualMethods.sumThree(self, a0, a1, a2) * self.multiplier + + def sumThree(self, a0, a1, a2): + self.sumThree_called = True + return VirtualMethods.sumThree(self, a0, a1, a2) * self.multiplier + + def sum1(self, a0, a1, a2): + self.sum1_called = True + return VirtualMethods.sum1(self, a0, a1, a2) * self.multiplier + + def sum2(self, a0, a1): + self.sum2_called = True + return VirtualMethods.sum2(self, a0, a1) * self.multiplier + + def sum3(self, a0, a1): + self.sum3_called = True + return VirtualMethods.sum3(self, a0, a1) * self.multiplier + + def sum4(self, a0, a1): + self.sum4_called = True + return VirtualMethods.sum4(self, a0, a1) * self.multiplier + + def name(self): + self.name_called = True + return Str('ExtendedVirtualMethods') + + def callMe(self): + self.callMe_called += 1 + + def getMargins(self): + return tuple([m*2 for m in VirtualMethods.getMargins(self)]) + + +class VirtualMethodsTest(unittest.TestCase): + '''Test case for modified virtual methods.''' + + def setUp(self): + self.vm = VirtualMethods() + self.evm = ExtendedVirtualMethods() + + def tearDown(self): + del self.vm + del self.evm + + def testModifiedVirtualMethod0(self): + '''Renamed virtual method.''' + a0, a1, a2 = 2, 3, 5 + result0 = self.vm.callSum0(a0, a1, a2) + result1 = self.vm.sumThree(a0, a1, a2) + self.assertEqual(result0, a0 + a1 + a2) + self.assertEqual(result0, result1) + self.assertRaises(AttributeError, getattr, self.vm, 'sum0') + + def testReimplementedModifiedVirtualMethod0(self): + '''Override of a renamed virtual method.''' + a0, a1, a2 = 2, 3, 5 + result0 = self.vm.callSum0(a0, a1, a2) + result1 = self.vm.sumThree(a0, a1, a2) + result2 = self.evm.callSum0(a0, a1, a2) + self.assertEqual(result0, result1) + self.assertEqual(result0 * self.evm.multiplier, result2) + self.assertTrue(self.evm.sumThree_called) + self.assertFalse(self.evm.sum0_called) + + def testModifiedVirtualMethod1(self): + '''Virtual method with three arguments and the last one + changed to have the default value set to 1000.''' + a0, a1, a2 = 2, 3, 5 + result0 = self.vm.sum1(a0, a1) + self.assertEqual(result0, a0 + a1 + 1000) + result1 = self.vm.sum1(a0, a1, a2) + result2 = self.vm.callSum1(a0, a1, a2) + self.assertEqual(result1, result2) + + def testReimplementedModifiedVirtualMethod1(self): + '''Override of the virtual method with three arguments and + the last one changed to have the default value set to 1000.''' + a0, a1 = 2, 3 + result0 = self.vm.sum1(a0, a1) + result1 = self.evm.callSum1(a0, a1, 1000) + self.assertEqual(result0 * self.evm.multiplier, result1) + self.assertTrue(self.evm.sum1_called) + + def testModifiedVirtualMethod2(self): + '''Virtual method originally with three arguments, the last + one was removed and the default value set to 2000.''' + a0, a1 = 1, 2 + result0 = self.vm.sum2(a0, a1) + self.assertEqual(result0, a0 + a1 + 2000) + result1 = self.vm.sum2(a0, a1) + result2 = self.vm.callSum2(a0, a1, 2000) + self.assertEqual(result1, result2) + self.assertRaises(TypeError, self.vm.sum2, 1, 2, 3) + + def testReimplementedModifiedVirtualMethod2(self): + '''Override of the virtual method originally with three arguments, + the last one was removed and the default value set to 2000.''' + a0, a1 = 1, 2 + ignored = 54321 + result0 = self.vm.sum2(a0, a1) + result1 = self.evm.callSum2(a0, a1, ignored) + self.assertEqual(result0 * self.evm.multiplier, result1) + self.assertTrue(self.evm.sum2_called) + + def testModifiedVirtualMethod3(self): + '''Virtual method originally with three arguments have the second + one removed and replaced by custom code that replaces it by the sum + of the first and the last arguments.''' + a0, a1 = 1, 2 + result0 = self.vm.sum3(a0, a1) + self.assertEqual(result0, a0 + (a0 + a1) + a1) + result1 = self.vm.callSum3(a0, 10, a1) + self.assertNotEqual(result0, result1) + result2 = self.vm.callSum3(a0, a0 + a1, a1) + self.assertEqual(result0, result2) + self.assertRaises(TypeError, self.vm.sum3, 1, 2, 3) + + def testReimplementedModifiedVirtualMethod3(self): + '''Override of the virtual method originally with three arguments + have the second one removed and replaced by custom code that + replaces it by the sum of the first and the last arguments.''' + a0, a1 = 1, 2 + ignored = 54321 + result0 = self.vm.sum3(a0, a1) + result1 = self.evm.callSum3(a0, ignored, a1) + self.assertEqual(result0 * self.evm.multiplier, result1) + self.assertTrue(self.evm.sum3_called) + + def testModifiedVirtualMethod4(self): + '''Virtual method originally with three arguments, the + last one was removed and the default value set to 3000.''' + a0, a1 = 1, 2 + default_value = 3000 + result0 = self.vm.sum4(a0, a1) + self.assertEqual(result0, a0 + default_value + a1) + removed_arg_value = 100 + result1 = self.vm.callSum4(a0, removed_arg_value, a1) + self.assertEqual(result1, a0 + removed_arg_value + a1) + self.assertRaises(TypeError, self.vm.sum4, 1, 2, 3) + + def testReimplementedModifiedVirtualMethod4(self): + '''Override of the virtual method originally with three arguments, + the last one was removed and the default value set to 3000. + The method was modified with code injection on the binding override + (the one that receives calls from C++ with the original signature + and forwards it to Python overrides) that subtracts the value of the + second argument (removed in Python) from the value of the first + before sending them to Python.''' + a0, a1 = 1, 2 + removed_arg_value = 2011 + default_value = 3000 + result = self.evm.callSum4(a0, removed_arg_value, a1) + self.assertEqual(result, (a0 - removed_arg_value + a1 + default_value) * self.evm.multiplier) + self.assertTrue(self.evm.sum4_called) + + def testOverridenMethodResultModification(self): + '''Injected code modifies the result of a call to a virtual + method overridden in Python.''' + orig_name = self.vm.callName() + self.assertEqual(orig_name, 'VirtualMethods') + name = self.evm.callName() + self.assertEqual(name, 'PimpedExtendedVirtualMethods') + self.assertEqual(name, Str('PimpedExtendedVirtualMethods')) + self.assertTrue(self.evm.name_called) + + def testInjectCodeCallsPythonVirtualMethodOverride(self): + '''When injected code calls the Python override by itself + no code for the method call should be generated.''' + self.evm.callCallMe() + self.assertEqual(self.evm.callMe_called, 1) + + def testAllArgumentsRemoved(self): + values = (10, 20, 30, 40) + self.vm.setMargins(*values) + self.assertEqual(self.vm.getMargins(), values) + + def testAllArgumentsRemovedCallVirtual(self): + values = (10, 20, 30, 40) + self.vm.setMargins(*values) + self.assertEqual(self.vm.callGetMargins(), values) + + def testExtendedAllArgumentsRemoved(self): + values = (10, 20, 30, 40) + self.evm.setMargins(*values) + double = tuple([m*2 for m in values]) + self.assertEqual(self.evm.getMargins(), double) + + def testExtendedAllArgumentsRemovedCallVirtual(self): + values = (10, 20, 30, 40) + self.evm.setMargins(*values) + double = tuple([m*2 for m in values]) + self.assertEqual(self.evm.callGetMargins(), double) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/multi_cpp_inheritance_test.py b/sources/shiboken2/tests/samplebinding/multi_cpp_inheritance_test.py new file mode 100644 index 000000000..6546c3ac6 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/multi_cpp_inheritance_test.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 multiple inheritance''' + +import sys +import unittest + +from sample import * + +class SimpleUseCase(ObjectType, Str): + def __init__(self, name): + ObjectType.__init__(self) + Str.__init__(self, name) + +class SimpleUseCaseReverse(Str, ObjectType): + def __init__(self, name): + ObjectType.__init__(self) + Str.__init__(self, name) + +class SimpleUseCase2(SimpleUseCase): + def __init__(self, name): + SimpleUseCase.__init__(self, name) + +class ComplexUseCase(SimpleUseCase2, Point): + def __init__(self, name): + SimpleUseCase2.__init__(self, name) + Point.__init__(self) + +class ComplexUseCaseReverse(Point, SimpleUseCase2): + def __init__(self, name): + SimpleUseCase2.__init__(self, name) + Point.__init__(self) + +class MultipleCppDerivedTest(unittest.TestCase): + def testInstanciation(self): + s = SimpleUseCase("Hi") + self.assertEqual(s, "Hi") + s.setObjectName(s) + self.assertEqual(s.objectName(), "Hi") + + def testInstanciation2(self): + s = SimpleUseCase2("Hi") + self.assertEqual(s, "Hi") + s.setObjectName(s) + self.assertEqual(s.objectName(), "Hi") + + def testComplexInstanciation(self): + c = ComplexUseCase("Hi") + self.assertEqual(c, "Hi") + c.setObjectName(c) + self.assertEqual(c.objectName(), "Hi") + c.setX(2); + self.assertEqual(c.x(), 2) + +class MultipleCppDerivedReverseTest(unittest.TestCase): + def testInstanciation(self): + s = SimpleUseCaseReverse("Hi") + self.assertEqual(s, "Hi") + s.setObjectName(s) + self.assertEqual(s.objectName(), "Hi") + + def testInstanciation2(self): + s = SimpleUseCase2("Hi") + self.assertEqual(s, "Hi") + s.setObjectName(s) + self.assertEqual(s.objectName(), "Hi") + + def testComplexInstanciation(self): + c = ComplexUseCaseReverse("Hi") + c.setObjectName(c) + self.assertEqual(c.objectName(), "Hi") + c.setX(2); + self.assertEqual(c, Point(2, 0)) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/multiple_derived_test.py b/sources/shiboken2/tests/samplebinding/multiple_derived_test.py new file mode 100644 index 000000000..e84cc76fd --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/multiple_derived_test.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 multiple inheritance''' + +import sys +import unittest + +from sample import Base1, Base2, Base3, Base4, Base5, Base6 +from sample import MDerived1, MDerived2, MDerived3, MDerived4, MDerived5, SonOfMDerived1 + +class ExtMDerived1(MDerived1): + def __init__(self): + MDerived1.__init__(self) + self.multiplier = 20 + self.base2Method_called = False + def base2Method(self): + return Base2.base2Method(self) * self.multiplier + +class MultipleDerivedTest(unittest.TestCase): + '''Test cases for multiple inheritance''' + + def testIsInstance(self): + '''MDerived1 is instance of its parents Base1 and Base2.''' + a = MDerived1() + self.assertTrue(isinstance(a, MDerived1)) + self.assertTrue(isinstance(a, Base1)) + self.assertTrue(isinstance(a, Base2)) + + def testIsSubclass(self): + '''MDerived1 is subclass of its parents Base1 and Base2.''' + self.assertTrue(issubclass(MDerived1, Base1)) + self.assertTrue(issubclass(MDerived1, Base2)) + + def testCallToFunctionWithBase1ArgumentThatCastsBackToMDerived1(self): + '''MDerived1 is passed as an Base1 argument to a method that returns it casted back to MDerived1.''' + a = MDerived1() + b = MDerived1.transformFromBase1(a) + self.assertEqual(a, b) + + def testCallToFunctionWithBase2ArgumentThatCastsBackToMDerived1(self): + '''MDerived1 is passed as an Base2 argument to a method that returns it casted back to MDerived1.''' + a = MDerived1() + b = MDerived1.transformFromBase2(a) + self.assertEqual(a, b) + + def testPythonClassIsInstance(self): + '''Python defined class ExtMDerived1 is instance of its parents MDerived1, Base1 and Base2.''' + a = ExtMDerived1() + self.assertTrue(isinstance(a, ExtMDerived1)) + self.assertTrue(isinstance(a, MDerived1)) + self.assertTrue(isinstance(a, Base1)) + self.assertTrue(isinstance(a, Base2)) + + def testPythonClassIsSubclass(self): + '''Python defined class ExtMDerived1 is subclass of its parents MDerived1, Base1 and Base2.''' + self.assertTrue(issubclass(ExtMDerived1, MDerived1)) + self.assertTrue(issubclass(ExtMDerived1, Base1)) + self.assertTrue(issubclass(ExtMDerived1, Base2)) + + def testCastFromMDerived1ToBases(self): + '''MDerived1 is casted by C++ to its parents and the binding must return the MDerived1 wrapper.''' + a = MDerived1() + refcnt = sys.getrefcount(a) + b1 = a.castToBase1() + b2 = a.castToBase2() + self.assertTrue(isinstance(b1, MDerived1)) + self.assertTrue(isinstance(b2, MDerived1)) + self.assertEqual(a, b1) + self.assertEqual(a, b2) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + + def testCastFromExtMDerived1ToMDerived1Bases(self): + '''Python defined class ExtMDerived1 is casted by C++ to MDerived1 parents and the binding must return the correct ExtMDerived1 instance.''' + a = ExtMDerived1() + refcnt = sys.getrefcount(a) + b1 = a.castToBase1() + self.assertTrue(isinstance(b1, MDerived1)) + self.assertTrue(isinstance(b1, ExtMDerived1)) + b2 = a.castToBase2() + self.assertTrue(isinstance(b2, MDerived1)) + self.assertTrue(isinstance(b2, ExtMDerived1)) + self.assertEqual(a, b1) + self.assertEqual(a, b2) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + + def testCastFromSonOfMDerived1ToBases(self): + '''SonOfMDerived1 is casted by C++ to its parents and the binding must return the SonOfMDerived1 wrapper.''' + a = SonOfMDerived1() + refcnt = sys.getrefcount(a) + md1 = a.castToMDerived1() + b1 = a.castToBase1() + b2 = a.castToBase2() + self.assertTrue(isinstance(md1, SonOfMDerived1)) + self.assertTrue(isinstance(b2, SonOfMDerived1)) + self.assertTrue(isinstance(b2, SonOfMDerived1)) + self.assertEqual(a, md1) + self.assertEqual(a, b1) + self.assertEqual(a, b2) + self.assertEqual(sys.getrefcount(a), refcnt + 3) + + def testReimplementedBase2VirtualMethodOnClassInheritingFromMDerived1(self): + a = ExtMDerived1() + value = a.base2Method() + self.assertTrue(value, Base2.base2Method(a) * a.multiplier) + + def testCastFromMDerived2ToBases(self): + '''MDerived2 is casted by C++ to its parents and the binding must return the MDerived2 wrapper.''' + a = MDerived2() + refcnt = sys.getrefcount(a) + b3 = a.castToBase3() + b4 = a.castToBase4() + b5 = a.castToBase5() + b6 = a.castToBase6() + self.assertTrue(isinstance(b3, MDerived2)) + self.assertTrue(isinstance(b4, MDerived2)) + self.assertTrue(isinstance(b5, MDerived2)) + self.assertTrue(isinstance(b6, MDerived2)) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(a, b5) + self.assertEqual(a, b6) + self.assertEqual(sys.getrefcount(a), refcnt + 4) + + def testCastFromMDerived3ToBases(self): + '''MDerived3 is casted by C++ to its parents and the binding must return the MDerived3 wrapper.''' + a = MDerived3() + refcnt = sys.getrefcount(a) + md1 = a.castToMDerived1() + md2 = a.castToMDerived2() + b1 = a.castToBase1() + b2 = a.castToBase2() + b3 = a.castToBase3() + b4 = a.castToBase4() + b5 = a.castToBase5() + b6 = a.castToBase6() + self.assertTrue(isinstance(md1, MDerived3)) + self.assertTrue(isinstance(md2, MDerived3)) + self.assertTrue(isinstance(b1, MDerived3)) + self.assertTrue(isinstance(b2, MDerived3)) + self.assertTrue(isinstance(b3, MDerived3)) + self.assertTrue(isinstance(b4, MDerived3)) + self.assertTrue(isinstance(b5, MDerived3)) + self.assertTrue(isinstance(b6, MDerived3)) + self.assertEqual(a, md1) + self.assertEqual(a, md2) + self.assertEqual(a, b1) + self.assertEqual(a, b2) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(a, b5) + self.assertEqual(a, b6) + self.assertEqual(sys.getrefcount(a), refcnt + 8) + + def testCastFromMDerived4ToBases(self): + '''MDerived4 is casted by C++ to its parents and the binding must return the MDerived4 wrapper.''' + a = MDerived4() + refcnt = sys.getrefcount(a) + b3 = a.castToBase3() + b4 = a.castToBase4() + self.assertTrue(isinstance(b3, MDerived4)) + self.assertTrue(isinstance(b4, MDerived4)) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + + def testCastFromMDerived5ToBases(self): + '''MDerived5 is casted by C++ to its parents and the binding must return the MDerived5 wrapper.''' + a = MDerived5() + refcnt = sys.getrefcount(a) + b3 = a.castToBase3() + b4 = a.castToBase4() + self.assertTrue(isinstance(b3, MDerived5)) + self.assertTrue(isinstance(b4, MDerived5)) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + + def testCastFromMDerived3ToBase3(self): + '''MDerived3 is casted by C++ to Base3 grandparent using both the inherited and reimplement castToBase3 methods.''' + a = MDerived3() + refcnt = sys.getrefcount(a) + b3_reimplemented = a.castToBase3() + b3_inherited = MDerived2.castToBase3(a) + self.assertTrue(isinstance(b3_reimplemented, MDerived3)) + self.assertTrue(isinstance(b3_inherited, MDerived3)) + self.assertEqual(a, b3_reimplemented) + self.assertEqual(a, b3_inherited) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/namespace_test.py b/sources/shiboken2/tests/samplebinding/namespace_test.py new file mode 100644 index 000000000..653b9081b --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/namespace_test.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 std::map container conversions''' + +import unittest +from sample import * +from py3kcompat import IS_PY3K + +if IS_PY3K: + TYPE_STR = "class" +else: + TYPE_STR = "type" + +class TestEnumUnderNamespace(unittest.TestCase): + def testInvisibleNamespace(self): + o1 = EnumOnNamespace.Option1 + self.assertEqual(o1, 1) + +class TestClassesUnderNamespace(unittest.TestCase): + def testIt(self): + c1 = SampleNamespace.SomeClass() + e1 = SampleNamespace.SomeClass.ProtectedEnum() + c2 = SampleNamespace.SomeClass.SomeInnerClass() + e2 = SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum() + c3 = SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough() + e3 = SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum() + + def testFunctionAddedOnNamespace(self): + res = SampleNamespace.ImInsideANamespace(2, 2) + self.assertEqual(res, 4) + + def testTpNames(self): + self.assertEqual(str(SampleNamespace.SomeClass), "<%s 'sample.SampleNamespace.SomeClass'>"%TYPE_STR) + self.assertEqual(str(SampleNamespace.SomeClass.ProtectedEnum), "<%s 'sample.SampleNamespace.SomeClass.ProtectedEnum'>"%TYPE_STR) + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum'>"%TYPE_STR) + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough'>"%TYPE_STR) + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum'>"%TYPE_STR) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/newdivision_test.py b/sources/shiboken2/tests/samplebinding/newdivision_test.py new file mode 100644 index 000000000..d1a2eda75 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/newdivision_test.py @@ -0,0 +1,42 @@ +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +from __future__ import division +from sample import * +import unittest + +class TestNewDivision(unittest.TestCase): + + def testIt(self): + p = Point(4, 4) + p2 = p/2 + self.assertEqual(p2, Point(2, 2)) + +if __name__ == "__main__": + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/nondefaultctor_test.py b/sources/shiboken2/tests/samplebinding/nondefaultctor_test.py new file mode 100644 index 000000000..e38dc9455 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/nondefaultctor_test.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 ...''' + +import sys +import unittest + +from sample import NonDefaultCtor + +class DerivedNonDefaultCtor (NonDefaultCtor): + def returnMyselfVirtual(self): + return NonDefaultCtor(self.value()+1) + +class AnotherDerivedNonDefaultCtor (NonDefaultCtor): + def __init__(self, some_string): + pass + +class NonDefaultCtorTest(unittest.TestCase): + + def testNonDefaultCtor(self): + c = NonDefaultCtor(2) + # these functions returns NonDefaultCtor by value, so a PyObjecy is created every time + self.assertNotEqual(c.returnMyself(), c) + self.assertEqual(c.returnMyself().value(), 2) + self.assertNotEqual(c.returnMyself(3), c) + self.assertEqual(c.returnMyself(3).value(), 2) + self.assertNotEqual(c.returnMyself(4, c), c) + self.assertEqual(c.returnMyself(4, c).value(), 2) + + def testVirtuals(self): + c = DerivedNonDefaultCtor(3) + # these functions returns NonDefaultCtor by value, so a PyObjecy is created every time + self.assertNotEqual(c.returnMyselfVirtual(), c) + self.assertEqual(c.returnMyselfVirtual().value(), 4) + self.assertEqual(c.callReturnMyselfVirtual().value(), 4) + + def testCtorOverload(self): + c = AnotherDerivedNonDefaultCtor("testing") + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/nonzero_test.py b/sources/shiboken2/tests/samplebinding/nonzero_test.py new file mode 100644 index 000000000..7020d30a8 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/nonzero_test.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 * + +class TestNonZeroOperator(unittest.TestCase): + def testIt(self): + c = Color() + self.assertFalse(c) + c = Color(2) + self.assertTrue(c) + +if __name__ == "__main__": + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/numericaltypedef_test.py b/sources/shiboken2/tests/samplebinding/numericaltypedef_test.py new file mode 100644 index 000000000..774b7f1d1 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/numericaltypedef_test.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 SizeF + +class NumericalTypedefTest(unittest.TestCase): + + def testNumericalTypedefExact(self): + width, height = (1.1, 2.2) + size = SizeF(width, height) + self.assertEqual(size.width(), width) + self.assertEqual(size.height(), height) + + def testNumericalTypedefConvertible(self): + width, height = (1, 2) + size = SizeF(width, height) + self.assertEqual(size.width(), float(width)) + self.assertEqual(size.height(), float(height)) + + def testNumericalTypedefOfUnsignedShort(self): + self.assertEqual(SizeF.passTypedefOfUnsignedShort(123), 123) + self.assertEqual(SizeF.passTypedefOfUnsignedShort(321), 321) + self.assertNotEqual(SizeF.passTypedefOfUnsignedShort(123), 0) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/numpy_test.py b/sources/shiboken2/tests/samplebinding/numpy_test.py new file mode 100644 index 000000000..65861e864 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/numpy_test.py @@ -0,0 +1,58 @@ +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 sys + +try: + from distutils import sysconfig + if bool(sysconfig.get_config_var('Py_DEBUG')): + sys.exit(0) + import numpy +except: + sys.exit(0) + +import unittest +from sample import PointF + +class TestNumpyTypes(unittest.TestCase): + + def testNumpyConverted(self): + x, y = (0.1, 0.2) + p = PointF(float(numpy.float32(x)), float(numpy.float32(y))) + self.assertAlmostEqual(p.x(), x) + self.assertAlmostEqual(p.y(), y) + + def testNumpyAsIs(self): + x, y = (0.1, 0.2) + p = PointF(numpy.float32(x), numpy.float32(y)) + self.assertAlmostEqual(p.x(), x) + self.assertAlmostEqual(p.y(), y) + +if __name__ == "__main__": + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/objecttype_test.py b/sources/shiboken2/tests/samplebinding/objecttype_test.py new file mode 100644 index 000000000..1a06e7e08 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/objecttype_test.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests ObjectType class of object-type with privates copy constructor and = operator.''' + +import unittest +import sys + +from sample import ObjectType, Str +import shiboken2 as shiboken + + +class ObjectTypeTest(unittest.TestCase): + '''Test cases ObjectType class of object-type with privates copy constructor and = operator.''' + + def testObjectTypeSetObjectNameWithStrVariable(self): + '''ObjectType.setObjectName with Str variable as argument.''' + s = Str('object name') + o = ObjectType() + o.setObjectName(s) + self.assertEqual(str(o.objectName()), str(s)) + + def testObjectTypeSetObjectNameWithStrInstantiation(self): + '''ObjectType.setObjectName with Str instantiation as argument.''' + s = 'object name' + o = ObjectType() + o.setObjectName(Str(s)) + self.assertEqual(str(o.objectName()), s) + + def testObjectTypeSetObjectNameWithPythonString(self): + '''ObjectType.setObjectName with Python string as argument.''' + o = ObjectType() + o.setObjectName('object name') + self.assertEqual(str(o.objectName()), 'object name') + + def testNullOverload(self): + o = ObjectType() + o.setObject(None) + self.assertEqual(o.callId(), 0) + o.setNullObject(None) + self.assertEqual(o.callId(), 1) + + def testParentFromCpp(self): + o = ObjectType() + self.assertEqual(sys.getrefcount(o), 2) + o.getCppParent().setObjectName('parent') + self.assertEqual(sys.getrefcount(o), 3) + o.getCppParent().setObjectName('parent') + self.assertEqual(sys.getrefcount(o), 3) + o.getCppParent().setObjectName('parent') + self.assertEqual(sys.getrefcount(o), 3) + o.getCppParent().setObjectName('parent') + self.assertEqual(sys.getrefcount(o), 3) + o.getCppParent().setObjectName('parent') + self.assertEqual(sys.getrefcount(o), 3) + o.destroyCppParent() + self.assertEqual(sys.getrefcount(o), 2) + + def testNextInFocusChainCycle(self): + parent = ObjectType() + child = ObjectType(parent) + next_focus = child.nextInFocusChain() + + shiboken.invalidate(parent) + + def testNextInFocusChainCycleList(self): + '''As above but in for a list of objects''' + parents = [] + children = [] + focus_chains = [] + for i in range(10): + parent = ObjectType() + child = ObjectType(parent) + next_focus = child.nextInFocusChain() + parents.append(parent) + children.append(child) + focus_chains.append(next_focus) + + shiboken.invalidate(parents) + + def testClassDecref(self): + # Bug was that class PyTypeObject wasn't decrefed when instance died + before = sys.getrefcount(ObjectType) + + for i in range(1000): + obj = ObjectType() + shiboken.delete(obj) + + after = sys.getrefcount(ObjectType) + + self.assertLess(abs(before - after), 5) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/objecttype_with_named_args_test.py b/sources/shiboken2/tests/samplebinding/objecttype_with_named_args_test.py new file mode 100755 index 000000000..533b5a5d1 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/objecttype_with_named_args_test.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 ObjectType + +class NamedArgsTest(unittest.TestCase): + + def testOneArgument(self): + p = ObjectType() + o = ObjectType(parent=p) + self.assertEqual(o.parent(), p) + + def testMoreArguments(self): + o = ObjectType() + + o.setObjectSplittedName("", prefix="pys", suffix="ide") + self.assertEqual(o.objectName(), "pyside") + + o.setObjectSplittedName("", suffix="ide", prefix="pys") + self.assertEqual(o.objectName(), "pyside") + + o.setObjectNameWithSize(name="pyside", size=6) + self.assertEqual(o.objectName(), "pyside") + + o.setObjectNameWithSize(size=6, name="pyside") + self.assertEqual(o.objectName(), "pyside") + + + def testUseDefaultValues(self): + o = ObjectType() + + o.setObjectNameWithSize(size=3) + self.assertEqual(o.objectName(), "") # user prefix=' b) + self.assertEqual(a.key(), "aoperator>") + + def testPointerOpeators(self): + a = ObjectTypeOperators("a") + b = ObjectTypeOperators("b") + self.assertEqual(a + "bc", "abc") + self.assertEqual("bc" + a, "bca") + self.assertEqual("a", a) + self.assertEqual(a, "a") + + def testOperatorInjection(self): + a = ObjectTypeOperators("a") + self.assertNotEqual(a, "b") + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py b/sources/shiboken2/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py new file mode 100644 index 000000000..3f09df200 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 ObjectTypeHolder + +class TestObjectTypeReferenceAsVirtualMethodArgument(unittest.TestCase): + + def testBasic(self): + holder = ObjectTypeHolder('TheObjectFromC++') + self.assertEqual(holder.callPassObjectTypeAsReference(), 'TheObjectFromC++') + + def testExtended(self): + class Holder(ObjectTypeHolder): + def passObjectTypeAsReference(self, objectType): + return objectType.objectName().prepend(('ThisIs')) + holder = Holder('TheObjectFromC++') + self.assertEqual(holder.callPassObjectTypeAsReference(), 'ThisIsTheObjectFromC++') + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/oddbool_test.py b/sources/shiboken2/tests/samplebinding/oddbool_test.py new file mode 100644 index 000000000..3424d9dc0 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/oddbool_test.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 OddBool user's primitive type conversion.''' + +import unittest + +from sample import OddBoolUser + +class DerivedOddBoolUser (OddBoolUser): + def returnMyselfVirtual(self): + return OddBoolUser() + pass + +class OddBoolTest(unittest.TestCase): + + def testOddBoolUser(self): + obuTrue = OddBoolUser() + obuFalse = OddBoolUser() + obuTrue.setOddBool(True) + self.assertEqual(obuFalse.oddBool(), False) + self.assertEqual(obuTrue.oddBool(), True) + self.assertEqual(obuTrue.callInvertedOddBool(), False) + + self.assertEqual(obuTrue.oddBool() == True, True) + self.assertEqual(False == obuFalse.oddBool(), True) + self.assertEqual(obuTrue.oddBool() == obuFalse.oddBool(), False) + + self.assertEqual(obuFalse.oddBool() != True, True) + self.assertEqual(True != obuFalse.oddBool(), True) + self.assertEqual(obuTrue.oddBool() != obuFalse.oddBool(), True) + + def testVirtuals(self): + dobu = DerivedOddBoolUser() + self.assertEqual(dobu.invertedOddBool(), True) + + def testImplicitConversionWithUsersPrimitiveType(self): + obu = OddBoolUser(True) + self.assertTrue(obu.oddBool()) + obu = OddBoolUser(False) + self.assertFalse(obu.oddBool()) + cpx = complex(1.0, 0.0) + obu = OddBoolUser(cpx) + self.assertTrue(obu.oddBool()) + cpx = complex(0.0, 0.0) + obu = OddBoolUser(cpx) + self.assertFalse(obu.oddBool()) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/oldstyleclass_as_number_test.py b/sources/shiboken2/tests/samplebinding/oldstyleclass_as_number_test.py new file mode 100644 index 000000000..a4f52e1fe --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/oldstyleclass_as_number_test.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 +import sample +from py3kcompat import IS_PY3K + +class OldStyle: + pass + +class NewStyle(object): + pass + +class OldStyleNumber: + def __init__(self, value): + self.value = value + def __trunc__(self): + return self.value + +class NewStyleNumber(object): + def __init__(self, value): + self.value = value + def __int__(self): + return int(self.value) + def __trunc__(self): + return self.value + +class TestOldStyleClassAsNumber(unittest.TestCase): + + def testBasic(self): + '''For the sake of calibration...''' + self.assertEqual(sample.acceptInt(123), 123) + + def testOldStyleClassPassedAsInteger(self): + '''Old-style classes aren't numbers and shouldn't be accepted.''' + obj = OldStyle() + self.assertRaises(TypeError, sample.acceptInt, obj) + + def testNewStyleClassPassedAsInteger(self): + '''New-style classes aren't numbers and shouldn't be accepted.''' + obj = NewStyle() + self.assertRaises(TypeError, sample.acceptInt, obj) + + def testOldStyleClassWithNumberProtocol(self): + obj = OldStyleNumber(123) + self.assertEqual(sample.acceptInt(obj), obj.value) + + def testNewStyleClassWithNumberProtocol(self): + obj = NewStyleNumber(123) + self.assertEqual(sample.acceptInt(obj), obj.value) + +if __name__ == "__main__" and not IS_PY3K: + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/onlycopyclass_test.py b/sources/shiboken2/tests/samplebinding/onlycopyclass_test.py new file mode 100644 index 000000000..647d2cdd7 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/onlycopyclass_test.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 OnlyCopy, FriendOfOnlyCopy + +class ClassWithOnlyCopyCtorTest(unittest.TestCase): + def testGetOne(self): + obj = FriendOfOnlyCopy.createOnlyCopy(123) + self.assertEqual(type(obj), OnlyCopy) + self.assertEqual(obj.value(), 123) + + def testGetMany(self): + objs = FriendOfOnlyCopy.createListOfOnlyCopy(3) + self.assertEqual(type(objs), list) + self.assertEqual(len(objs), 3) + for value, obj in enumerate(objs): + self.assertEqual(obj.value(), value) + + def testPassAsValue(self): + obj = FriendOfOnlyCopy.createOnlyCopy(123) + self.assertEqual(obj.value(), OnlyCopy.getValue(obj)) + + def testPassAsReference(self): + obj = FriendOfOnlyCopy.createOnlyCopy(123) + self.assertEqual(obj.value(), OnlyCopy.getValueFromReference(obj)) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/overflow_test.py b/sources/shiboken2/tests/samplebinding/overflow_test.py new file mode 100644 index 000000000..8a0fff45d --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/overflow_test.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 case for overflowing C++ numeric types.''' + +import sys +import unittest + +from sample import * +from py3kcompat import IS_PY3K, long + +class OverflowTest(unittest.TestCase): + '''Test case for overflowing C++ numeric types.''' + + def testUnsignedInt(self): + '''C++ function receives an unsigned int argument and raise OverflowError if the value is negative.''' + val = 100 + self.assertEqual(doubleUnsignedInt(val), 2 * val) + val *= -1 + self.assertRaises(OverflowError, doubleUnsignedInt, val) + + def testLongLong(self): + '''C++ function receives an long long argument and raise OverflowError if the value is negative.''' + val = 100 + self.assertEqual(doubleLongLong(val), 2 * val) + val = long(100) + self.assertEqual(doubleLongLong(val), 2 * val) + val = (2 << 64) + 1 + self.assertRaises(OverflowError, doubleLongLong, val) + + def testUnsignedLongLong(self): + '''C++ function receives an unsigned long long argument and raise OverflowError if the value is negative.''' + val = 100 + self.assertEqual(doubleUnsignedLongLong(val), 2 * val) + val = long(100) + self.assertEqual(doubleUnsignedLongLong(val), 2 * val) + val = -100 + self.assertRaises(OverflowError, doubleUnsignedLongLong, val) + val = long(-200) + self.assertRaises(OverflowError, doubleUnsignedLongLong, val) + + def testOverflow(self): + '''Calls function with unsigned int parameter using an overflowing value.''' + self.assertRaises(OverflowError, doubleUnsignedInt, 42415335332353253) + doubleUnsignedInt(0xdeadbeef) + + def testShortOverflow(self): + '''Calls function with short parameter using an overflowing value.''' + doubleShort(-3) + self.assertRaises(OverflowError, doubleShort, 0xFFFF*-1) + self.assertRaises(OverflowError, doubleShort, 0xFFFF + 1) + + def testOverflowOnCtor(self): + '''Calls object ctor with int parameter using overflowing values.''' + self.assertRaises(OverflowError, Point, 42415335332353253, 42415335332353253) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/overload_sorting_test.py b/sources/shiboken2/tests/samplebinding/overload_sorting_test.py new file mode 100644 index 000000000..30e1ad955 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/overload_sorting_test.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 overload sorting''' + +import unittest + +from sample import * + +class Dummy(object): + pass + +class SimpleOverloadSorting(unittest.TestCase): + + def setUp(self): + self.obj = SortedOverload() + + def testIntDouble(self): + '''Overloads with int and double''' + self.assertEqual(self.obj.overload(3), "int") + self.assertEqual(self.obj.overload(3.14), "double") + + def testImplicitConvert(self): + '''Overloads with implicit convertible types''' + self.assertEqual(self.obj.overload(ImplicitTarget()), "ImplicitTarget") + self.assertEqual(self.obj.overload(ImplicitBase()), "ImplicitBase") + + def testContainer(self): + '''Overloads with containers arguments''' + self.assertEqual(self.obj.overload([ImplicitBase()]), "list(ImplicitBase)") + + def testPyObject(self): + '''Overloads with PyObject args''' + self.assertEqual(self.obj.overload(Dummy()), "PyObject") + + def testImplicitOnly(self): + '''Passing an implicit convertible object to an overload''' + self.assertTrue(self.obj.implicit_overload(ImplicitTarget())) + + def testPyObjectSort(self): + self.assertEqual(self.obj.pyObjOverload(1, 2), "int,int") + self.assertEqual(self.obj.pyObjOverload(object(), 2), "PyObject,int") + + +class DeepOverloadSorting(unittest.TestCase): + + def setUp(self): + self.obj = SortedOverload() + + def testPyObject(self): + '''Deep Overload - (int, PyObject *)''' + self.assertEqual(self.obj.overloadDeep(1, Dummy()), "PyObject") + + def testImplicit(self): + '''Deep Overload - (int, ImplicitBase *)''' + self.assertEqual(self.obj.overloadDeep(1, ImplicitBase()), "ImplicitBase") + +class EnumOverIntSorting(unittest.TestCase): + def testEnumOverInt(self): + ic = ImplicitConv(ImplicitConv.CtorTwo) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorTwo) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/overload_test.py b/sources/shiboken2/tests/samplebinding/overload_test.py new file mode 100644 index 000000000..efcd3bed8 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/overload_test.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Overload class''' + +import unittest +from sample import Echo, Overload, Point, PointF, Polygon, Rect, RectF, Size, Str + + +def raisesWithErrorMessage(func, arguments, errorType, errorMsg): + '''NOTE: Using 'try' because assertRaisesRegexp is not available + to check the error message.''' + try: + func(*arguments) + return False + except Exception as err: + if type(err) != TypeError: + return False + if not errorMsg in str(err): + return False + return True + + +class OverloadTest(unittest.TestCase): + '''Test case for Overload class''' + + def testOverloadMethod0(self): + '''Check overloaded method call for signature "overloaded()".''' + overload = Overload() + self.assertEqual(overload.overloaded(), Overload.Function0) + + def testOverloadMethod1(self): + '''Check overloaded method call for signature "overloaded(Size*)".''' + overload = Overload() + size = Size() + self.assertEqual(overload.overloaded(size), Overload.Function1) + + def testOverloadMethod2(self): + '''Check overloaded method call for signature "overloaded(Point*, ParamEnum)".''' + overload = Overload() + point = Point() + self.assertEqual(overload.overloaded(point, Overload.Param1), Overload.Function2) + + def testOverloadMethod3(self): + '''Check overloaded method call for signature "overloaded(const Point&)".''' + overload = Overload() + point = Point() + self.assertEqual(overload.overloaded(point), Overload.Function3) + + def testDifferentReturnTypes(self): + '''Check method calls for overloads with different return types.''' + overload = Overload() + self.assertEqual(overload.differentReturnTypes(), None) + self.assertEqual(overload.differentReturnTypes(Overload.Param1), None) + self.assertEqual(overload.differentReturnTypes(Overload.Param0, 13), 13) + + def testIntOverloads(self): + overload = Overload() + self.assertEqual(overload.intOverloads(2, 3), 2) + self.assertEqual(overload.intOverloads(2, 4.5), 3) + self.assertEqual(overload.intOverloads(Point(0, 0), 3), 1) + + def testIntDoubleOverloads(self): + overload = Overload() + self.assertEqual(overload.intDoubleOverloads(1, 2), Overload.Function0) + self.assertEqual(overload.intDoubleOverloads(1, 2.0), Overload.Function0) + self.assertEqual(overload.intDoubleOverloads(1.0, 2), Overload.Function1) + self.assertEqual(overload.intDoubleOverloads(1.0, 2.0), Overload.Function1) + + def testWrapperIntIntOverloads(self): + overload = Overload() + self.assertEqual(overload.wrapperIntIntOverloads(Point(), 1, 2), Overload.Function0) + self.assertEqual(overload.wrapperIntIntOverloads(Polygon(), 1, 2), Overload.Function1) + + def testDrawTextPointAndStr(self): + overload = Overload() + self.assertEqual(overload.drawText(Point(), Str()), Overload.Function0) + self.assertEqual(overload.drawText(Point(), ''), Overload.Function0) + self.assertEqual(overload.drawText(PointF(), Str()), Overload.Function1) + self.assertEqual(overload.drawText(PointF(), ''), Overload.Function1) + + def testDrawTextRectIntStr(self): + overload = Overload() + self.assertEqual(overload.drawText(Rect(), 1, Str()), Overload.Function2) + self.assertEqual(overload.drawText(Rect(), 1, ''), Overload.Function2) + self.assertEqual(overload.drawText(RectF(), 1, Str()), Overload.Function3) + self.assertEqual(overload.drawText(RectF(), 1, ''), Overload.Function3) + + def testDrawTextRectFStrEcho(self): + overload = Overload() + self.assertEqual(overload.drawText(RectF(), Str()), Overload.Function4) + self.assertEqual(overload.drawText(RectF(), ''), Overload.Function4) + self.assertEqual(overload.drawText(RectF(), Str(), Echo()), Overload.Function4) + self.assertEqual(overload.drawText(RectF(), '', Echo()), Overload.Function4) + self.assertEqual(overload.drawText(Rect(), Str()), Overload.Function4) + self.assertEqual(overload.drawText(Rect(), ''), Overload.Function4) + self.assertEqual(overload.drawText(Rect(), Str(), Echo()), Overload.Function4) + self.assertEqual(overload.drawText(Rect(), '', Echo()), Overload.Function4) + + def testDrawTextIntIntStr(self): + overload = Overload() + self.assertEqual(overload.drawText(1, 2, Str()), Overload.Function5) + self.assertEqual(overload.drawText(1, 2, ''), Overload.Function5) + + def testDrawTextIntIntIntIntStr(self): + overload = Overload() + self.assertEqual(overload.drawText(1, 2, 3, 4, 5, Str()), Overload.Function6) + self.assertEqual(overload.drawText(1, 2, 3, 4, 5, ''), Overload.Function6) + + def testDrawText2IntIntIntIntStr(self): + overload = Overload() + self.assertEqual(overload.drawText2(1, 2, 3, 4, 5, Str()), Overload.Function6) + self.assertEqual(overload.drawText2(1, 2, 3, 4, 5, ''), Overload.Function6) + self.assertEqual(overload.drawText2(1, 2, 3, 4, 5), Overload.Function6) + self.assertEqual(overload.drawText2(1, 2, 3, 4), Overload.Function6) + self.assertEqual(overload.drawText2(1, 2, 3), Overload.Function6) + + def testDrawText3(self): + overload = Overload() + self.assertEqual(overload.drawText3(Str(), Str(), Str()), Overload.Function0) + self.assertEqual(overload.drawText3('', '', ''), Overload.Function0) + self.assertEqual(overload.drawText3(1, 2, 3, 4, 5), Overload.Function1) + self.assertEqual(overload.drawText3(1, 2, 3, 4, 5), Overload.Function1) + + def testDrawText3Exception(self): + overload = Overload() + args = (Str(), Str(), Str(), 4, 5) + result = raisesWithErrorMessage(overload.drawText3, args, + TypeError, 'called with wrong argument types:') + self.assertTrue(result) + + def testDrawText4(self): + overload = Overload() + self.assertEqual(overload.drawText4(1, 2, 3), Overload.Function0) + self.assertEqual(overload.drawText4(1, 2, 3, 4, 5), Overload.Function1) + + def testAcceptSequence(self): + # Overload.acceptSequence() + overload = Overload() + self.assertEqual(overload.acceptSequence(), Overload.Function0) + + def testAcceptSequenceIntInt(self): + # Overload.acceptSequence(int,int) + overload = Overload() + self.assertEqual(overload.acceptSequence(1, 2), Overload.Function1) + + def testAcceptSequenceStrParamEnum(self): + # Overload.acceptSequence(Str,Overload::ParamEnum) + overload = Overload() + self.assertEqual(overload.acceptSequence(''), Overload.Function2) + self.assertEqual(overload.acceptSequence('', Overload.Param0), Overload.Function2) + self.assertEqual(overload.acceptSequence(Str('')), Overload.Function2) + self.assertEqual(overload.acceptSequence(Str(''), Overload.Param0), Overload.Function2) + + def testAcceptSequenceSize(self): + # Overload.acceptSequence(Size) + overload = Overload() + self.assertEqual(overload.acceptSequence(Size()), Overload.Function3) + + def testAcceptSequenceStringList(self): + # Overload.acceptSequence(const char**) + overload = Overload() + strings = ['line 1', 'line 2'] + self.assertEqual(overload.acceptSequence(strings), Overload.Function4) + args = (['line 1', 2], ) + result = raisesWithErrorMessage(overload.acceptSequence, args, + TypeError, 'The argument must be a sequence of strings.') + self.assertTrue(result) + + def testAcceptSequencePyObject(self): + # Overload.acceptSequence(void*) + overload = Overload() + class Foo(object): + pass + foo = Foo() + self.assertEqual(overload.acceptSequence(foo), Overload.Function5) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/overloadwithdefault_test.py b/sources/shiboken2/tests/samplebinding/overloadwithdefault_test.py new file mode 100644 index 000000000..9f243a573 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/overloadwithdefault_test.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Overload, Str +from py3kcompat import b + +class OverloadTest(unittest.TestCase): + + def testNoArgument(self): + overload = Overload() + self.assertEqual(overload.strBufferOverloads(), Overload.Function2) + + def testStrArgument(self): + overload = Overload() + self.assertEqual(overload.strBufferOverloads(Str('')), Overload.Function0) + self.assertEqual(overload.strBufferOverloads(Str(''), ''), Overload.Function0) + self.assertEqual(overload.strBufferOverloads(Str(''), '', False), Overload.Function0) + + def testStringArgumentAsStr(self): + overload = Overload() + self.assertEqual(overload.strBufferOverloads('', ''), Overload.Function0) + self.assertEqual(overload.strBufferOverloads('', '', False), Overload.Function0) + + def testStringArgumentAsBuffer(self): + overload = Overload() + self.assertEqual(overload.strBufferOverloads(b'', 0), Overload.Function1) + + def testBufferArgument(self): + overload = Overload() + self.assertEqual(overload.strBufferOverloads(b(''), 0), Overload.Function1) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/ownership_argument_invalidation_test.py b/sources/shiboken2/tests/samplebinding/ownership_argument_invalidation_test.py new file mode 100644 index 000000000..5c6f31395 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ownership_argument_invalidation_test.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Wrapper validity tests for arguments.''' + +import sys +import unittest + +from sample import Polygon, Point + +class WrapperValidityOfArgumentsTest(unittest.TestCase): + '''Wrapper validity tests for arguments.''' + + def testInvalidArgumentToMethod(self): + '''Call to method using invalidated Python wrapper as argument should raise RuntimeError.''' + poly = Polygon() + Polygon.stealOwnershipFromPython(poly) + self.assertRaises(RuntimeError, Polygon.doublePolygonScale, poly) + + def testInvalidArgumentToConstructor(self): + '''Call to constructor using invalidated Python wrapper as argument should raise RuntimeError.''' + pt = Point(1, 2) + Polygon.stealOwnershipFromPython(pt) + self.assertRaises(RuntimeError, Polygon, pt) + + def testInvalidArgumentWithImplicitConversion(self): + '''Call to method using invalidated Python wrapper to be implicitly converted should raise RuntimeError.''' + pt = Point(1, 2) + Polygon.stealOwnershipFromPython(pt) + self.assertRaises(RuntimeError, Polygon.doublePolygonScale, pt) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/ownership_delete_child_in_cpp_test.py b/sources/shiboken2/tests/samplebinding/ownership_delete_child_in_cpp_test.py new file mode 100644 index 000000000..829cabd81 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ownership_delete_child_in_cpp_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests for destroy a child object in C++''' + +import unittest + +from sample import ObjectType + + +class DeleteChildInCpp(unittest.TestCase): + '''Test case for destroying a child in c++''' + + def testDeleteChild(self): + '''Delete child in C++ should invalidate child - using C++ wrapper''' + parent = ObjectType() + parent.setObjectName('parent') + child = ObjectType(parent) + child.setObjectName('child') + + parent.killChild('child') + self.assertRaises(RuntimeError, child.objectName) + self.assertEqual(parent.objectName(), 'parent') + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/ownership_delete_child_in_python_test.py b/sources/shiboken2/tests/samplebinding/ownership_delete_child_in_python_test.py new file mode 100644 index 000000000..32312af7f --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ownership_delete_child_in_python_test.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests for deleting a child object in python''' + +import unittest +import random +import string + +from sample import ObjectType +from py3kcompat import IS_PY3K + +if IS_PY3K: + string.letters = string.ascii_letters + + +class DeleteChildInPython(unittest.TestCase): + '''Test case for deleting (unref) a child in python''' + + def testDeleteChild(self): + '''Delete child in python should not invalidate child''' + parent = ObjectType() + child = ObjectType(parent) + name = ''.join(random.sample(string.letters, 5)) + child.setObjectName(name) + + del child + new_child = parent.children()[0] + self.assertEqual(new_child.objectName(), name) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/ownership_delete_parent_test.py b/sources/shiboken2/tests/samplebinding/ownership_delete_parent_test.py new file mode 100644 index 000000000..1c135a4aa --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ownership_delete_parent_test.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests for destroying the parent''' + +import sys +import unittest + +from sample import ObjectType + + +class DeleteParentTest(unittest.TestCase): + '''Test case for deleting a parent object''' + + def testParentDestructor(self): + '''Delete parent object should invalidate child''' + parent = ObjectType() + child = ObjectType() + child.setParent(parent) + + refcount_before = sys.getrefcount(child) + + del parent + self.assertRaises(RuntimeError, child.objectName) + self.assertEqual(sys.getrefcount(child), refcount_before-1) + + def testParentDestructorMultipleChildren(self): + '''Delete parent object should invalidate all children''' + parent = ObjectType() + children = [ObjectType() for _ in range(10)] + + for child in children: + child.setParent(parent) + + del parent + for i, child in enumerate(children): + self.assertRaises(RuntimeError, child.objectName) + self.assertEqual(sys.getrefcount(child), 4) + + def testRecursiveParentDelete(self): + '''Delete parent should invalidate grandchildren''' + parent = ObjectType() + child = ObjectType(parent) + grandchild = ObjectType(child) + + del parent + self.assertRaises(RuntimeError, child.objectName) + self.assertEqual(sys.getrefcount(child), 2) + self.assertRaises(RuntimeError, grandchild.objectName) + self.assertEqual(sys.getrefcount(grandchild), 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/ownership_invalidate_after_use_test.py b/sources/shiboken2/tests/samplebinding/ownership_invalidate_after_use_test.py new file mode 100644 index 000000000..8b3e84738 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ownership_invalidate_after_use_test.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Ownership tests for cases of invalidation of Python wrapper after use.''' + +import sys +import unittest + +from sample import ObjectType, ObjectTypeDerived, Event + + +class ExtObjectType(ObjectType): + def __init__(self): + ObjectType.__init__(self) + self.type_of_last_event = None + self.last_event = None + def event(self, event): + self.last_event = event + self.type_of_last_event = event.eventType() + return True + +class MyObjectType (ObjectType): + def __init__(self): + super(MyObjectType, self).__init__() + self.fail = False + + def event(self, ev): + self.callInvalidateEvent(ev) + try: + ev.eventType() + except: + self.fail = True + raise + return True + + def invalidateEvent(self, ev): + pass + +class ExtObjectTypeDerived(ObjectTypeDerived): + def __init__(self): + ObjectTypeDerived.__init__(self) + self.type_of_last_event = None + self.last_event = None + def event(self, event): + self.last_event = event + self.type_of_last_event = event.eventType() + return True + +class OwnershipInvalidateAfterUseTest(unittest.TestCase): + '''Ownership tests for cases of invalidation of Python wrapper after use.''' + + def testInvalidateAfterUse(self): + '''In ObjectType.event(Event*) the wrapper object created for Event must me marked as invalid after the method is called.''' + eot = ExtObjectType() + eot.causeEvent(Event.SOME_EVENT) + self.assertEqual(eot.type_of_last_event, Event.SOME_EVENT) + self.assertRaises(RuntimeError, eot.last_event.eventType) + + def testObjectInvalidatedAfterUseAsParameter(self): + '''Tries to use wrapper invalidated after use as a parameter to another method.''' + eot = ExtObjectType() + ot = ObjectType() + eot.causeEvent(Event.ANY_EVENT) + self.assertEqual(eot.type_of_last_event, Event.ANY_EVENT) + self.assertRaises(RuntimeError, ot.event, eot.last_event) + + def testit(self): + obj = MyObjectType() + obj.causeEvent(Event.BASIC_EVENT) + self.assertFalse(obj.fail) + + def testInvalidateAfterUseInDerived(self): + '''Invalidate was failing in a derived C++ class that also inherited + other base classes''' + eot = ExtObjectTypeDerived() + eot.causeEvent(Event.SOME_EVENT) + self.assertEqual(eot.type_of_last_event, Event.SOME_EVENT) + self.assertRaises(RuntimeError, eot.last_event.eventType) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/ownership_invalidate_child_test.py b/sources/shiboken2/tests/samplebinding/ownership_invalidate_child_test.py new file mode 100644 index 000000000..e92fa39f5 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ownership_invalidate_child_test.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests for invalidating a C++ created child that was already on the care of a parent.''' + +import unittest + +from sample import ObjectType, BlackBox + + +class InvalidateChildTest(unittest.TestCase): + '''Tests for invalidating a C++ created child that was already on the care of a parent.''' + + def testInvalidateChild(self): + '''Invalidating method call should remove child from the care of a parent if it has one.''' + parent = ObjectType() + child1 = ObjectType(parent) + child1.setObjectName('child1') + child2 = ObjectType.create() + child2.setParent(parent) + child2.setObjectName('child2') + + self.assertEqual(parent.children(), [child1, child2]) + + bbox = BlackBox() + + # This method steals ownership from Python to C++. + bbox.keepObjectType(child1) + self.assertEqual(parent.children(), [child2]) + + bbox.keepObjectType(child2) + self.assertEqual(parent.children(), []) + + del parent + + self.assertEqual(child1.objectName(), 'child1') + self.assertRaises(RuntimeError, child2.objectName) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py b/sources/shiboken2/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py new file mode 100644 index 000000000..69527974c --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''The BlackBox class has cases of ownership transference between Python and C++.''' + +import sys +import unittest + +from sample import Point, BlackBox + +class OwnershipInvalidateNonPolymorphicTest(unittest.TestCase): + '''The BlackBox class has cases of ownership transference between Python and C++.''' + + def testOwnershipTransference(self): + '''Ownership transference from Python to C++ and back again.''' + p1 = Point(10, 20) + bb = BlackBox() + p1_ticket = bb.keepPoint(p1) + self.assertRaises(RuntimeError, p1.x) + p1_ret = bb.retrievePoint(p1_ticket) + self.assertEqual(p1_ret, Point(10, 20)) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/ownership_invalidate_parent_test.py b/sources/shiboken2/tests/samplebinding/ownership_invalidate_parent_test.py new file mode 100644 index 000000000..848c982ce --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ownership_invalidate_parent_test.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests for invalidating a parent of other objects.''' + +import unittest + +from sample import ObjectType, BlackBox + + +class InvalidateParentTest(unittest.TestCase): + '''Tests for invalidating a parent of other objects.''' + + def testInvalidateParent(self): + '''Invalidate parent should invalidate children''' + parent = ObjectType.create() + child1 = ObjectType(parent) + child1.setObjectName("child1") + child2 = ObjectType.create() + child2.setObjectName("child2") + child2.setParent(parent) + grandchild1 = ObjectType(child1) + grandchild1.setObjectName("grandchild1") + grandchild2 = ObjectType.create() + grandchild2.setObjectName("grandchild2") + grandchild2.setParent(child2) + bbox = BlackBox() + + bbox.keepObjectType(parent) # Should invalidate the parent + + self.assertRaises(RuntimeError, parent.objectName) + # some children still valid they are wrapper classes + self.assertEqual(child1.objectName(), "child1") + self.assertRaises(RuntimeError, child2.objectName) + self.assertEqual(grandchild1.objectName(), "grandchild1") + self.assertRaises(RuntimeError, grandchild2.objectName) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/ownership_reparenting_test.py b/sources/shiboken2/tests/samplebinding/ownership_reparenting_test.py new file mode 100644 index 000000000..20e6aca03 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ownership_reparenting_test.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests for object reparenting.''' + +import unittest +import sys + +from sample import ObjectType + +class ExtObjectType(ObjectType): + def __init__(self): + ObjectType.__init__(self) + + +class ReparentingTest(unittest.TestCase): + '''Tests for object reparenting.''' + + def testReparentedObjectTypeIdentity(self): + '''Reparent children from one parent to another.''' + object_list = [] + old_parent = ObjectType() + new_parent = ObjectType() + for i in range(3): + obj = ObjectType() + object_list.append(obj) + obj.setParent(old_parent) + for obj in object_list: + obj.setParent(new_parent) + for child in new_parent.children(): + self.assertTrue(child in object_list) + + def testReparentWithTheSameParent(self): + '''Set the same parent twice to check if the ref continue the same''' + obj = ObjectType() + parent = ObjectType() + self.assertEqual(sys.getrefcount(obj), 2) + obj.setParent(parent) + self.assertEqual(sys.getrefcount(obj), 3) + obj.setParent(parent) + self.assertEqual(sys.getrefcount(obj), 3) + + def testReparentedExtObjectType(self): + '''Reparent children from one extended parent to another.''' + object_list = [] + old_parent = ExtObjectType() + new_parent = ExtObjectType() + for i in range(3): + obj = ExtObjectType() + object_list.append(obj) + obj.setParent(old_parent) + for obj in object_list: + obj.setParent(new_parent) + for orig, child in zip(object_list, new_parent.children()): + self.assertEqual(type(orig), type(child)) + + def testReparentedObjectTypeIdentityWithParentsCreatedInCpp(self): + '''Reparent children from one parent to another, both created in C++.''' + object_list = [] + old_parent = ObjectType.create() + new_parent = ObjectType.create() + for i in range(3): + obj = ObjectType() + object_list.append(obj) + obj.setParent(old_parent) + for obj in object_list: + obj.setParent(new_parent) + for child in new_parent.children(): + self.assertTrue(child in object_list) + + def testReparentedObjectTypeIdentityWithChildrenCreatedInCpp(self): + '''Reparent children created in C++ from one parent to another.''' + object_list = [] + old_parent = ObjectType() + new_parent = ObjectType() + for i in range(3): + obj = ObjectType.create() + object_list.append(obj) + obj.setParent(old_parent) + for obj in object_list: + obj.setParent(new_parent) + for child in new_parent.children(): + self.assertTrue(child in object_list) + + def testReparentedObjectTypeIdentityWithParentsAndChildrenCreatedInCpp(self): + '''Reparent children from one parent to another. Parents and children are created in C++.''' + object_list = [] + old_parent = ObjectType.create() + new_parent = ObjectType.create() + for i in range(3): + obj = ObjectType.create() + object_list.append(obj) + obj.setParent(old_parent) + for obj in object_list: + obj.setParent(new_parent) + for child in new_parent.children(): + self.assertTrue(child in object_list) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/ownership_transference_test.py b/sources/shiboken2/tests/samplebinding/ownership_transference_test.py new file mode 100644 index 000000000..0df2a09ba --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/ownership_transference_test.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''The BlackBox class has cases of ownership transference between C++ and Python.''' + +import sys +import unittest + +from sample import ObjectType, BlackBox + +class BlackBoxTest(unittest.TestCase): + '''The BlackBox class has cases of ownership transference between C++ and Python.''' + + def testOwnershipTransference(self): + '''Ownership transference from Python to C++ and back again.''' + o1 = ObjectType() + o1.setObjectName('object1') + o1_refcnt = sys.getrefcount(o1) + o2 = ObjectType() + o2.setObjectName('object2') + o2_refcnt = sys.getrefcount(o2) + bb = BlackBox() + o1_ticket = bb.keepObjectType(o1) + o2_ticket = bb.keepObjectType(o2) + self.assertEqual(set(bb.objects()), set([o1, o2])) + self.assertEqual(str(o1.objectName()), 'object1') + self.assertEqual(str(o2.objectName()), 'object2') + self.assertEqual(sys.getrefcount(o1), o1_refcnt + 1) # PySide give +1 ref to object with c++ ownership + self.assertEqual(sys.getrefcount(o2), o2_refcnt + 1) + o2 = bb.retrieveObjectType(o2_ticket) + self.assertEqual(sys.getrefcount(o2), o2_refcnt) + del bb + self.assertRaises(RuntimeError, o1.objectName) + self.assertEqual(str(o2.objectName()), 'object2') + self.assertEqual(sys.getrefcount(o2), o2_refcnt) + + def testBlackBoxReleasingUnknownObjectType(self): + '''Asks BlackBox to release an unknown ObjectType.''' + o1 = ObjectType() + o2 = ObjectType() + bb = BlackBox() + o1_ticket = bb.keepObjectType(o1) + o3 = bb.retrieveObjectType(-5) + self.assertEqual(o3, None) + + def testOwnershipTransferenceCppCreated(self): + '''Ownership transference using a C++ created object.''' + o1 = ObjectType.create() + o1.setObjectName('object1') + o1_refcnt = sys.getrefcount(o1) + bb = BlackBox() + o1_ticket = bb.keepObjectType(o1) + self.assertRaises(RuntimeError, o1.objectName) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/pair_test.py b/sources/shiboken2/tests/samplebinding/pair_test.py new file mode 100644 index 000000000..4786213c5 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/pair_test.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 std::pair container conversions''' + +import sys +import unittest + +from sample import PairUser + +class ExtendedPairUser(PairUser): + def __init__(self): + PairUser.__init__(self) + self.create_pair_called = False + + def createPair(self): + self.create_pair_called = True + return (7, 13) + +class PairConversionTest(unittest.TestCase): + '''Test case for std::pair container conversions''' + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a virtual method is correctly called from C++.''' + pu = ExtendedPairUser() + pair = pu.callCreatePair() + self.assertTrue(pu.create_pair_called) + self.assertEqual(type(pair), tuple) + self.assertEqual(type(pair[0]), int) + self.assertEqual(type(pair[1]), int) + self.assertEqual(pair, (7, 13)) + + def testPrimitiveConversionInsideContainer(self): + '''Test primitive type conversion inside conversible std::pair container.''' + cpx0 = complex(1.2, 3.4) + cpx1 = complex(5.6, 7.8) + cp = PairUser.createComplexPair(cpx0, cpx1) + self.assertEqual(type(cp), tuple) + self.assertEqual(type(cp[0]), complex) + self.assertEqual(type(cp[1]), complex) + self.assertEqual(cp, (cpx0, cpx1)) + + def testSumPair(self): + '''Test method that sums the items of a pair using values of the types expected by C++ (int and double)''' + pu = PairUser() + pair = (3, 7.13) + result = pu.sumPair(pair) + self.assertEqual(result, sum(pair)) + + def testSumPairDifferentTypes(self): + '''Test method that sums the items of a pair using values of types different from the ones expected by C++ (int and double)''' + pu = PairUser() + pair = (3.3, 7) + result = pu.sumPair(pair) + self.assertNotEqual(result, sum(pair)) + self.assertEqual(result, int(pair[0]) + pair[1]) + + def testConversionInBothDirections(self): + '''Test converting a pair from Python to C++ and the other way around.''' + pu = PairUser() + pair = (3, 5) + pu.setPair(pair) + result = pu.getPair() + self.assertEqual(result, pair) + + def testConversionInBothDirectionsWithSimilarContainer(self): + '''Test converting a list, instead of the expected tuple, from Python to C++ and the other way around.''' + pu = PairUser() + pair = [3, 5] + pu.setPair(pair) + result = pu.getPair() + self.assertNotEqual(result, pair) + self.assertEqual(result, tuple(pair)) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/pen_test.py b/sources/shiboken2/tests/samplebinding/pen_test.py new file mode 100644 index 000000000..54c96b9c8 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/pen_test.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 with const char* as argument''' + +import unittest + +from sample import Color, Pen, SampleNamespace + +class TestPen(unittest.TestCase): + '''Simple test case for Pen.''' + + def testPenWithEmptyConstructor(self): + pen = Pen() + self.assertEqual(pen.ctorType(), Pen.EmptyCtor) + + def testPenWithEnumConstructor(self): + pen = Pen(SampleNamespace.RandomNumber) + self.assertEqual(pen.ctorType(), Pen.EnumCtor) + + def testPenWithColorConstructor(self): + pen = Pen(Color()) + self.assertEqual(pen.ctorType(), Pen.ColorCtor) + + def testPenWithCopyConstructor(self): + pen = Pen(Pen()) + self.assertEqual(pen.ctorType(), Pen.CopyCtor) + + def testPenWithIntConvertedToColor(self): + pen = Pen(1) + self.assertEqual(pen.ctorType(), Pen.ColorCtor) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/point_test.py b/sources/shiboken2/tests/samplebinding/point_test.py new file mode 100644 index 000000000..6f84ac999 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/point_test.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Point class''' + +import sys +import unittest + +from sample import Point +from py3kcompat import unicode + +class PointTest(unittest.TestCase): + '''Test case for Point class, including operator overloads.''' + + def testConstructor(self): + '''Test Point class constructor.''' + pt = Point(5.0, 2.3) + self.assertEqual(pt.x(), 5.0) + self.assertEqual(pt.y(), 2.3) + + def testPlusOperator(self): + '''Test Point class + operator.''' + pt1 = Point(5.0, 2.3) + pt2 = Point(0.5, 3.2) + self.assertEqual(pt1 + pt2, Point(5.0 + 0.5, 2.3 + 3.2)) + + def testEqualOperator(self): + '''Test Point class == operator.''' + pt1 = Point(5.0, 2.3) + pt2 = Point(5.0, 2.3) + pt3 = Point(0.5, 3.2) + self.assertTrue(pt1 == pt1) + self.assertTrue(pt1 == pt2) + self.assertFalse(pt1 == pt3) + self.assertFalse(pt1 == object()) + + def testNotEqualOperator(self): + '''Test Point class != operator.''' + pt1 = Point(5.0, 2.3) + pt2 = Point(5.0, 2.3) + self.assertRaises(NotImplementedError, pt1.__ne__, pt2) + + def testReturnNewCopy(self): + '''Point returns a copy of itself.''' + pt1 = Point(1.1, 2.3) + pt2 = pt1.copy() + self.assertEqual(pt1, pt2) + pt2 += pt1 + self.assertFalse(pt1 == pt2) + + def testReturnConstPointer(self): + '''Point returns a const pointer for itself.''' + pt1 = Point(5.0, 2.3) + refcount1 = sys.getrefcount(pt1) + pt2 = pt1.getSelf() + self.assertEqual(pt1, pt2) + self.assertEqual(sys.getrefcount(pt1), refcount1 + 1) + self.assertEqual(sys.getrefcount(pt1), sys.getrefcount(pt2)) + + def testUintOverflow(self): + pt1 = Point(0.0, 0.0) + self.assertRaises(OverflowError, pt1.setXAsUint, 840835495615213080) + self.assertEqual(pt1.x(), 0.0) + + def testAddedOperator(self): + p = Point(0.0, 0.0) + r = p - unicode('Hi') + self.assertEqual(r, unicode('Hi')) + + # now the reverse op. + r = unicode('Hi') - p + self.assertEqual(r, unicode('Hi')) + + def testModifiedMethod(self): + pt1 = Point(0.0, 0.0) + pt2 = Point(10.0, 10.0) + expected = Point((pt1.x() + pt2.x()) / 2.0, (pt1.y() + pt2.y()) / 2.0) + self.assertEqual(pt1.midpoint(pt2), expected) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/pointerholder_test.py b/sources/shiboken2/tests/samplebinding/pointerholder_test.py new file mode 100644 index 000000000..32ef99d5c --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/pointerholder_test.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 a class that holds an arbitraty pointer and is modified to hold an PyObject.''' + +import sys +import unittest + +from sample import PointerHolder + +class TestPointerHolder(unittest.TestCase): + '''Test cases for a class that holds an arbitraty pointer and is modified to hold an PyObject.''' + + def testStoringAndRetrievingPointer(self): + ph = PointerHolder('Hello') + self.assertEqual(ph.pointer(), 'Hello') + a = (1, 2, 3) + ph = PointerHolder(a) + self.assertEqual(ph.pointer(), a) + + def testReferenceCounting(self): + '''Test reference counting when retrieving data with PointerHolder.pointer().''' + a = (1, 2, 3) + refcnt = sys.getrefcount(a) + ph = PointerHolder(a) + ptr = ph.pointer() + self.assertEqual(sys.getrefcount(a), refcnt + 1) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/pointf_test.py b/sources/shiboken2/tests/samplebinding/pointf_test.py new file mode 100644 index 000000000..9318dca24 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/pointf_test.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 PointF class''' + +import unittest + +from sample import PointF + +class PointFTest(unittest.TestCase): + '''Test case for PointF class, including operator overloads.''' + + def testConstructor(self): + '''Test PointF class constructor.''' + pt = PointF(5.0, 2.3) + self.assertEqual(pt.x(), 5.0) + self.assertEqual(pt.y(), 2.3) + + def testPlusOperator(self): + '''Test PointF class + operator.''' + pt1 = PointF(5.0, 2.3) + pt2 = PointF(0.5, 3.2) + self.assertEqual(pt1 + pt2, PointF(5.0 + 0.5, 2.3 + 3.2)) + + def testEqualOperator(self): + '''Test PointF class == operator.''' + pt1 = PointF(5.0, 2.3) + pt2 = PointF(5.0, 2.3) + pt3 = PointF(0.5, 3.2) + self.assertTrue(pt1 == pt1) + self.assertTrue(pt1 == pt2) + self.assertFalse(pt1 == pt3) + + def testModifiedMethod(self): + pt1 = PointF(0.0, 0.0) + pt2 = PointF(10.0, 10.0) + expected = PointF((pt1.x() + pt2.x()) / 2.0, (pt1.y() + pt2.y()) / 2.0) + self.assertEqual(pt1.midpoint(pt2), expected) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/primitivereferenceargument_test.py b/sources/shiboken2/tests/samplebinding/primitivereferenceargument_test.py new file mode 100644 index 000000000..e973c0d78 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/primitivereferenceargument_test.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 +import sample + +class PrimitiveReferenceArgumentTest(unittest.TestCase): + + def testIntReferenceArgument(self): + '''C++ signature: int acceptIntReference(int&)''' + self.assertEqual(sample.acceptIntReference(123), 123) + + def testOddBoolReferenceArgument(self): + '''C++ signature: OddBool acceptOddBoolReference(OddBool&)''' + self.assertEqual(sample.acceptOddBoolReference(True), True) + self.assertEqual(sample.acceptOddBoolReference(False), False) + self.assertNotEqual(sample.acceptOddBoolReference(True), False) + self.assertNotEqual(sample.acceptOddBoolReference(False), True) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/privatector_test.py b/sources/shiboken2/tests/samplebinding/privatector_test.py new file mode 100644 index 000000000..471f735cb --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/privatector_test.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 a class with only a private constructor.''' + +import gc +import sys +import unittest + +from sample import PrivateCtor + + +class PrivateCtorTest(unittest.TestCase): + '''Test case for PrivateCtor class''' + + def testPrivateCtorInstanciation(self): + '''Test if instanciation of class with a private constructor raises an exception.''' + self.assertRaises(TypeError, PrivateCtor) + + def testPrivateCtorInheritance(self): + '''Test if inheriting from PrivateCtor raises an exception.''' + def inherit(): + class Foo(PrivateCtor): + pass + self.assertRaises(TypeError, inherit) + + def testPrivateCtorInstanceMethod(self): + '''Test if PrivateCtor.instance() method return the proper singleton.''' + pd1 = PrivateCtor.instance() + calls = pd1.instanceCalls() + self.assertEqual(type(pd1), PrivateCtor) + pd2 = PrivateCtor.instance() + self.assertEqual(pd2, pd1) + self.assertEqual(pd2.instanceCalls(), calls + 1) + + def testPrivateCtorRefCounting(self): + '''Test refcounting of the singleton returned by PrivateCtor.instance().''' + pd1 = PrivateCtor.instance() + calls = pd1.instanceCalls() + refcnt = sys.getrefcount(pd1) + pd2 = PrivateCtor.instance() + self.assertEqual(pd2.instanceCalls(), calls + 1) + self.assertEqual(sys.getrefcount(pd2), sys.getrefcount(pd1)) + self.assertEqual(sys.getrefcount(pd2), refcnt + 1) + del pd1 + self.assertEqual(sys.getrefcount(pd2), refcnt) + del pd2 + gc.collect() + pd3 = PrivateCtor.instance() + self.assertEqual(type(pd3), PrivateCtor) + self.assertEqual(pd3.instanceCalls(), calls + 2) + self.assertEqual(sys.getrefcount(pd3), refcnt) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/privatedtor_test.py b/sources/shiboken2/tests/samplebinding/privatedtor_test.py new file mode 100644 index 000000000..3048a9848 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/privatedtor_test.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 a class with a private destructor.''' + +import gc +import sys +import unittest + +import shiboken2 as shiboken +from sample import PrivateDtor + + +class PrivateDtorTest(unittest.TestCase): + '''Test case for PrivateDtor class''' + + def testPrivateDtorInstanciation(self): + '''Test if instanciation of class with a private destructor raises an exception.''' + self.assertRaises(TypeError, PrivateDtor) + + def testPrivateDtorInheritance(self): + '''Test if inheriting from PrivateDtor raises an exception.''' + def inherit(): + class Foo(PrivateDtor): + pass + self.assertRaises(TypeError, inherit) + + def testPrivateDtorInstanceMethod(self): + '''Test if PrivateDtor.instance() method return the proper singleton.''' + pd1 = PrivateDtor.instance() + calls = pd1.instanceCalls() + self.assertEqual(type(pd1), PrivateDtor) + pd2 = PrivateDtor.instance() + self.assertEqual(pd2, pd1) + self.assertEqual(pd2.instanceCalls(), calls + 1) + + def testPrivateDtorRefCounting(self): + '''Test refcounting of the singleton returned by PrivateDtor.instance().''' + pd1 = PrivateDtor.instance() + calls = pd1.instanceCalls() + refcnt = sys.getrefcount(pd1) + pd2 = PrivateDtor.instance() + self.assertEqual(pd2.instanceCalls(), calls + 1) + self.assertEqual(sys.getrefcount(pd2), sys.getrefcount(pd1)) + self.assertEqual(sys.getrefcount(pd2), refcnt + 1) + del pd1 + self.assertEqual(sys.getrefcount(pd2), refcnt) + del pd2 + gc.collect() + pd3 = PrivateDtor.instance() + self.assertEqual(type(pd3), PrivateDtor) + self.assertEqual(pd3.instanceCalls(), calls + 2) + self.assertEqual(sys.getrefcount(pd3), refcnt) + + def testClassDecref(self): + # Bug was that class PyTypeObject wasn't decrefed when instance + # was invalidated + + before = sys.getrefcount(PrivateDtor) + + for i in range(1000): + obj = PrivateDtor.instance() + shiboken.invalidate(obj) + + after = sys.getrefcount(PrivateDtor) + + self.assertLess(abs(before - after), 5) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/protected_test.py b/sources/shiboken2/tests/samplebinding/protected_test.py new file mode 100644 index 000000000..9201a63cf --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/protected_test.py @@ -0,0 +1,357 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 protected methods.''' + +import unittest + +from sample import cacheSize +from sample import ProtectedNonPolymorphic, ProtectedVirtualDestructor +from sample import ProtectedPolymorphic, ProtectedPolymorphicDaughter, ProtectedPolymorphicGrandDaughter +from sample import createProtectedProperty, ProtectedProperty, ProtectedEnumClass +from sample import PrivateDtor +from sample import Event, ObjectType, Point + +class ExtendedProtectedPolymorphic(ProtectedPolymorphic): + def __init__(self, name): + ProtectedPolymorphic.__init__(self, name) + self.protectedName_called = False + def protectedName(self): + self.protectedName_called = True + self._name = 'Extended' + ProtectedPolymorphic.protectedName(self) + return self._name + +class ExtendedProtectedPolymorphicDaughter(ProtectedPolymorphicDaughter): + def __init__(self, name): + self.protectedName_called = False + ProtectedPolymorphicDaughter.__init__(self, name) + def protectedName(self): + self.protectedName_called = True + self._name = 'ExtendedDaughter' + ProtectedPolymorphicDaughter.protectedName(self) + return self._name + +class ExtendedProtectedPolymorphicGrandDaughter(ProtectedPolymorphicGrandDaughter): + def __init__(self, name): + self.protectedName_called = False + ProtectedPolymorphicGrandDaughter.__init__(self, name) + def protectedName(self): + self.protectedName_called = True + self._name = 'ExtendedGrandDaughter' + ProtectedPolymorphicGrandDaughter.protectedName(self) + return self._name + +class ExtendedProtectedVirtualDestructor(ProtectedVirtualDestructor): + def __init__(self): + ProtectedVirtualDestructor.__init__(self) + +class ProtectedNonPolymorphicTest(unittest.TestCase): + '''Test cases for protected method in a class without virtual methods.''' + + def tearDown(self): + self.assertEqual(cacheSize(), 0) + + def testProtectedCall(self): + '''Calls a non-virtual protected method.''' + p = ProtectedNonPolymorphic('NonPoly') + self.assertEqual(p.publicName(), p.protectedName()) + a0, a1 = 1, 2 + self.assertEqual(p.protectedSum(a0, a1), a0 + a1) + + def testProtectedCallWithInstanceCreatedOnCpp(self): + '''Calls a non-virtual protected method on an instance created in C++.''' + p = ProtectedNonPolymorphic.create() + self.assertEqual(p.publicName(), p.protectedName()) + a0, a1 = 1, 2 + self.assertEqual(p.protectedSum(a0, a1), a0 + a1) + + def testModifiedProtectedCall(self): + '''Calls a non-virtual protected method modified with code injection.''' + p = ProtectedNonPolymorphic('NonPoly') + self.assertEqual(p.dataTypeName(), 'integer') + self.assertEqual(p.dataTypeName(1), 'integer') + self.assertEqual(p.dataTypeName(Point(1, 2)), 'pointer') + +class ProtectedPolymorphicTest(unittest.TestCase): + '''Test cases for protected method in a class with virtual methods.''' + + def tearDown(self): + self.assertEqual(cacheSize(), 0) + + def testProtectedCall(self): + '''Calls a virtual protected method.''' + p = ProtectedNonPolymorphic('Poly') + self.assertEqual(p.publicName(), p.protectedName()) + a0, a1 = 1, 2 + self.assertEqual(p.protectedSum(a0, a1), a0 + a1) + + def testProtectedCallWithInstanceCreatedOnCpp(self): + '''Calls a virtual protected method on an instance created in C++.''' + p = ProtectedPolymorphic.create() + self.assertEqual(p.publicName(), p.protectedName()) + self.assertEqual(p.callProtectedName(), p.protectedName()) + + def testReimplementedProtectedCall(self): + '''Calls a reimplemented virtual protected method.''' + original_name = 'Poly' + p = ExtendedProtectedPolymorphic(original_name) + name = p.callProtectedName() + self.assertTrue(p.protectedName_called) + self.assertEqual(p.protectedName(), name) + self.assertEqual(ProtectedPolymorphic.protectedName(p), original_name) +class ProtectedPolymorphicDaugherTest(unittest.TestCase): + '''Test cases for protected method in a class inheriting for a class with virtual methods.''' + + def testProtectedCallWithInstanceCreatedOnCpp(self): + '''Calls a virtual protected method from parent class on an instance created in C++.''' + p = ProtectedPolymorphicDaughter.create() + self.assertEqual(p.publicName(), p.protectedName()) + self.assertEqual(p.callProtectedName(), p.protectedName()) + + def testReimplementedProtectedCall(self): + '''Calls a reimplemented virtual protected method from parent class.''' + original_name = 'Poly' + p = ExtendedProtectedPolymorphicDaughter(original_name) + name = p.callProtectedName() + self.assertTrue(p.protectedName_called) + self.assertEqual(p.protectedName(), name) + self.assertEqual(ProtectedPolymorphicDaughter.protectedName(p), original_name) + + +class ProtectedPolymorphicGrandDaugherTest(unittest.TestCase): + '''Test cases for protected method in a class inheriting for a class that inherits from + another with protected virtual methods.''' + + def tearDown(self): + self.assertEqual(cacheSize(), 0) + + def testProtectedCallWithInstanceCreatedOnCpp(self): + '''Calls a virtual protected method from parent class on an instance created in C++.''' + p = ProtectedPolymorphicGrandDaughter.create() + self.assertEqual(p.publicName(), p.protectedName()) + self.assertEqual(p.callProtectedName(), p.protectedName()) + + def testReimplementedProtectedCall(self): + '''Calls a reimplemented virtual protected method from parent class.''' + original_name = 'Poly' + p = ExtendedProtectedPolymorphicGrandDaughter(original_name) + name = p.callProtectedName() + self.assertTrue(p.protectedName_called) + self.assertEqual(p.protectedName(), name) + self.assertEqual(ProtectedPolymorphicGrandDaughter.protectedName(p), original_name) + +class ProtectedVirtualDtorTest(unittest.TestCase): + '''Test cases for protected virtual destructor.''' + + def setUp(self): + ProtectedVirtualDestructor.resetDtorCounter() + + def tearDown(self): + self.assertEqual(cacheSize(), 0) + + def testVirtualProtectedDtor(self): + '''Original protected virtual destructor is being called.''' + dtor_called = ProtectedVirtualDestructor.dtorCalled() + for i in range(1, 10): + pvd = ProtectedVirtualDestructor() + del pvd + self.assertEqual(ProtectedVirtualDestructor.dtorCalled(), dtor_called + i) + + def testVirtualProtectedDtorOnCppCreatedObject(self): + '''Original protected virtual destructor is being called for a C++ created object.''' + dtor_called = ProtectedVirtualDestructor.dtorCalled() + for i in range(1, 10): + pvd = ProtectedVirtualDestructor.create() + del pvd + self.assertEqual(ProtectedVirtualDestructor.dtorCalled(), dtor_called + i) + + def testProtectedDtorOnDerivedClass(self): + '''Original protected virtual destructor is being called for a derived class.''' + dtor_called = ExtendedProtectedVirtualDestructor.dtorCalled() + for i in range(1, 10): + pvd = ExtendedProtectedVirtualDestructor() + del pvd + self.assertEqual(ExtendedProtectedVirtualDestructor.dtorCalled(), dtor_called + i) + + +class ExtendedProtectedEnumClass(ProtectedEnumClass): + def __init__(self): + ProtectedEnumClass.__init__(self) + def protectedEnumMethod(self, value): + if value == ProtectedEnumClass.ProtectedItem0: + return ProtectedEnumClass.ProtectedItem1 + return ProtectedEnumClass.ProtectedItem0 + def publicEnumMethod(self, value): + if value == ProtectedEnumClass.PublicItem0: + return ProtectedEnumClass.PublicItem1 + return ProtectedEnumClass.PublicItem0 + +class ProtectedEnumTest(unittest.TestCase): + '''Test cases for protected enum.''' + + def tearDown(self): + self.assertEqual(cacheSize(), 0) + + def testProtectedMethodWithProtectedEnumArgument(self): + '''Calls protected method with protected enum argument.''' + obj = ProtectedEnumClass() + + self.assertEqual(type(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedEnum) + + self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem0) + self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem1) + + self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem0) + self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem1) + + def testProtectedMethodWithPublicEnumArgument(self): + '''Calls protected method with public enum argument.''' + obj = ProtectedEnumClass() + + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem0) + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem1) + + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem0) + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem1) + + def testOverriddenProtectedMethodWithProtectedEnumArgument(self): + '''Calls overridden protected method with protected enum argument.''' + obj = ExtendedProtectedEnumClass() + + self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem1) + self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem0) + + self.assertEqual(ProtectedEnumClass.protectedEnumMethod(obj, ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem0) + self.assertEqual(ProtectedEnumClass.protectedEnumMethod(obj, ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem1) + + self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem1) + self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem0) + + def testOverriddenProtectedMethodWithPublicEnumArgument(self): + '''Calls overridden protected method with public enum argument.''' + obj = ExtendedProtectedEnumClass() + + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem1) + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem0) + + self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem0) + self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem1) + + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem1) + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem0) + + +class ProtectedPropertyTest(unittest.TestCase): + '''Test cases for a class with a protected property (or field in C++).''' + + def setUp(self): + self.obj = ProtectedProperty() + + def tearDown(self): + del self.obj + self.assertEqual(cacheSize(), 0) + + def testProtectedProperty(self): + '''Writes and reads a protected integer property.''' + self.obj.protectedProperty = 3 + self.assertEqual(self.obj.protectedProperty, 3) + + def testProtectedContainerProperty(self): + '''Writes and reads a protected list of integers property.''' + lst = [1, 2, 3, 4] + self.obj.protectedContainerProperty = lst + self.assertEqual(self.obj.protectedContainerProperty, lst) + + def testProtectedEnumProperty(self): + '''Writes and reads a protected enum property.''' + self.obj.protectedEnumProperty = Event.SOME_EVENT + self.assertEqual(self.obj.protectedEnumProperty, Event.SOME_EVENT) + + def testProtectedValueTypeProperty(self): + '''Writes and reads a protected value type property.''' + point = Point(12, 34) + self.obj.protectedValueTypeProperty = point + self.assertEqual(self.obj.protectedValueTypeProperty, point) + self.assertFalse(self.obj.protectedValueTypeProperty is point) + pointProperty = self.obj.protectedValueTypeProperty + self.assertTrue(self.obj.protectedValueTypeProperty is pointProperty) + + def testProtectedValueTypePropertyWrapperRegistration(self): + '''Access colocated protected value type property.''' + cache_size = cacheSize() + point = Point(12, 34) + obj = createProtectedProperty() + obj.protectedValueTypeProperty + self.assertEqual(obj.protectedValueTypeProperty.copy(), + obj.protectedValueTypeProperty) + obj.protectedValueTypeProperty = point + self.assertEqual(obj.protectedValueTypeProperty, point) + self.assertFalse(obj.protectedValueTypeProperty is point) + pointProperty = obj.protectedValueTypeProperty + self.assertTrue(obj.protectedValueTypeProperty is pointProperty) + del obj, point, pointProperty + self.assertEqual(cacheSize(), cache_size) + + def testProtectedValueTypePointerProperty(self): + '''Writes and reads a protected value type pointer property.''' + pt1 = Point(12, 34) + pt2 = Point(12, 34) + self.obj.protectedValueTypePointerProperty = pt1 + self.assertEqual(self.obj.protectedValueTypePointerProperty, pt1) + self.assertEqual(self.obj.protectedValueTypePointerProperty, pt2) + self.assertTrue(self.obj.protectedValueTypePointerProperty is pt1) + self.assertFalse(self.obj.protectedValueTypePointerProperty is pt2) + + def testProtectedObjectTypeProperty(self): + '''Writes and reads a protected object type property.''' + obj = ObjectType() + self.obj.protectedObjectTypeProperty = obj + self.assertEqual(self.obj.protectedObjectTypeProperty, obj) + + +class PrivateDtorProtectedMethodTest(unittest.TestCase): + '''Test cases for classes with private destructors and protected methods.''' + + def tearDown(self): + self.assertEqual(cacheSize(), 0) + + def testProtectedMethod(self): + '''Calls protected method of a class with a private destructor.''' + obj = PrivateDtor.instance() + + self.assertEqual(type(obj), PrivateDtor) + self.assertEqual(obj.instanceCalls(), 1) + self.assertEqual(obj.instanceCalls(), obj.protectedInstanceCalls()) + obj = PrivateDtor.instance() + self.assertEqual(obj.instanceCalls(), 2) + self.assertEqual(obj.instanceCalls(), obj.protectedInstanceCalls()) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/pstrlist_test.py b/sources/shiboken2/tests/samplebinding/pstrlist_test.py new file mode 100644 index 000000000..47e89bacb --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/pstrlist_test.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 +import sample + +class PStrListTest(unittest.TestCase): + + def testPStrList(self): + a = 'str0' + b = 'str1' + lst = sample.createPStrList(a, b) + self.assertEqual(lst, [a, b]) + + def testListOfPStr(self): + a = 'str0' + b = 'str1' + lst = sample.createListOfPStr(a, b) + self.assertEqual(lst, [a, b]) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/pystr_test.py b/sources/shiboken2/tests/samplebinding/pystr_test.py new file mode 100644 index 000000000..9056e96b7 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/pystr_test.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 definition of __str__ method.''' + +import sys +import unittest + +from sample import Point + +class PyStrTest(unittest.TestCase): + '''Test case for definition of __str__ method.''' + + def testPyStr(self): + '''Test case for defined __str__ method.''' + pt = Point(5, 2) + self.assertEqual(str(pt), 'Point(5.0, 2.0)') + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/python_thread_test.py b/sources/shiboken2/tests/samplebinding/python_thread_test.py new file mode 100644 index 000000000..dcd59ee1f --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/python_thread_test.py @@ -0,0 +1,116 @@ +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +#!/usr/bin/env python + +'''Tests for using Shiboken-based bindings with python threads''' + +import unittest +import threading +import sample +import time + +import logging + +#logging.basicConfig(level=logging.DEBUG) + +from random import random + +class Producer(threading.Thread): + '''Producer thread''' + + def __init__(self, bucket, max_runs, *args): + #Constructor. Receives the bucket + super(Producer, self).__init__(*args) + self.runs = 0 + self.bucket = bucket + self.max_runs = max_runs + self.production_list = [] + + def run(self): + while self.runs < self.max_runs: + value = int(random()*10) % 10 + self.bucket.push(value) + self.production_list.append(value) + logging.debug('PRODUCER - pushed %d' % value) + self.runs += 1 + #self.msleep(5) + time.sleep(0.01) + + +class Consumer(threading.Thread): + '''Consumer thread''' + def __init__(self, bucket, max_runs, *args): + #Constructor. Receives the bucket + super(Consumer, self).__init__(*args) + self.runs = 0 + self.bucket = bucket + self.max_runs = max_runs + self.consumption_list = [] + + def run(self): + while self.runs < self.max_runs: + if not self.bucket.empty(): + value = self.bucket.pop() + self.consumption_list.append(value) + logging.debug('CONSUMER - got %d' % value) + self.runs += 1 + else: + logging.debug('CONSUMER - empty bucket') + time.sleep(0.01) + +class ProducerConsumer(unittest.TestCase): + '''Basic test case for producer-consumer QThread''' + + def finishCb(self): + #Quits the application + self.app.exit(0) + + def testProdCon(self): + #QThread producer-consumer example + bucket = sample.Bucket() + prod = Producer(bucket, 10) + cons = Consumer(bucket, 10) + + prod.start() + cons.start() + + #QObject.connect(prod, SIGNAL('finished()'), self.finishCb) + #QObject.connect(cons, SIGNAL('finished()'), self.finishCb) + + prod.join() + cons.join() + + self.assertEqual(prod.production_list, cons.consumption_list) + + + + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/receive_null_cstring_test.py b/sources/shiboken2/tests/samplebinding/receive_null_cstring_test.py new file mode 100644 index 000000000..12cc67142 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/receive_null_cstring_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 case for a function that could receive a NULL pointer in a '[const] char*' parameter.''' + +import unittest + +from sample import countCharacters + +class ReceiveNullCStringTest(unittest.TestCase): + '''Test case for a function that could receive a NULL pointer in a '[const] char*' parameter.''' + + def testBasic(self): + '''The test function should be working for the basic cases.''' + a = '' + b = 'abc' + self.assertEqual(countCharacters(a), len(a)) + self.assertEqual(countCharacters(b), len(b)) + + def testReceiveNull(self): + '''The test function returns '-1' when receives a None value instead of a string.''' + self.assertEqual(countCharacters(None), -1) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/reference_test.py b/sources/shiboken2/tests/samplebinding/reference_test.py new file mode 100644 index 000000000..aaf809451 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/reference_test.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 methods that receive references to objects.''' + +import sys +import unittest + +from sample import * + +class ExtendedReference(Reference): + def __init__(self): + Reference.__init__(self) + self.uses_reference_virtual_called = False + self.uses_const_reference_virtual_called = False + self.reference_inc = 1 + self.const_reference_inc = 2 + self.multiplier = 333 + + def usesReferenceVirtual(self, ref, inc): + self.uses_reference_virtual_called = True + return ref.objId() + inc + self.reference_inc + + def usesConstReferenceVirtual(self, ref, inc): + self.uses_const_reference_virtual_called = True + return ref.objId() + inc + self.const_reference_inc + + def alterReferenceIdVirtual(self, ref): + ref.setObjId(ref.objId() * self.multiplier) + + +class ReferenceTest(unittest.TestCase): + '''Test case for methods that receive references to objects.''' + + def testMethodThatReceivesReference(self): + '''Test a method that receives a reference to an object as argument.''' + objId = 123 + r = Reference(objId) + self.assertEqual(Reference.usesReference(r), objId) + + def testCantSegFaultWhenReceiveNone(self): + '''do not segfault when receiving None as argument.''' + s = Str() + self.assertTrue(None == s) + + def testMethodThatReceivesConstReference(self): + '''Test a method that receives a const reference to an object as argument.''' + objId = 123 + r = Reference(objId) + self.assertEqual(Reference.usesConstReference(r), objId) + + def testModificationOfReference(self): + '''Tests if the identity of a reference argument is preserved when passing it to be altered in C++.''' + objId = 123 + r1 = Reference(objId) + r1.alterReferenceIdVirtual(r1) + self.assertEqual(r1.objId(), objId * Reference.multiplier()) + + def testModificationOfReferenceCallingAVirtualIndirectly(self): + '''Tests if the identity of a reference argument is preserved when passing it to be altered in C++ through a method that calls a virtual method.''' + objId = 123 + r1 = Reference(objId) + r1.callAlterReferenceIdVirtual(r1) + self.assertEqual(r1.objId(), objId * Reference.multiplier()) + + def testModificationOfReferenceCallingAReimplementedVirtualIndirectly(self): + '''Test if a Python override of a virtual method with a reference parameter called from C++ alters the argument properly.''' + objId = 123 + r = Reference(objId) + er = ExtendedReference() + result = er.callAlterReferenceIdVirtual(r) + self.assertEqual(r.objId(), objId * er.multiplier) + + def testReimplementedVirtualMethodCallWithReferenceParameter(self): + '''Test if a Python override of a virtual method with a reference parameter is correctly called from C++.''' + inc = 9 + objId = 123 + r = Reference(objId) + er = ExtendedReference() + result = er.callUsesReferenceVirtual(r, inc) + self.assertEqual(result, objId + inc + er.reference_inc) + + def testReimplementedVirtualMethodCallWithConstReferenceParameter(self): + '''Test if a Python override of a virtual method with a const reference parameter is correctly called from C++.''' + inc = 9 + objId = 123 + r = Reference(objId) + er = ExtendedReference() + result = er.callUsesConstReferenceVirtual(r, inc) + self.assertEqual(result, objId + inc + er.const_reference_inc) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/referencetopointer_test.py b/sources/shiboken2/tests/samplebinding/referencetopointer_test.py new file mode 100644 index 000000000..8d85032a0 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/referencetopointer_test.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 a reference to pointer argument type.''' + +import unittest + +from sample import VirtualMethods, Str + +class ExtendedVirtualMethods(VirtualMethods): + def __init__(self): + VirtualMethods.__init__(self) + self.prefix = 'Ext' + + def createStr(self, text): + ext_text = text + if text is not None: + ext_text = self.prefix + text + return VirtualMethods.createStr(self, ext_text) + + +class ReferenceToPointerTest(unittest.TestCase): + '''Test cases for a reference to pointer argument type.''' + + def testSimpleCallWithNone(self): + '''Simple call to createStr method with a None argument.''' + obj = VirtualMethods() + ok, string = obj.createStr(None) + self.assertFalse(ok) + self.assertEqual(string, None) + + def testSimpleCallWithString(self): + '''Simple call to createStr method with a Python string argument.''' + obj = VirtualMethods() + ok, string = obj.createStr('foo') + self.assertTrue(ok) + self.assertEqual(string, Str('foo')) + + def testCallNonReimplementedMethodWithNone(self): + '''Calls createStr method from C++ with a None argument.''' + obj = VirtualMethods() + ok, string = obj.callCreateStr(None) + self.assertFalse(ok) + self.assertEqual(string, None) + + def testCallNonReimplementedMethodWithString(self): + '''Calls createStr method from C++ with a Python string argument.''' + obj = VirtualMethods() + ok, string = obj.callCreateStr('foo') + self.assertTrue(ok) + self.assertEqual(string, Str('foo')) + + def testCallReimplementedMethodWithNone(self): + '''Calls reimplemented createStr method from C++ with a None argument.''' + obj = ExtendedVirtualMethods() + ok, string = obj.callCreateStr(None) + self.assertFalse(ok) + self.assertEqual(string, None) + + def testCallReimplementedMethodWithString(self): + '''Calls reimplemented createStr method from C++ with a Python string argument.''' + obj = ExtendedVirtualMethods() + ok, string = obj.callCreateStr('foo') + self.assertTrue(ok) + self.assertEqual(string, Str(obj.prefix + 'foo')) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/return_null_test.py b/sources/shiboken2/tests/samplebinding/return_null_test.py new file mode 100644 index 000000000..377624482 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/return_null_test.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 case for functions that could return a NULL pointer.''' + +import sys +import unittest + +from sample import returnNullPrimitivePointer, returnNullValueTypePointer, returnNullObjectTypePointer + +class ReturnNullTest(unittest.TestCase): + '''Test case for functions that could return a NULL pointer.''' + + def testReturnNull(self): + '''Function returns a NULL pointer to a primitive type.''' + o = returnNullPrimitivePointer() + self.assertEqual(o, None) + + def testReturnNullObjectType(self): + '''Function returns a NULL pointer to an object-type.''' + o = returnNullObjectTypePointer() + self.assertEqual(o, None) + + def testReturnNullValueType(self): + '''Function returns a NULL pointer to a value-type.''' + o = returnNullValueTypePointer() + self.assertEqual(o, None) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/richcompare_test.py b/sources/shiboken2/tests/samplebinding/richcompare_test.py new file mode 100644 index 000000000..8c5eea694 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/richcompare_test.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 * + +class TestRichCompare(unittest.TestCase): + + def testIt(self): + a = Expression(2) + b = Expression(3) + c = a + b + d = a + c < b + a + self.assertEqual(d.toString(), "((2+(2+3))<(3+2))") + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/sample-binding.txt.in b/sources/shiboken2/tests/samplebinding/sample-binding.txt.in new file mode 100644 index 000000000..317f76f09 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/sample-binding.txt.in @@ -0,0 +1,15 @@ +[generator-project] + +generator-set = shiboken + +header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h +typesystem-file = @sample_TYPESYSTEM@ + +output-directory = @CMAKE_CURRENT_BINARY_DIR@ + +include-path = @libsample_SOURCE_DIR@ + +typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@ + +enable-parent-ctor-heuristic +use-isnull-as-nb_nonzero diff --git a/sources/shiboken2/tests/samplebinding/sample_test.py b/sources/shiboken2/tests/samplebinding/sample_test.py new file mode 100644 index 000000000..65d1d2871 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/sample_test.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 libsample bindings module''' + +import unittest + +import sample + +class ModuleTest(unittest.TestCase): + '''Test case for module and global functions''' + + def testModuleMembers(self): + '''Test availability of classes, global functions and other members on binding''' + expected_members = set(['Abstract', 'Derived', 'Point', + 'ListUser', 'PairUser', 'MapUser', + 'gimmeComplexList', 'gimmeDouble', 'gimmeInt', + 'makeCString', 'multiplyPair', 'returnCString', + 'SampleNamespace', 'transmuteComplexIntoPoint', + 'transmutePointIntoComplex', 'sumComplexPair', + 'FirstThing', 'SecondThing', 'ThirdThing', + 'GlobalEnum', 'NoThing']) + self.assertTrue(expected_members.issubset(dir(sample))) + + def testAbstractPrintFormatEnum(self): + '''Test availability of PrintFormat enum from Abstract class''' + enum_members = set(['PrintFormat', 'Short', 'Verbose', + 'OnlyId', 'ClassNameAndId']) + self.assertTrue(enum_members.issubset(dir(sample.Abstract))) + + def testSampleNamespaceOptionEnum(self): + '''Test availability of Option enum from SampleNamespace namespace''' + enum_members = set(['Option', 'None_', 'RandomNumber', 'UnixTime']) + self.assertTrue(enum_members.issubset(dir(sample.SampleNamespace))) + + def testAddedFunctionAtModuleLevel(self): + '''Calls function added to module from type system description.''' + str1 = 'Foo' + self.assertEqual(sample.multiplyString(str1, 3), str1 * 3) + self.assertEqual(sample.multiplyString(str1, 0), str1 * 0) + + def testAddedFunctionWithVarargs(self): + '''Calls function that receives varargs added to module from type system description.''' + self.assertEqual(sample.countVarargs(1), 0) + self.assertEqual(sample.countVarargs(1, 2), 1) + self.assertEqual(sample.countVarargs(1, 2, 3, 'a', 'b', 4, (5, 6)), 6) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/simplefile_glue.cpp b/sources/shiboken2/tests/samplebinding/simplefile_glue.cpp new file mode 100644 index 000000000..a7f05eb99 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/simplefile_glue.cpp @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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$ +** +****************************************************************************/ + +if (!%CPPSELF.%FUNCTION_NAME()) { + PyObject* error_msg = PyBytes_FromFormat( + "Could not open file: \"%s\"", %CPPSELF->filename()); + PyErr_SetObject(PyExc_IOError, error_msg); + return 0; +} diff --git a/sources/shiboken2/tests/samplebinding/simplefile_test.py b/sources/shiboken2/tests/samplebinding/simplefile_test.py new file mode 100644 index 000000000..c2a1afe59 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/simplefile_test.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 SimpleFile class''' + +import os +import unittest + +from sample import SimpleFile + +class SimpleFileTest(unittest.TestCase): + '''Test cases for SimpleFile class.''' + + def setUp(self): + filename = 'simplefile%d.txt' % os.getpid() + self.existing_filename = os.path.join(os.path.curdir, filename) + self.delete_file = False + if not os.path.exists(self.existing_filename): + f = open(self.existing_filename, 'w') + for line in range(10): + f.write('sbrubbles\n') + f.close() + self.delete_file = True + + self.non_existing_filename = os.path.join(os.path.curdir, 'inexistingfile.txt') + i = 0 + while os.path.exists(self.non_existing_filename): + i += 1 + filename = 'inexistingfile-%d.txt' % i + self.non_existing_filename = os.path.join(os.path.curdir, filename) + + def tearDown(self): + if self.delete_file: + os.remove(self.existing_filename) + + def testExistingFile(self): + '''Test SimpleFile class with existing file.''' + f = SimpleFile(self.existing_filename) + self.assertEqual(f.filename(), self.existing_filename) + f.open() + self.assertNotEqual(f.size(), 0) + f.close() + + def testNonExistingFile(self): + '''Test SimpleFile class with non-existing file.''' + f = SimpleFile(self.non_existing_filename) + self.assertEqual(f.filename(), self.non_existing_filename) + self.assertRaises(IOError, f.open) + self.assertEqual(f.size(), 0) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/size_test.py b/sources/shiboken2/tests/samplebinding/size_test.py new file mode 100644 index 000000000..502539689 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/size_test.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 operator overloads on Size class''' + +import unittest + +from sample import Size + +class PointTest(unittest.TestCase): + '''Test case for Size class, including operator overloads.''' + + def testConstructor(self): + '''Test Size class constructor.''' + width, height = (5.0, 2.3) + size = Size(width, height) + self.assertEqual(size.width(), width) + self.assertEqual(size.height(), height) + self.assertEqual(size.calculateArea(), width * height) + + def testCopyConstructor(self): + '''Test Size class copy constructor.''' + width, height = (5.0, 2.3) + s1 = Size(width, height) + s2 = Size(s1) + self.assertFalse(s1 is s2) + self.assertEqual(s1, s2) + + def testPlusOperator(self): + '''Test Size class + operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(0.5, 3.2) + self.assertEqual(s1 + s2, Size(5.0 + 0.5, 2.3 + 3.2)) + + def testEqualOperator(self): + '''Test Size class == operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(5.0, 2.3) + s3 = Size(0.5, 3.2) + self.assertTrue(s1 == s1) + self.assertTrue(s1 == s2) + self.assertFalse(s1 == s3) + + def testNotEqualOperator(self): + '''Test Size class != operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(5.0, 2.3) + s3 = Size(0.5, 3.2) + self.assertFalse(s1 != s1) + self.assertFalse(s1 != s2) + self.assertTrue(s1 != s3) + + def testMinorEqualOperator(self): + '''Test Size class <= operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(5.0, 2.3) + s3 = Size(0.5, 3.2) + self.assertTrue(s1 <= s1) + self.assertTrue(s1 <= s2) + self.assertTrue(s3 <= s1) + self.assertFalse(s1 <= s3) + + def testMinorOperator(self): + '''Test Size class < operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(0.5, 3.2) + self.assertFalse(s1 < s1) + self.assertFalse(s1 < s2) + self.assertTrue(s2 < s1) + + def testMajorEqualOperator(self): + '''Test Size class >= operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(5.0, 2.3) + s3 = Size(0.5, 3.2) + self.assertTrue(s1 >= s1) + self.assertTrue(s1 >= s2) + self.assertTrue(s1 >= s3) + self.assertFalse(s3 >= s1) + + def testMajorOperator(self): + '''Test Size class > operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(0.5, 3.2) + self.assertFalse(s1 > s1) + self.assertTrue(s1 > s2) + self.assertFalse(s2 > s1) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/static_nonstatic_methods_test.py b/sources/shiboken2/tests/samplebinding/static_nonstatic_methods_test.py new file mode 100644 index 000000000..6451c4440 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/static_nonstatic_methods_test.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 overloads involving static and non-static versions of a method.''' + +import os +import unittest + +from sample import SimpleFile + +class SimpleFile2 (SimpleFile): + def exists(self): + return "Mooo" + +class SimpleFile3 (SimpleFile): + pass + +class SimpleFile4 (SimpleFile): + exists = 5 + +class StaticNonStaticMethodsTest(unittest.TestCase): + '''Test cases for overloads involving static and non-static versions of a method.''' + + def setUp(self): + filename = 'simplefile%d.txt' % os.getpid() + self.existing_filename = os.path.join(os.path.curdir, filename) + self.delete_file = False + if not os.path.exists(self.existing_filename): + f = open(self.existing_filename, 'w') + for line in range(10): + f.write('sbrubbles\n') + f.close() + self.delete_file = True + + self.non_existing_filename = os.path.join(os.path.curdir, 'inexistingfile.txt') + i = 0 + while os.path.exists(self.non_existing_filename): + i += 1 + filename = 'inexistingfile-%d.txt' % i + self.non_existing_filename = os.path.join(os.path.curdir, filename) + + def tearDown(self): + if self.delete_file: + os.remove(self.existing_filename) + + def testCallingStaticMethodWithClass(self): + '''Call static method using class.''' + self.assertTrue(SimpleFile.exists(self.existing_filename)) + self.assertFalse(SimpleFile.exists(self.non_existing_filename)) + + def testCallingStaticMethodWithInstance(self): + '''Call static method using instance of class.''' + f = SimpleFile(self.non_existing_filename) + self.assertTrue(f.exists(self.existing_filename)) + self.assertFalse(f.exists(self.non_existing_filename)) + + def testCallingInstanceMethod(self): + '''Call instance method.''' + f1 = SimpleFile(self.non_existing_filename) + self.assertFalse(f1.exists()) + f2 = SimpleFile(self.existing_filename) + self.assertTrue(f2.exists()) + + def testOverridingStaticNonStaticMethod(self): + f = SimpleFile2(self.existing_filename) + self.assertEqual(f.exists(), "Mooo") + + f = SimpleFile3(self.existing_filename) + self.assertTrue(f.exists()) + + f = SimpleFile4(self.existing_filename) + self.assertEqual(f.exists, 5) + + def testDuckPunchingStaticNonStaticMethod(self): + f = SimpleFile(self.existing_filename) + f.exists = lambda : "Meee" + self.assertEqual(f.exists(), "Meee") + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/str_test.py b/sources/shiboken2/tests/samplebinding/str_test.py new file mode 100644 index 000000000..dca7e1f44 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/str_test.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 a method that receives a reference to class that is implicitly convertible from a Python native type.''' + +import unittest + +from sample import Str + +class StrTest(unittest.TestCase): + '''Test cases for thr Str class.''' + + def test__str__Method(self): + '''Test if the binding correcly implements the Python __str__ method.''' + s1 = 'original string' + s2 = Str(s1) + self.assertEqual(s1, s2) + self.assertEqual(s1, str(s2)) + + def testPassExactClassAsReferenceToArgument(self): + '''Test passing the expected class as an argument to a method that expects a reference.''' + s1 = Str('This is %VAR!').arg(Str('Sparta')) + self.assertEqual(str(s1), 'This is Sparta!') + + def testPassPythonTypeImplictlyConvertibleToAClassUsedAsReference(self): + '''Test passing a Python class implicitly convertible to a wrapped class that is expected to be passed as reference.''' + s1 = Str('This is %VAR!').arg('Athens') + self.assertEqual(str(s1), 'This is Athens!') + + def testSequenceOperators(self): + s1 = Str("abcdef") + self.assertEqual(len(s1), 6); + self.assertEqual(len(Str()), 0); + + # getitem + self.assertEqual(s1[0], "a"); + self.assertEqual(s1[1], "b"); + self.assertEqual(s1[2], "c"); + self.assertEqual(s1[3], "d"); + self.assertEqual(s1[4], "e"); + self.assertEqual(s1[5], "f"); + self.assertEqual(s1[-1], "f"); + self.assertEqual(s1[-2], "e"); + + self.assertRaises(TypeError, s1.__getitem__, 6) + + # setitem + s1[0] = 'A' + s1[1] = 'B' + self.assertEqual(s1[0], 'A'); + self.assertEqual(s1[1], 'B'); + self.assertRaises(TypeError, s1.__setitem__(6, 67)) + + def testReverseOperator(self): + s1 = Str("hello") + n1 = 2 + self.assertEqual(s1+2, "hello2") + self.assertEqual(2+s1, "2hello") + + def testToIntError(self): + self.assertEqual(Str('Z').toInt(), (0, False)) + + def testToIntWithDecimal(self): + decimal = Str('37') + val, ok = decimal.toInt() + self.assertEqual(type(val), int) + self.assertEqual(type(ok), bool) + self.assertEqual(val, int(str(decimal))) + + def testToIntWithOctal(self): + octal = Str('52') + val, ok = octal.toInt(8) + self.assertEqual(type(val), int) + self.assertEqual(type(ok), bool) + self.assertEqual(val, int(str(octal), 8)) + + def testToIntWithHexadecimal(self): + hexa = Str('2A') + val, ok = hexa.toInt(16) + self.assertEqual(type(val), int) + self.assertEqual(type(ok), bool) + self.assertEqual(val, int(str(hexa), 16)) + self.assertEqual(hexa.toInt(), (0, False)) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/strlist_test.py b/sources/shiboken2/tests/samplebinding/strlist_test.py new file mode 100644 index 000000000..341fcfa32 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/strlist_test.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 StrList class that inherits from std::list.''' + +import unittest + +from sample import Str, StrList + +class StrListTest(unittest.TestCase): + '''Test cases for StrList class that inherits from std::list.''' + + def testStrListCtor_NoParams(self): + '''StrList constructor receives no parameter.''' + sl = StrList() + self.assertEqual(len(sl), 0) + self.assertEqual(sl.constructorUsed(), StrList.NoParamsCtor) + + def testStrListCtor_Str(self): + '''StrList constructor receives a Str object.''' + s = Str('Foo') + sl = StrList(s) + self.assertEqual(len(sl), 1) + self.assertEqual(sl[0], s) + self.assertEqual(sl.constructorUsed(), StrList.StrCtor) + + def testStrListCtor_PythonString(self): + '''StrList constructor receives a Python string.''' + s = 'Foo' + sl = StrList(s) + self.assertEqual(len(sl), 1) + self.assertEqual(sl[0], s) + self.assertEqual(sl.constructorUsed(), StrList.StrCtor) + + def testStrListCtor_StrList(self): + '''StrList constructor receives a StrList object.''' + sl1 = StrList(Str('Foo')) + sl2 = StrList(sl1) + #self.assertEqual(len(sl1), len(sl2)) + #self.assertEqual(sl1, sl2) + self.assertEqual(sl2.constructorUsed(), StrList.CopyCtor) + + def testStrListCtor_ListOfStrs(self): + '''StrList constructor receives a Python list of Str objects.''' + strs = [Str('Foo'), Str('Bar')] + sl = StrList(strs) + self.assertEqual(len(sl), len(strs)) + self.assertEqual(sl, strs) + self.assertEqual(sl.constructorUsed(), StrList.ListOfStrCtor) + + def testStrListCtor_MixedListOfStrsAndPythonStrings(self): + '''StrList constructor receives a Python list of mixed Str objects and Python strings.''' + strs = [Str('Foo'), 'Bar'] + sl = StrList(strs) + self.assertEqual(len(sl), len(strs)) + self.assertEqual(sl, strs) + self.assertEqual(sl.constructorUsed(), StrList.ListOfStrCtor) + + def testCompareStrListWithTupleOfStrs(self): + '''Compares StrList with a Python tuple of Str objects.''' + sl = StrList() + sl.append(Str('Foo')) + sl.append(Str('Bar')) + self.assertEqual(len(sl), 2) + self.assertEqual(sl, (Str('Foo'), Str('Bar'))) + + def testCompareStrListWithTupleOfPythonStrings(self): + '''Compares StrList with a Python tuple of Python strings.''' + sl = StrList() + sl.append(Str('Foo')) + sl.append(Str('Bar')) + self.assertEqual(len(sl), 2) + self.assertEqual(sl, ('Foo', 'Bar')) + + def testCompareStrListWithTupleOfStrAndPythonString(self): + '''Compares StrList with a Python tuple of mixed Str objects and Python strings.''' + sl = StrList() + sl.append(Str('Foo')) + sl.append(Str('Bar')) + self.assertEqual(len(sl), 2) + self.assertEqual(sl, (Str('Foo'), 'Bar')) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/templateinheritingclass_test.py b/sources/shiboken2/tests/samplebinding/templateinheritingclass_test.py new file mode 100644 index 000000000..7acb6a597 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/templateinheritingclass_test.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Photon + +'''This tests classes that inherit from template classes, +simulating a situation found in Qt's phonon module.''' + +class TemplateInheritingClassTest(unittest.TestCase): + def testClassBasics(self): + self.assertEqual(Photon.ValueIdentity.classType(), Photon.IdentityType) + self.assertEqual(Photon.ValueDuplicator.classType(), Photon.DuplicatorType) + + def testInstanceBasics(self): + value = 123 + samer = Photon.ValueIdentity(value) + self.assertEqual(samer.multiplicator(), 1) + doubler = Photon.ValueDuplicator(value) + self.assertEqual(doubler.multiplicator(), 2) + self.assertEqual(samer.value(), doubler.value()) + self.assertEqual(samer.calculate() * 2, doubler.calculate()) + + def testPassToFunctionAsPointer(self): + obj = Photon.ValueDuplicator(123) + self.assertEqual(Photon.callCalculateForValueDuplicatorPointer(obj), obj.calculate()) + + def testPassToFunctionAsReference(self): + obj = Photon.ValueDuplicator(321) + self.assertEqual(Photon.callCalculateForValueDuplicatorReference(obj), obj.calculate()) + + def testPassToMethodAsValue(self): + value1, value2 = 123, 321 + one = Photon.ValueIdentity(value1) + other = Photon.ValueIdentity(value2) + self.assertEqual(one.sumValueUsingPointer(other), value1 + value2) + + def testPassToMethodAsReference(self): + value1, value2 = 123, 321 + one = Photon.ValueDuplicator(value1) + other = Photon.ValueDuplicator(value2) + self.assertEqual(one.sumValueUsingReference(other), value1 + value2) + + def testPassPointerThrough(self): + obj1 = Photon.ValueIdentity(123) + self.assertEqual(obj1, obj1.passPointerThrough(obj1)) + obj2 = Photon.ValueDuplicator(321) + self.assertEqual(obj2, obj2.passPointerThrough(obj2)) + self.assertRaises(TypeError, obj1.passPointerThrough, obj2) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/time_test.py b/sources/shiboken2/tests/samplebinding/time_test.py new file mode 100644 index 000000000..db8818fd3 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/time_test.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 constructor and method signature decisor on Time class.''' + +import sys +import unittest +import datetime + +from sample import Time, ImplicitConv, ObjectType + +class TimeTest(unittest.TestCase): + '''Test cases for constructor and method signature decisor on Time class. + The constructor and one method have these signatures: CTORMETHOD() and + CTORMETHOD(int h, int m, int s = 0, int ms = 0); there another method + with a more complex signature METH(int, int, ImplicitConv=DEFVALUE, ObjectType=0), + to produce an even worse scenario. + ''' + + def testConstructorWithoutParamers(self): + '''Constructor without parameters: Time()''' + time = Time() + self.assertTrue(time.isNull()) + + def testConstructorWithAllParamers(self): + '''Constructor with all parameters: Time(int h, int m, int s = 0, int ms = 0)''' + time = Time(1, 2, 3, 4) + self.assertTrue(time.toString(), '01:02:03.004') + + def testConstructorWithThreeParamers(self): + '''Constructor with 3 parameters: Time(int h, int m, int s = 0, int ms = 0)''' + time = Time(1, 2, 3) + self.assertTrue(time.toString(), '01:02:03.000') + + def testConstructorWithTwoParamers(self): + '''Constructor with 2 parameters: Time(int h, int m, int s = 0, int ms = 0)''' + time = Time(1, 2) + self.assertTrue(time.toString(), '01:02:00.000') + + def testSimpleMethodWithoutParamers(self): + '''Constructor without parameters: Time.setTime()''' + time = Time(1, 2, 3, 4) + time.setTime() + self.assertTrue(time.isNull()) + + def testSimpleMethodWithAllParamers(self): + '''Simple method with all parameters: Time.setTime(int h, int m, int s = 0, int ms = 0)''' + time = Time() + time.setTime(1, 2, 3, 4) + self.assertTrue(time.toString(), '01:02:03.004') + + def testSimpleMethodWithThreeParamers(self): + '''Simple method with 3 parameters: Time.setTime(int h, int m, int s = 0, int ms = 0)''' + time = Time() + time.setTime(1, 2, 3) + self.assertTrue(time.toString(), '01:02:03.000') + + def testSimpleMethodWithTwoParamers(self): + '''Simple method with 2 parameters: Time.setTime(int h, int m, int s = 0, int ms = 0)''' + time = Time() + time.setTime(1, 2) + self.assertTrue(time.toString(), '01:02:00.000') + + def testMethodWithoutParamers(self): + '''Method without parameters: Time.somethingCompletelyDifferent()''' + time = Time() + result = time.somethingCompletelyDifferent() + self.assertEqual(result, Time.ZeroArgs) + + def testMethodWithAllParamers(self): + '''Method with all parameters: + Time.somethingCompletelyDifferent( + int h, int m, ImplicitConv ic = ImplicitConv::CtorThree, ObjectType* type = 0 + ); + ''' + time = Time() + obj = ObjectType() + result = time.somethingCompletelyDifferent(1, 2, ImplicitConv(2), obj) + self.assertEqual(result, Time.FourArgs) + + def testMethodWithThreeParamers(self): + '''Method with 3 parameters: Time.somethingCompletelyDifferent(...)''' + time = Time() + result = time.somethingCompletelyDifferent(1, 2, ImplicitConv(ImplicitConv.CtorOne)) + self.assertEqual(result, Time.ThreeArgs) + + def testMethodWithTwoParamers(self): + '''Method with 2 parameters: Time.somethingCompletelyDifferent(...)''' + time = Time() + result = time.somethingCompletelyDifferent(1, 2) + self.assertEqual(result, Time.TwoArgs) + + def testMethodWithThreeParamersAndImplicitConversion(self): + '''Method with 3 parameters, the last one triggers an implicit conversion.''' + time = Time() + result = time.somethingCompletelyDifferent(1, 2, ImplicitConv.CtorOne) + self.assertEqual(result, Time.ThreeArgs) + + def testCompareWithPythonTime(self): + time = Time(12, 32, 5) + py = datetime.time(12, 32, 5) + self.assertEqual(time, py) + + def testNotEqual(self): + time = Time(12, 32, 6) + py = datetime.time(12, 32, 5) + self.assertNotEqual(time, py) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/transform_test.py b/sources/shiboken2/tests/samplebinding/transform_test.py new file mode 100644 index 000000000..f490945b8 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/transform_test.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 argument modification with more than nine arguments.''' + +import unittest + +from sample import Point, applyHomogeneousTransform + +class TransformTest(unittest.TestCase): + '''Test cases for modifying a function with > 9 arguments.''' + + def testTransform_ValidMatrix(self): + '''Transform applies successfully.''' + p = Point(3, 4) + r = applyHomogeneousTransform(p, 0, 1, 0, -1, 0, 0, 0, 0, 1) + self.assertTrue(type(r) is Point) + self.assertEqual(r.x(), 4) + self.assertEqual(r.y(), -3) + + def testTransform_InvalidMatrix(self): + '''Transform does not apply successfully.''' + p = Point(3, 4) + r = applyHomogeneousTransform(p, 1, 0, 0, 0, 1, 0, 0, 0, 0) + self.assertTrue(r is None) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/typeconverters_test.py b/sources/shiboken2/tests/samplebinding/typeconverters_test.py new file mode 100644 index 000000000..b3b469c56 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/typeconverters_test.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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$ +## +############################################################################# + +'''Tests various usages of the type converters.''' + +import unittest +import sample + +class GetPythonTypeByNameTest(unittest.TestCase): + + '''Uses an added function with inject code that uses the libshiboken + function "Shiboken::Conversions::getPythonTypeObject(typeName)".''' + + def testGetObjectType(self): + pyType1 = sample.getPythonType('ObjectType') + self.assertEqual(pyType1, sample.ObjectType) + pyType2 = sample.getPythonType('ObjectType*') + self.assertEqual(pyType2, sample.ObjectType) + self.assertEqual(pyType1, pyType2) + + def testGetValueType(self): + pyType1 = sample.getPythonType('Point') + self.assertEqual(pyType1, sample.Point) + pyType2 = sample.getPythonType('Point*') + self.assertEqual(pyType2, sample.Point) + self.assertEqual(pyType1, pyType2) + + def testGetUsersPrimitiveType(self): + pyType = sample.getPythonType('OddBool') + self.assertEqual(pyType, bool) + + def testGetUsersPrimitiveTypeWithoutTargetLangApiName(self): + '''If the primitive type attribute "target-lang-api-name" is not set + there'll be no Python type associated with the C++ type.''' + pyType = sample.getPythonType('PStr') + self.assertEqual(pyType, None) + + def testPrimitiveTypeAndTypedef(self): + pyType = sample.getPythonType('double') + self.assertEqual(pyType, float) + pyTypedef = sample.getPythonType('real') + self.assertEqual(pyType, pyTypedef) + + def testPairContainerType(self): + pyType = sample.getPythonType('std::pair') + self.assertEqual(pyType, list) + + def testListContainerType(self): + pyType = sample.getPythonType('std::list') + self.assertEqual(pyType, list) + + def testMapContainerType(self): + pyType = sample.getPythonType('std::map') + self.assertEqual(pyType, dict) + + def testGlobalEnumType(self): + pyType = sample.getPythonType('GlobalEnum') + self.assertEqual(pyType, sample.GlobalEnum) + + def testScopedEnumType(self): + pyType = sample.getPythonType('Abstract::Type') + self.assertEqual(pyType, sample.Abstract.Type) + + +class CheckValueAndObjectTypeByNameTest(unittest.TestCase): + + '''Uses an added function with inject code that uses the libshiboken + functions that check if a type is Object or Value, based on its converter.''' + + def testErrors(self): + '''not existent type''' + self.assertRaises(ValueError, sample.cppTypeIsValueType, 'NotExistentType') + self.assertRaises(ValueError, sample.cppTypeIsObjectType, 'NotExistentType') + + def testObjectType1(self): + self.assertTrue(sample.cppTypeIsObjectType('ObjectType')) + self.assertFalse(sample.cppTypeIsValueType('ObjectType')) + + def testObjectType2(self): + self.assertTrue(sample.cppTypeIsObjectType('ObjectType*')) + self.assertFalse(sample.cppTypeIsValueType('ObjectType*')) + + def testValueType1(self): + self.assertTrue(sample.cppTypeIsValueType('Point')) + self.assertFalse(sample.cppTypeIsObjectType('Point')) + + def testValueType2(self): + self.assertTrue(sample.cppTypeIsValueType('Point*')) + self.assertFalse(sample.cppTypeIsObjectType('Point*')) + + def testUsersPrimitiveType(self): + self.assertFalse(sample.cppTypeIsValueType('Complex')) + self.assertFalse(sample.cppTypeIsObjectType('Complex')) + + def testContainerType(self): + self.assertFalse(sample.cppTypeIsValueType('std::list')) + self.assertFalse(sample.cppTypeIsObjectType('std::list')) + + +class SpecificConverterTest(unittest.TestCase): + + '''Uses an added function with inject code that uses the libshiboken + adapter class "Shiboken::Conversions::SpecificConverter".''' + + def testNotExistentType(self): + conversion = sample.getConversionTypeString('NotExistentType') + self.assertEqual(conversion, 'Invalid conversion') + + def testObjectType(self): + conversion = sample.getConversionTypeString('ObjectType') + self.assertEqual(conversion, 'Pointer conversion') + conversion = sample.getConversionTypeString('ObjectType*') + self.assertEqual(conversion, 'Pointer conversion') + conversion = sample.getConversionTypeString('ObjectType&') + self.assertEqual(conversion, 'Reference conversion') + + def testValueType(self): + conversion = sample.getConversionTypeString('Point') + self.assertEqual(conversion, 'Copy conversion') + conversion = sample.getConversionTypeString('Point*') + self.assertEqual(conversion, 'Pointer conversion') + conversion = sample.getConversionTypeString('Point&') + self.assertEqual(conversion, 'Reference conversion') + + +class StringBasedConversionTest(unittest.TestCase): + + def testValueType(self): + pts = (sample.Point(1, 1), sample.Point(2, 2), sample.Point(3, 3)) + result = sample.convertValueTypeToCppAndThenToPython(pts[0], pts[1], pts[2]) + for orig, new in zip(pts, result): + self.assertEqual(orig, new) + self.assertFalse(pts[0] is result[0]) + self.assertTrue(pts[1] is result[1]) + self.assertTrue(pts[2] is result[2]) + + def testObjectType(self): + objs = (sample.ObjectType(), sample.ObjectType()) + objs[0].setObjectName('obj0') + objs[1].setObjectName('obj1') + result = sample.convertObjectTypeToCppAndThenToPython(objs[0], objs[1]) + for orig, new in zip(objs, result): + self.assertEqual(orig, new) + self.assertEqual(orig.objectName(), new.objectName()) + self.assertTrue(orig is new) + + def testContainerType(self): + lst = range(4) + result = sample.convertListOfIntegersToCppAndThenToPython(lst) + self.assertTrue(len(result), 1) + self.assertTrue(lst, result[0]) + + def testCppPrimitiveType(self): + integers = (12, 34) + result = sample.convertIntegersToCppAndThenToPython(integers[0], integers[1]) + for orig, new in zip(integers, result): + self.assertEqual(orig, new) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/typedealloc_test.py b/sources/shiboken2/tests/samplebinding/typedealloc_test.py new file mode 100644 index 000000000..b0fe763e0 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/typedealloc_test.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 deallocation of type extended in Python.''' + +import gc +import weakref +import unittest + +from sample import Point + + +class TypeDeallocTest(unittest.TestCase): + + def setUp(self): + self.called = False + + def tearDown(self): + del self.called + + def callback(self, *args): + self.called = True + + def testScopeEnd(self): + ref = None + def scope(): + class Ext(Point): + pass + o = Ext() + global ref + ref = weakref.ref(Ext, self.callback) + scope() + gc.collect() + self.assertTrue(self.called) + + def testDeleteType(self): + class Ext(Point): + pass + ref = weakref.ref(Ext, self.callback) + del Ext + gc.collect() + self.assertTrue(self.called) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/typedtordoublefree_test.py b/sources/shiboken2/tests/samplebinding/typedtordoublefree_test.py new file mode 100644 index 000000000..1106c8761 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/typedtordoublefree_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 ObjectType + +class TestTypeDestructorDoubleFree(unittest.TestCase): + def testTypeDestructorDoubleFree(self): + '''Causes the type destructors of two derived classes to be called.''' + def scope(): + class ExtObj1(ObjectType): + def __init__(self): + ObjectType.__init__(self) + obj = ExtObj1() + child = ObjectType(parent=obj) + self.assertEqual(obj.takeChild(child), child) + class ExtObj2(ObjectType): + def __init__(self): + ObjectType.__init__(self) + obj = ExtObj2() + child = ObjectType(parent=obj) + self.assertEqual(obj.takeChild(child), child) + scope() + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml new file mode 100644 index 000000000..089f835fc --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml @@ -0,0 +1,2426 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + return PyLong_FromSize_t(%in); + + + + %out = %OUTTYPE(PyLong_AsSsize_t(%in)); + + + + + + + static bool Check2TupleOfNumbers(PyObject* pyIn) { + if (!PySequence_Check(pyIn) || !(PySequence_Size(pyIn) == 2)) + return false; + Shiboken::AutoDecRef pyReal(PySequence_GetItem(pyIn, 0)); + if (!SbkNumber_Check(pyReal)) + return false; + Shiboken::AutoDecRef pyImag(PySequence_GetItem(pyIn, 1)); + if (!SbkNumber_Check(pyImag)) + return false; + return true; + } + + + + + + return PyComplex_FromDoubles(%in.real(), %in.imag()); + + + + + double real = PyComplex_RealAsDouble(%in); + double imag = PyComplex_ImagAsDouble(%in); + %out = %OUTTYPE(real, imag); + + + Shiboken::AutoDecRef pyReal(PySequence_GetItem(%in, 0)); + Shiboken::AutoDecRef pyImag(PySequence_GetItem(%in, 1)); + double real = %CONVERTTOCPP[double](pyReal); + double imag = %CONVERTTOCPP[double](pyImag); + %out = %OUTTYPE(real, imag); + + + + + + + + + + SBK_UNUSED(%in); + Py_RETURN_NONE; + + + + %out = %OUTTYPE(%in == 0); + + + + + + + + + + if (!%in) + Py_RETURN_NONE; + #ifdef IS_PY3K + return PyCapsule_New(%in, 0, 0); + #else + return PyCObject_FromVoidPtr(%in, 0); + #endif + + + + %out = 0; + + + void* ptr; + #ifdef IS_PY3K + ptr = PyCapsule_GetPointer(%in, 0); + #else + ptr = PyCObject_AsVoidPtr(%in); + #endif + %out = (%OUTTYPE)ptr; + + + + + + + static bool checkPyCapsuleOrPyCObject(PyObject* pyObj) + { + #ifdef IS_PY3K + return PyCapsule_CheckExact(pyObj); + #else + return PyCObject_Check(pyObj); + #endif + } + + + + + + + #ifdef IS_PY3K + return PyCapsule_New(&%in, 0, 0); + #else + return PyCObject_FromVoidPtr(&%in, 0); + #endif + + + + void* ptr; + #ifdef IS_PY3K + ptr = PyCapsule_GetPointer(%in, 0); + #else + ptr = PyCObject_AsVoidPtr(%in); + #endif + %out = *((%OUTTYPE*)ptr); + + + + + + + + + + + return PyBool_FromLong(%in.value()); + + + + // Tests CONVERTTOCPP macro with C++ primitive type. + bool b = %CONVERTTOCPP[bool](%in); + %out = %OUTTYPE(b); + + + // Tests CONVERTTOCPP macro with user's primitive type. + Complex cpx = %CONVERTTOCPP[Complex](%in); + %out = %OUTTYPE(cpx.real() != 0.0 || cpx.imag() != 0.0); + + + + + + + + + + return Shiboken::String::fromCString(%in.cstring(), %in.size()); + + + + const char* str = %CONVERTTOCPP[const char*](%in); + %out = %OUTTYPE(str); + + + %out = %OUTTYPE(); + + + + + + + + + + + + + + + + %FUNCTION_NAME(&%1, %2); + %PYARG_0 = %CONVERTTOPYTHON[PStr](%1); + + + + + + + + + + + + + + + + %FUNCTION_NAME(&%1); + %PYARG_0 = %CONVERTTOPYTHON[PStr](%1); + + + + + + + + + PyObject* %out = PyList_New((int) %in.size()); + PStrList::const_iterator it = %in.begin(); + for (int idx = 0; it != %in.end(); ++it, ++idx) { + PStr cppItem(*it); + PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[PStr](cppItem)); + } + return %out; + + + + %OUTTYPE& list = %out; + Shiboken::AutoDecRef seq(PySequence_Fast(%in, 0)); + for (int i = 0; i < PySequence_Fast_GET_SIZE(seq.object()); i++) { + PyObject* pyItem = PySequence_Fast_GET_ITEM(seq.object(), i); + PStr cppItem = %CONVERTTOCPP[PStr](pyItem); + list.push_back(cppItem); + } + + + + + + + + PStrList %0; + %0.push_back(%1); + %0.push_back(%2); + %PYARG_0 = %CONVERTTOPYTHON[PStrList](%0); + + + + + std::list<PStr> %0; + %0.push_back(%1); + %0.push_back(%2); + %PYARG_0 = %CONVERTTOPYTHON[std::list<PStr>](%0); + + + + + + %PYARG_0 = (PyObject*) Shiboken::Conversions::getPythonTypeObject(%1); + if (!%PYARG_0) + %PYARG_0 = Py_None; + Py_INCREF(%PYARG_0); + + + + + + + + + + + + + + + + + + + + + + Shiboken::Conversions::SpecificConverter converter(%1); + const char* %0 = 0; + switch (converter.conversionType()) { + case Shiboken::Conversions::SpecificConverter::CopyConversion: + %0 = "Copy conversion"; + break; + case Shiboken::Conversions::SpecificConverter::PointerConversion: + %0 = "Pointer conversion"; + break; + case Shiboken::Conversions::SpecificConverter::ReferenceConversion: + %0 = "Reference conversion"; + break; + default: + %0 = "Invalid conversion"; + } + %PYARG_0 = %CONVERTTOPYTHON[const char*](%0); + + + + + static PyObject* __convertCppValuesToPython(const char** typeName, void** values, int size) + { + PyObject* result = PyTuple_New(size); + for (int i = 0; i < size; ++i) { + Shiboken::Conversions::SpecificConverter converter(typeName[i]); + PyTuple_SET_ITEM(result, i, converter.toPython(values[i])); + } + return result; + } + + + + const char* typeNames[] = { "Point", "Point*", "Point&" }; + void* values[] = { &%1, &%2, &(%3) }; + %PYARG_0 = __convertCppValuesToPython(typeNames, values, 3); + + + + + const char* typeNames[] = { "ObjectType*", "ObjectType&" }; + void* values[] = { &%1, &(%2) }; + %PYARG_0 = __convertCppValuesToPython(typeNames, values, 2); + + + + + const char* typeNames[] = { "std::list<int>" }; + void* values[] = { &%1 }; + %PYARG_0 = __convertCppValuesToPython(typeNames, values, 1); + + + + + const char* typeNames[] = { "int", "int" }; + void* values[] = { &%1, &%2 }; + %PYARG_0 = __convertCppValuesToPython(typeNames, values, 2); + + + + + + + + PyObject* %out = PyTuple_New(2); + PyTuple_SET_ITEM(%out, 0, %CONVERTTOPYTHON[%INTYPE_0](%in.first)); + PyTuple_SET_ITEM(%out, 1, %CONVERTTOPYTHON[%INTYPE_1](%in.second)); + return %out; + + + + %out.first = %CONVERTTOCPP[%OUTTYPE_0](PySequence_Fast_GET_ITEM(%in, 0)); + %out.second = %CONVERTTOCPP[%OUTTYPE_1](PySequence_Fast_GET_ITEM(%in, 1)); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PyObject* %out = PyDict_New(); + %INTYPE::const_iterator it = %in.begin(); + for (; it != %in.end(); ++it) { + %INTYPE_0 key = it->first; + %INTYPE_1 value = it->second; + PyDict_SetItem(%out, + %CONVERTTOPYTHON[%INTYPE_0](key), + %CONVERTTOPYTHON[%INTYPE_1](value)); + } + return %out; + + + + PyObject* key; + PyObject* value; + Py_ssize_t pos = 0; + while (PyDict_Next(%in, &pos, &key, &value)) { + %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key); + %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value); + %out.insert(%OUTTYPE::value_type(cppKey, cppValue)); + } + + + + + + + + %RETURN_TYPE %0 = Shiboken::BindingManager::instance().getAllPyObjects().size(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + const unsigned char* %out = reinterpret_cast<const unsigned char*>(Shiboken::String::toCString(%PYARG_1)); + + + + + + unsigned int %out = static_cast<unsigned int>(Shiboken::String::len(%PYARG_1)); + + + + + + %RETURN_TYPE %0 = %1 + %2; + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + %RETURN_TYPE %0 = %1.x() + %1.y(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + // The dot in "%1." must be replaced with a "->" by the generator. + %RETURN_TYPE %0 = %1.objectName().size(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + const char* tmpArg = %CONVERTTOCPP[const char*](%PYARG_1); + %0 = new %FUNCTION_NAME(atoi(tmpArg)); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + static void reparent_layout_items(PyObject* parent, PyObject* layout) + { + // CHECKTYPE and ISCONVERTIBLE are used here for test purposes, don't change them. + if (!%CHECKTYPE[ObjectTypeLayout*](layout) && !%ISCONVERTIBLE[ObjectTypeLayout*](layout)) + return; + // %CHECKTYPE[ObjectTypeLayout*](layout) + // %ISCONVERTIBLE[ObjectTypeLayout*](layout) + ObjectTypeLayout* var; + var = %CONVERTTOCPP[ObjectTypeLayout*](layout); + // TODO-CONVERTER: erase this + /* + ObjectTypeLayout* var2 = %CONVERTTOCPP[ObjectTypeLayout*](layout); + */ + const ObjectTypeList& objChildren = var->objects(); + ObjectTypeList::const_iterator it = objChildren.begin(); + for (; it != objChildren.end(); ++it) { + if ((*it)->isLayoutType()) { + ObjectTypeLayout* l = reinterpret_cast<ObjectTypeLayout*>(*it); + reparent_layout_items(parent, %CONVERTTOPYTHON[ObjectTypeLayout*](l)); + Shiboken::Object::setParent(layout, %CONVERTTOPYTHON[ObjectTypeLayout*](l)); + } else { + Shiboken::Object::setParent(parent, %CONVERTTOPYTHON[ObjectType*](*it)); + } + } + } + + + + + + + if (%PYARG_1 != Py_None) + reparent_layout_items(%PYSELF, %PYARG_1); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, %2) * 10; + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(%PYARG_1); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, true, %3, %4); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + int %out = PySequence_Size(%PYARG_1); + + + + + + Shiboken::AutoArrayPointer<Point> %out(%1); + for (int i = 0; i < %1; ++i) + %out[i] = %CONVERTTOCPP[Point](PySequence_Fast_GET_ITEM(%PYARG_1, i)); + + + + + + + + + + + + int size = (%2 < 0) ? %1.size() : %2; + %BEGIN_ALLOW_THREADS + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME((const void*) %1.data(), size); + %END_ALLOW_THREADS + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + + + + + + + + + + + Shiboken::AutoDecRef _py_ok_(PySequence_GetItem(%PYARG_0, 0)); + Shiboken::AutoDecRef _py_ret_(PySequence_GetItem(%PYARG_0, 1)); + *%2 = %CONVERTTOCPP[bool](_py_ok_); + %RETURN_TYPE %out = %CONVERTTOCPP[%RETURN_TYPE](_py_ret_); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ObjectType* tmpObject = 0; + %BEGIN_ALLOW_THREADS + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(&tmpObject); + %END_ALLOW_THREADS + %PYARG_0 = PyTuple_New(2); + PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%RETURN_TYPE](%0)); + PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[ObjectType*](tmpObject)); + + + + + %RETURN_TYPE %0 = !%CPPSELF.%FUNCTION_NAME(%1); + %PYARG_0 = %CONVERTTOPYTHON[OddBool](%0); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, %1+%3, %3); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + PyObject* new_arg0 = PyInt_FromLong(PyInt_AS_LONG(%PYARG_1) - %2); + Py_DECREF(%PYARG_1); + %PYARG_1 = new_arg0; + + + + + %0.prepend(Str("Pimped")); + + + + + PyObject_Call(%PYTHON_METHOD_OVERRIDE, %PYTHON_ARGUMENTS, NULL); + + + + + + + + + + Shiboken::AutoDecRef _py_ok_(PySequence_GetItem(%PYARG_0, 0)); + Shiboken::AutoDecRef _py_ret_(PySequence_GetItem(%PYARG_0, 1)); + %RETURN_TYPE %out = %CONVERTTOCPP[%RETURN_TYPE](_py_ok_); + %2 = %CONVERTTOCPP[Str*](_py_ret_); + + + + Str* _str_arg_ = 0; + %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, _str_arg_); + + + %PYARG_0 = PyTuple_New(2); + PyObject* _item_ = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + PyTuple_SET_ITEM(%PYARG_0, 0, _item_); + _item_ = %CONVERTTOPYTHON[Str*](_str_arg_); + PyTuple_SET_ITEM(%PYARG_0, 1, _item_); + + + + + + + + + + + Str* _str_arg_ = 0; + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(%1, _str_arg_); + + + %PYARG_0 = PyTuple_New(2); + PyObject* _item_ = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + PyTuple_SET_ITEM(%PYARG_0, 0, _item_); + _item_ = %CONVERTTOPYTHON[Str*](_str_arg_); + PyTuple_SET_ITEM(%PYARG_0, 1, _item_); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %BEGIN_ALLOW_THREADS + // It's important for test purposes to use a constructor with parenthesis as argument. + %RETURN_TYPE %0 = %RETURN_TYPE(%CPPSELF.%FUNCTION_NAME(Str(%1))); + %END_ALLOW_THREADS + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + + + + + + + + + %0 = new %TYPE(%PYARG_1); + + + + + %PYARG_0 = reinterpret_cast<PyObject*>(%CPPSELF.%FUNCTION_NAME()); + if (!%PYARG_0) + %PYARG_0 = Py_None; + Py_INCREF(%PYARG_0); + + + + + + + + + + + + bool ok_; + %RETURN_TYPE retval_ = + %FUNCTION_NAME(%1, %2, %3, %4, %5, %6, %7, %8, %9, %10, &ok_); + if (!ok_) + %PYARG_0 = Py_None; + else + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](retval_); + + + + + + + + typedef std::list<int> Inner; + typedef std::list<Inner> Outer; + + int result = 0; + + Outer::const_iterator oiter, oend = %1.end(); + for (oiter = %1.begin(); oiter != oend; ++oiter) { + const Inner& inner = *oiter; + Inner::const_iterator iiter, iend = inner.end(); + for (iiter = inner.begin(); iiter != iend; ++iiter) + result += *iiter; + } + + %PYARG_0 = %CONVERTTOPYTHON[int](result); + + + + + + + typedef std::pair<int, int> Pair; + typedef std::list<Pair> List; + + int result = 0; + + List::const_iterator iter, end = %1.end(); + for (iter = %1.begin(); iter != end; ++iter) + result += iter->first * iter->second; + + %PYARG_0 = %CONVERTTOPYTHON[int](result); + + + + + + + + + + + + + int* array = NULL; + bool errorOccurred = false; + + if (PySequence_Check(%PYARG_1)) { + if((array = Shiboken::sequenceToIntArray(%PYARG_1, true)) == NULL && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "Should be a sequence of ints"); + errorOccurred = true; + } + } else { + PyErr_SetString(PyExc_TypeError, "Should be a sequence of ints"); + errorOccurred = true; + } + + if (!errorOccurred) { + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(array); + if (array) + delete[] array; + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + } + + + + + + + + int %out = PySequence_Size(%PYARG_1); + + + + + + int numItems = PySequence_Size(%PYARG_1); + Shiboken::AutoArrayPointer<int> %out(numItems); + for (int i = 0; i < numItems; ++i) { + if (%CHECKTYPE[int](PySequence_Fast_GET_ITEM(%PYARG_1, i))) + %out[i] = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(%PYARG_1, i)); + else if (%ISCONVERTIBLE[int](PySequence_Fast_GET_ITEM(%PYARG_1, i))) + %out[i] = -1; + else + %out[i] = -2; + } + + + PyObject* %out = PyList_New(count); + for (int i = 0; i < count; ++i) + PyList_SET_ITEM(%out, i, %CONVERTTOPYTHON[int](%in[i])); + + + + + + + + + + + + + int numItems = PySequence_Size(%PYARG_1); + int *cppItems = new int[numItems]; + for (int i = 0; i < numItems; i++) + cppItems[i] = %CONVERTTOCPP[int](PySequence_GetItem(%PYARG_1, i)); + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(numItems, cppItems); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + delete[] cppItems; + + + + + + PyObject* InjectCode_tpstr(PyObject*) { return Shiboken::String::fromCString("Hi! I'm the inject code dummy class."); } + + + + %PYTHONTYPEOBJECT.tp_str = InjectCode_tpstr; + + + + + + %1 += 1; + + + PyObject* tmp = Shiboken::String::fromCString("end"); + Shiboken::String::concat(&%PYARG_0, tmp); + Py_DECREF(tmp); + + + + + + + PyObject* tmp = Shiboken::String::fromCString("end"); + Shiboken::String::concat(&%PYARG_0, tmp); + Py_DECREF(tmp); + + + + + + + + + + + + + int argc; + char** argv; + if (!Shiboken::sequenceToArgcArgv(%PYARG_1, &argc, &argv)) { + PyErr_SetString(PyExc_TypeError, "error"); + return 0; + } + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(argc, argv); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + for (int i = 0; i < argc; ++i) + free(argv[i]); + delete[] argv; + + + + + + + + + + + + + int argc; + char** argv; + if (!Shiboken::sequenceToArgcArgv(%PYARG_1, &argc, &argv)) { + PyErr_SetString(PyExc_TypeError, "error"); + return 0; + } + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(argc, argv); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + for (int i = 0; i < argc; ++i) + free(argv[i]); + delete[] argv; + + + + + + + + + return Shiboken::String::fromCString("PyObject"); + + + + + + return Shiboken::String::fromCString("PyObject"); + + + + + + + unsigned char* %out = 0; + + + + + + + + + + int x1 = (int) %CPPSELF.x(); + int x2 = ((int) (%CPPSELF.x() * 100)) - (x1 * 100); + int y1 = (int) %CPPSELF.y(); + int y2 = ((int) (%CPPSELF.y() * 100)) - (y1 * 100); + %PYARG_0 = Shiboken::String::fromFormat("Point(%d.%d, %d.%d)", x1, x2, y1, y2); + + + + + int x1 = (int) %CPPSELF.x(); + int x2 = ((int) (%CPPSELF.x() * 10)) - (x1 * 10); + int y1 = (int) %CPPSELF.y(); + int y2 = ((int) (%CPPSELF.y() * 10)) - (y1 * 10); + %PYARG_0 = Shiboken::String::fromFormat("<Point object at %p: (%d.%d, %d.%d)>", %CPPSELF, x1, x2, y1, y2); + + + + + + PyObject* type = PyObject_Type(%PYSELF); + PyObject* args = NULL; + + args = Py_BuildValue("(dd)", %CPPSELF.x(), %CPPSELF.y()); + + %PYARG_0 = Py_BuildValue("(OO)", type, args); + + + + + + + + + + + + Point _midpoint; + // The test consists in *NOT* using the ARGUMENT_NAMES type system variable. + %CPPSELF.%FUNCTION_NAME(%1, &_midpoint); + %PYARG_0 = %CONVERTTOPYTHON[Point](_midpoint); + + + + + + + + + + + + + + + + + + + + + int x1 = (int) %CPPSELF.x(); + int x2 = ((int) (%CPPSELF.x() * 100)) - (x1 * 100); + int y1 = (int) %CPPSELF.y(); + int y2 = ((int) (%CPPSELF.y() * 100)) - (y1 * 100); + %PYARG_0 = Shiboken::String::fromFormat("PointF(%d.%d, %d.%d)", x1, x2, y1, y2); + + + + + int x1 = (int) %CPPSELF.x(); + int x2 = ((int) (%CPPSELF.x() * 10)) - (x1 * 10); + int y1 = (int) %CPPSELF.y(); + int y2 = ((int) (%CPPSELF.y() * 10)) - (y1 * 10); + %PYARG_0 = Shiboken::String::fromFormat("<PointF object at %p: (%d.%d, %d.%d)>", %CPPSELF, x1, x2, y1, y2); + + + + + + PyObject *type = PyObject_Type(%PYSELF); + PyObject *args = NULL; + + args = Py_BuildValue("(dd)", %CPPSELF.x(), %CPPSELF.y()); + + %PYARG_0 = Py_BuildValue("(OO)", type, args); + + + + + + + + + + + + PointF _midpoint; + // The test consists in using the ARGUMENT_NAMES type system variable. + %CPPSELF.%FUNCTION_NAME(%ARGUMENT_NAMES, &_midpoint); + %PYARG_0 = %CONVERTTOPYTHON[PointF](_midpoint); + + + + + + + + + + + + + + + + + + + + + + + + + + + + if (!PyDateTimeAPI) + PyDateTime_IMPORT; + if (PyTime_Check(%1)) { + int pyH = PyDateTime_TIME_GET_HOUR(%1); + int pyM = PyDateTime_TIME_GET_MINUTE(%1); + int pyS = PyDateTime_TIME_GET_SECOND(%1); + if ((pyH == %CPPSELF.hour()) && + (pyM == %CPPSELF.minute()) && + (pyS == %CPPSELF.second())) + %PYARG_0 = Py_False; + else + %PYARG_0 = Py_True; + } + + + + + if (!PyDateTimeAPI) + PyDateTime_IMPORT; + if (PyTime_Check(%1)) { + int pyH = PyDateTime_TIME_GET_HOUR(%1); + int pyM = PyDateTime_TIME_GET_MINUTE(%1); + int pyS = PyDateTime_TIME_GET_SECOND(%1); + if ((pyH == %CPPSELF.hour()) && + (pyM == %CPPSELF.minute()) && + (pyS == %CPPSELF.second())) + %PYARG_0 = Py_True; + else + %PYARG_0 = Py_False; + } + + + + + + + + %0 = new %TYPE(); + + + Shiboken::AutoDecRef result(PyObject_CallMethod(%PYSELF, const_cast<char*>("setHeight"), const_cast<char*>("i"), 2)); + + + + + + + + + + + + + + + + + + + + + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(%1, 2, %3); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + + + { + Shiboken::AutoDecRef strList(PySequence_Fast(%PYARG_1, "The argument must be a sequence.")); + int lineCount = PySequence_Fast_GET_SIZE(strList.object()); + for (int line = 0; line < lineCount; ++line) { + if (!Shiboken::String::check(PySequence_Fast_GET_ITEM(strList.object(), line))) { + PyErr_SetString(PyExc_TypeError, "The argument must be a sequence of strings."); + break; + } + } + } + const char** %out = 0; + + + + + + + + void* %out = 0; + + + + + + + + + + + + + + + + + + + + + %BEGIN_ALLOW_THREADS + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(argOut, %2); + %END_ALLOW_THREADS + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + + + + %PYARG_0 = Shiboken::String::fromCString(%CPPSELF.cstring()); + + + + + return %CPPSELF.size(); + + + + + if (_i < 0 || _i >= %CPPSELF.size()) { + PyErr_BadArgument(); + return 0; + } else { + char res[2]; + res[0] = %CPPSELF.get_char(_i); + res[1] = 0; + return Shiboken::String::fromCString(res); + } + + + + + PyObject* args = Py_BuildValue("(iO)", _i, _value); + PyObject* result = Sbk_StrFunc_set_char(self, args); + Py_DECREF(args); + int ok = result == Py_True; + if (result) { + Py_DECREF(result); + } + return !ok ? -1 : 0; + + + + + + + + + + + + + + + + + + + + + + + %out = %OUTTYPE(); + + + Py_ssize_t len; + const char* str = Shiboken::String::toCString(%in, &len); + %out = %OUTTYPE(str, len); + + + + + + + + + + + + PyObject* data = 0; + if (PyUnicode_CheckExact(%PYARG_1)) { + data = PyUnicode_AsASCIIString(%PYARG_1); + } else { + data = %PYARG_1; + Py_INCREF(data); + } + + %0 = new %TYPE(PyBytes_AsString(data), PyBytes_GET_SIZE(data)); + Py_DECREF(data); + + + + + + + #if PY_VERSION_HEX < 0x03000000 + Shiboken::SbkType<ByteArray>()->tp_as_buffer = &SbkByteArrayBufferProc; + Shiboken::SbkType<ByteArray>()->tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER; + #endif + + + + + %PYARG_0 = PyBytes_FromStringAndSize(%CPPSELF.%FUNCTION_NAME(), %CPPSELF.size()); + + + + + + + + + + + + + + + + + + + Shiboken::AutoDecRef data(PyUnicode_AsASCIIString(%PYARG_1)); + if (!data.isNull()) { + ByteArray ba(*%CPPSELF); + ba.append(PyBytes_AsString(data.object()), PyBytes_GET_SIZE(data.object())); + %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba); + } + + + + + Shiboken::AutoDecRef data(PyUnicode_AsASCIIString(%PYARG_1)); + if (!data.isNull()) { + ByteArray ba(PyBytes_AsString(data.object()), PyBytes_GET_SIZE(data.object())); + ba.append(*%CPPSELF); + %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba); + } + + + + + ByteArray ba(PyBytes_AsString(%PYARG_1), PyBytes_GET_SIZE(%PYARG_1)); + ba = ba + *%CPPSELF; + %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba); + + + + + ByteArray ba(PyBytes_AsString(%PYARG_1), PyBytes_GET_SIZE(%PYARG_1)); + ba.append(*%CPPSELF); + %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba); + + + + + ByteArray b(((PyObject*)%PYSELF)->ob_type->tp_name); + PyObject* aux = Shiboken::String::fromStringAndSize(%CPPSELF.data(), %CPPSELF.size()); + if (PyUnicode_CheckExact(aux)) { + PyObject* tmp = PyUnicode_AsASCIIString(aux); + Py_DECREF(aux); + aux = tmp; + } + b += "('"; + b += ByteArray(PyBytes_AS_STRING(aux), PyBytes_GET_SIZE(aux)); + b += "')"; + %PYARG_0 = Shiboken::String::fromStringAndSize(b.data(), b.size()); + + + + + + %PYARG_0 = Shiboken::String::fromStringAndSize(%CPPSELF.data(), %CPPSELF.size()); + + + + + + return %CPPSELF.size(); + + + + + if (_i < 0 || _i >= %CPPSELF.size()) { + PyErr_SetString(PyExc_IndexError, "index out of bounds"); + return 0; + } else { + char res[2]; + res[0] = %CPPSELF.at(_i); + res[1] = 0; + return PyBytes_FromStringAndSize(res, 1); + } + + + + + + + + + return %CPPSELF.size(); + + + + + if (_i < 0 || _i >= static_cast<Py_ssize_t>(%CPPSELF.size())) { + PyErr_BadArgument(); + return 0; + } else { + %TYPE::const_iterator it = %CPPSELF.begin(); + for (Py_ssize_t i = 1; i <= _i; i++) + ++it; + return %CONVERTTOPYTHON[Str](*it); + } + + + + + + + + + + + + + + + + + + + + %RETURN_TYPE %0 = %TYPE::%FUNCTION_NAME(); + %PYARG_0 = Shiboken::Object::newObject(&SbkObject_Type, %0, false, false); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %PYARG_0 = Shiboken::String::fromCString(%1); + + + + + // This should test if code injections works inside rich comparison operators + Py_INCREF(Py_True); + %PYARG_0 = Py_True; + + + + + + + + + + + + + + + // Does nothing really, just test the code generation + // of constructors whose arguments where + long %out = PyInt_AS_LONG(%PYARG_1) + 1; + + + + + + + + %PYARG_0 = Shiboken::String::fromCString(""); + for (unsigned int i = 0; i < %2; ++i) + Shiboken::String::concat(&%PYARG_0, %PYARG_1); + + + + + + %RETURN_TYPE %0 = PyTuple_GET_SIZE(%PYARG_2); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + static bool PyDate_ImportAndCheck(PyObject* pyIn) { + if (!PyDateTimeAPI) + PyDateTime_IMPORT; + return PyDate_Check(pyIn); + } + + + + + int day = PyDateTime_GET_DAY(%in); + int month = PyDateTime_GET_MONTH(%in); + int year = PyDateTime_GET_YEAR(%in); + %out = %OUTTYPE(day, month, year); + + + + + + if (!PyDateTimeAPI) + PyDateTime_IMPORT; + %PYARG_0 = PyDate_FromDate(%CPPSELF.day(), %CPPSELF.month(), %CPPSELF.year()); + + + + + + + + + + + %RETURN_TYPE %0 = %CPPSELF.key() != %1; + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + %RETURN_TYPE %0 = *%CPPSELF & %1; + return %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + %RETURN_TYPE %0 = *%CPPSELF & %1; + return %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sources/shiboken2/tests/samplebinding/unsafe_parent_test.py b/sources/shiboken2/tests/samplebinding/unsafe_parent_test.py new file mode 100644 index 000000000..18da16458 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/unsafe_parent_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 ...''' + +import sys +import unittest + +from sample import ObjectType + +class DerivedObjectType(ObjectType): + def isPython(self): + return True + + def createChild(self, parent): + return DerivedObjectType(parent) + +class ParentTest(unittest.TestCase): + + def testUunsafeParent(self): + o = DerivedObjectType() + o.callVirtualCreateChild() + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/useraddedctor_test.py b/sources/shiboken2/tests/samplebinding/useraddedctor_test.py new file mode 100644 index 000000000..ea9d1f878 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/useraddedctor_test.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 user added constructors''' + +import unittest +from sample import * + +class PointTest(unittest.TestCase): + def testUsingSelfOnCtor(self): + # This is a user added ctor and no errors should happen! + s = Size("oi") + self.assertEqual(s.height(), 2) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/virtualdtor_test.py b/sources/shiboken2/tests/samplebinding/virtualdtor_test.py new file mode 100644 index 000000000..46f29179c --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/virtualdtor_test.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 virtual destructor.''' + +import sys +import unittest + +from sample import VirtualDtor + +class ExtendedVirtualDtor(VirtualDtor): + def __init__(self): + VirtualDtor.__init__(self) + +class VirtualDtorTest(unittest.TestCase): + '''Test case for virtual destructor.''' + + def setUp(self): + VirtualDtor.resetDtorCounter() + + def testVirtualDtor(self): + '''Original virtual destructor is being called.''' + dtor_called = VirtualDtor.dtorCalled() + for i in range(1, 10): + vd = VirtualDtor() + del vd + self.assertEqual(VirtualDtor.dtorCalled(), dtor_called + i) + + def testVirtualDtorOnCppCreatedObject(self): + '''Original virtual destructor is being called for a C++ created object.''' + dtor_called = VirtualDtor.dtorCalled() + for i in range(1, 10): + vd = VirtualDtor.create() + del vd + self.assertEqual(VirtualDtor.dtorCalled(), dtor_called + i) + + def testDtorOnDerivedClass(self): + '''Original virtual destructor is being called for a derived class.''' + dtor_called = ExtendedVirtualDtor.dtorCalled() + for i in range(1, 10): + evd = ExtendedVirtualDtor() + del evd + self.assertEqual(ExtendedVirtualDtor.dtorCalled(), dtor_called + i) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/virtualmethods_test.py b/sources/shiboken2/tests/samplebinding/virtualmethods_test.py new file mode 100644 index 000000000..8a361c9f9 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/virtualmethods_test.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 virtual methods.''' + +import sys +import unittest + +from sample import * + +import warnings + +class ExtendedVirtualMethods(VirtualMethods): + def __init__(self): + VirtualMethods.__init__(self) + self.virtual_method0_called = False + + def virtualMethod0(self, pt, val, cpx, b): + self.virtual_method0_called = True + return VirtualMethods.virtualMethod0(self, pt, val, cpx, b) * -1.0 + + def strListToStdList(self, arg): + warnings.simplefilter('error') + # returning wrong type for test purposes. + return True + + def recursionOnModifiedVirtual(self, arg): + # check if recursion is caused by injected code that calls C++. + return VirtualMethods.recursionOnModifiedVirtual(self, arg) + 10 + +class ExtendedVirtualDaughter(VirtualDaughter): + def __init__(self, name): + VirtualDaughter.__init__(self, name) + self.grand_daughter_name_called = False + + def name(self): + self.grand_daughter_name_called = True + return VirtualDaughter.name(self).prepend('Extended') + +class ExtendedExtendedVirtualDaughter(ExtendedVirtualDaughter): + def __init__(self, name): + ExtendedVirtualDaughter.__init__(self, name) + self.grand_grand_daughter_name_called = False + + def name(self): + self.grand_grand_daughter_name_called = True + return ExtendedVirtualDaughter.name(self).prepend('Extended') + +class VirtualMethodsTest(unittest.TestCase): + '''Test case for virtual methods''' + + def setUp(self): + self.prefix_from_codeinjection = Str('Pimped') + + def tearDown(self): + del self.prefix_from_codeinjection + + def testReimplementedVirtualMethod0(self): + '''Test Python override of a virtual method with various different parameters is correctly called from C++.''' + vm = VirtualMethods() + evm = ExtendedVirtualMethods() + pt = Point(1.1, 2.2) + val = 4 + cpx = complex(3.3, 4.4) + b = True + result0 = vm.callVirtualMethod0(pt, val, cpx, b) + result1 = evm.callVirtualMethod0(pt, val, cpx, b) + self.assertEqual(result0 * -1.0, result1) + + def testRecursionOnModifiedVirtual(self): + evm = ExtendedVirtualMethods() + self.assertEqual(evm.recursionOnModifiedVirtual(''), 10) + self.assertEqual(evm.callRecursionOnModifiedVirtual(''), 10) + + def testReimplementedVirtualMethodInheritedFromGrandParent(self): + '''Test Python override of a virtual method inherited from a grand parent.''' + original_name = 'Foo' + evd = ExtendedVirtualDaughter(original_name) + + self.assertEqual(VirtualDaughter.name(evd), original_name) + self.assertEqual(VirtualMethods.name(evd), original_name) + self.assertFalse(evd.grand_daughter_name_called) + + name = evd.callName() + self.assertTrue(evd.grand_daughter_name_called) + self.assertEqual(evd.name().prepend(self.prefix_from_codeinjection), name) + + def testReimplementedVirtualMethodInheritedFromGrandGrandParent(self): + '''Test Python override of a virtual method inherited from a grand grand parent.''' + original_name = 'Foo' + eevd = ExtendedExtendedVirtualDaughter(original_name) + + self.assertEqual(VirtualDaughter.name(eevd), original_name) + self.assertEqual(VirtualMethods.name(eevd), original_name) + self.assertFalse(eevd.grand_daughter_name_called) + self.assertFalse(eevd.grand_grand_daughter_name_called) + + name = eevd.callName() + self.assertTrue(eevd.grand_daughter_name_called) + self.assertTrue(eevd.grand_grand_daughter_name_called) + self.assertEqual(eevd.name().prepend(self.prefix_from_codeinjection), name) + +class PrettyErrorMessageTest(unittest.TestCase): + def testIt(self): + obj = ExtendedVirtualMethods() + self.assertRaises(RuntimeWarning, obj.callStrListToStdList, StrList()) + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/visibilitychange_test.py b/sources/shiboken2/tests/samplebinding/visibilitychange_test.py new file mode 100644 index 000000000..b89036a94 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/visibilitychange_test.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 * + +class VisibilityChangeTest(unittest.TestCase): + + def testVisibilityChange(self): + b1 = Base1() + b1.publicMethod() # ok... + d1 = MDerived1() + self.assertRaises(TypeError, d1.publicMethod); + +if __name__ == '__main__': + unittest.main() + + diff --git a/sources/shiboken2/tests/samplebinding/voidholder_test.py b/sources/shiboken2/tests/samplebinding/voidholder_test.py new file mode 100644 index 000000000..cb5cab6e5 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/voidholder_test.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 case for a class that holds a void pointer.''' + +import unittest + +from sample import VoidHolder, Point + +class VoidHolderTest(unittest.TestCase): + '''Test case for void pointer manipulation.''' + + def testGetVoidPointerFromCppAndPutsOnVoidHolder(self): + '''Passes a void pointer created in C++ and to kept by VoidHolder.''' + voidptr = VoidHolder.gimmeMeSomeVoidPointer() + voidholder = VoidHolder(voidptr) + self.assertEqual(voidptr, voidholder.voidPointer()) + + def testPutRandomObjectInsideVoidHolder(self): + '''Passes a C++ pointer for an object created in Python to be kept by VoidHolder.''' + obj = Point(1, 2) + voidholder = VoidHolder(obj) + self.assertEqual(obj, voidholder.voidPointer()) + + def testGetNoneObjectFromVoidHolder(self): + '''A VoidHolder created without parameters returns a NULL pointer + that should be converted to a Python None.''' + voidholder = VoidHolder() + self.assertEqual(voidholder.voidPointer(), None) + + def testPutPythonObjectInsideVoidHolder(self): + '''Passes a native Python object to be kept by VoidHolder.''' + obj = 'Foo' + voidholder = VoidHolder(obj) + self.assertEqual(obj, voidholder.voidPointer()) + + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/shiboken2/tests/samplebinding/weakref_test.py b/sources/shiboken2/tests/samplebinding/weakref_test.py new file mode 100644 index 000000000..77be7ec9f --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/weakref_test.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 weakref support''' + +import weakref +import unittest + +from sample import ObjectType, PrivateDtor + + +class WeakrefBasicTest(unittest.TestCase): + '''Simple test case of using a weakref''' + + def setUp(self): + self.called = False + + def cb(self, *args): + self.called = True + + def testBasic(self): + '''ObjectType weakref''' + obj = ObjectType() + ref = weakref.ref(obj, self.cb) + del obj + self.assertTrue(self.called) + + def testPrivateDtor(self): + '''PrivateDtor weakref''' + obj = PrivateDtor.instance() + ref = weakref.ref(obj, self.cb) + del obj + self.assertTrue(self.called) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/writableclassdict_test.py b/sources/shiboken2/tests/samplebinding/writableclassdict_test.py new file mode 100644 index 000000000..828ac686a --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/writableclassdict_test.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 Point + +class ExtPoint(Point): pass + +class TestWritableClassDict(unittest.TestCase): + def testSetattrOnClass(self): + setattr(Point, 'foo', 123) + self.assertEqual(Point.foo, 123) + pt = Point() + self.assertEqual(pt.foo, 123) + + def testSetattrOnInheritingClass(self): + setattr(Point, 'bar', 321) + self.assertEqual(Point.bar, 321) + self.assertEqual(ExtPoint.bar, 321) + pt = ExtPoint() + self.assertEqual(pt.bar, 321) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/shibokenmodule/module_test.py b/sources/shiboken2/tests/shibokenmodule/module_test.py new file mode 100644 index 000000000..bc2931251 --- /dev/null +++ b/sources/shiboken2/tests/shibokenmodule/module_test.py @@ -0,0 +1,116 @@ +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 shiboken2 as shiboken +import unittest +from sample import * + +class MultipleInherited (ObjectType, Point): + def __init__(self): + ObjectType.__init__(self) + Point.__init__(self) + +class TestShiboken(unittest.TestCase): + def testIsValid(self): + self.assertTrue(shiboken.isValid(object())) + self.assertTrue(shiboken.isValid(None)) + + bb = BlackBox() + item = ObjectType() + ticket = bb.keepObjectType(item) + bb.disposeObjectType(ticket) + self.assertFalse(shiboken.isValid(item)) + + def testWrapInstance(self): + addr = ObjectType.createObjectType() + obj = shiboken.wrapInstance(addr, ObjectType) + self.assertFalse(shiboken.createdByPython(obj)) + obj.setObjectName("obj") + self.assertEqual(obj.objectName(), "obj") + self.assertEqual(addr, obj.identifier()) + self.assertFalse(shiboken.createdByPython(obj)) + + # avoid mem leak =] + bb = BlackBox() + self.assertTrue(shiboken.createdByPython(bb)) + bb.disposeObjectType(bb.keepObjectType(obj)) + + def testIsOwnedByPython(self): + obj = ObjectType() + self.assertTrue(shiboken.ownedByPython(obj)) + p = ObjectType() + obj.setParent(p) + self.assertFalse(shiboken.ownedByPython(obj)) + + def testDump(self): + """Just check if dump doesn't crash on certain use cases""" + p = ObjectType() + obj = ObjectType(p) + obj2 = ObjectType(obj) + obj3 = ObjectType(obj) + self.assertEqual(shiboken.dump(None), "Ordinary Python type.") + shiboken.dump(obj) + + model = ObjectModel(p) + v = ObjectView(model, p) + shiboken.dump(v) + + m = MultipleInherited() + shiboken.dump(m) + self.assertEqual(len(shiboken.getCppPointer(m)), 2) + + # Don't crash even after deleting an object + shiboken.invalidate(obj) + shiboken.dump(obj) # deleted + shiboken.dump(p) # child deleted + shiboken.dump(obj2) # parent deleted + + def testDelete(self): + obj = ObjectType() + child = ObjectType(obj) + self.assertTrue(shiboken.isValid(obj)) + self.assertTrue(shiboken.isValid(child)) + # Note: this test doesn't assure that the object dtor was really called + shiboken.delete(obj) + self.assertFalse(shiboken.isValid(obj)) + self.assertFalse(shiboken.isValid(child)) + + def testVersionAttr(self): + self.assertEqual(type(shiboken.__version__), str) + self.assertTrue(len(shiboken.__version__) >= 5) + self.assertEqual(type(shiboken.__version_info__), tuple) + self.assertEqual(len(shiboken.__version_info__), 5) + + def testAllWrappers(self): + obj = ObjectType() + self.assertTrue(obj in shiboken.getAllValidWrappers()) + shiboken.delete(obj) + self.assertFalse(obj in shiboken.getAllValidWrappers()) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/smartbinding/CMakeLists.txt b/sources/shiboken2/tests/smartbinding/CMakeLists.txt new file mode 100644 index 000000000..e9c52d447 --- /dev/null +++ b/sources/shiboken2/tests/smartbinding/CMakeLists.txt @@ -0,0 +1,39 @@ +project(smart) + +set(smart_TYPESYSTEM +${CMAKE_CURRENT_SOURCE_DIR}/typesystem_smart.xml +) + +set(smart_SRC +${CMAKE_CURRENT_BINARY_DIR}/smart/smart_module_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/obj_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/integer_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/sharedptr_obj_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/sharedptr_integer_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/registry_wrapper.cpp +) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/smart-binding.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt" @ONLY) + +add_custom_command(OUTPUT ${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} +COMMENT "Running generator for 'smart' test binding..." +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR} + ${SBK_PYTHON_INCLUDE_DIR} + ${libsmart_SOURCE_DIR} + ${libshiboken_SOURCE_DIR}) +add_library(smart MODULE ${smart_SRC}) +set_property(TARGET smart PROPERTY PREFIX "") +if(WIN32) + set_property(TARGET smart PROPERTY SUFFIX ".pyd") +endif() +target_link_libraries(smart + libsmart + ${SBK_PYTHON_LIBRARIES} + libshiboken) diff --git a/sources/shiboken2/tests/smartbinding/global.h b/sources/shiboken2/tests/smartbinding/global.h new file mode 100644 index 000000000..a72cd21a5 --- /dev/null +++ b/sources/shiboken2/tests/smartbinding/global.h @@ -0,0 +1,29 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "smart.h" diff --git a/sources/shiboken2/tests/smartbinding/smart-binding.txt.in b/sources/shiboken2/tests/smartbinding/smart-binding.txt.in new file mode 100644 index 000000000..699f0bfe6 --- /dev/null +++ b/sources/shiboken2/tests/smartbinding/smart-binding.txt.in @@ -0,0 +1,15 @@ +[generator-project] + +generator-set = shiboken + +header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h +typesystem-file = @smart_TYPESYSTEM@ + +output-directory = @CMAKE_CURRENT_BINARY_DIR@ + +include-path = @libsmart_SOURCE_DIR@ + +typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@ + +enable-parent-ctor-heuristic +use-isnull-as-nb_nonzero diff --git a/sources/shiboken2/tests/smartbinding/smart_pointer_test.py b/sources/shiboken2/tests/smartbinding/smart_pointer_test.py new file mode 100644 index 000000000..c8eb1b2c5 --- /dev/null +++ b/sources/shiboken2/tests/smartbinding/smart_pointer_test.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2017 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of PySide2. +## +## $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 copy import copy +from smart import Obj, Registry, Integer + +def objCount(): + return Registry.getInstance().countObjects() + +def integerCount(): + return Registry.getInstance().countIntegers() + +class SmartPointerTests(unittest.TestCase): + def testObjSmartPointer(self): + # Uncomment to see more debug info about creation of objects and ref counts. + # Registry.getInstance().setShouldPrint(True) + + # Create Obj. + o = Obj() + self.assertEqual(objCount(), 1) + + # Create a shared pointer to an Obj together with an Obj. + ptrToObj = o.giveSharedPtrToObj() + self.assertEqual(objCount(), 2) + + # Delete the old Obj. + o = None + self.assertEqual(objCount(), 1) + + # Get a wrapper to the Obj inside of the shared pointer, object count should not change. + obj = ptrToObj.data() + self.assertEqual(objCount(), 1) + obj.m_integer = 50 + self.assertEqual(obj.m_integer, 50) + + # Set and get a member value via shared pointer (like operator->). + ptrToObj.m_integer = 100 + self.assertEqual(ptrToObj.m_integer, 100) + + # Get inner PyObject via shared pointer (like operator->) and set value in it. + ptrToObj.m_internalInteger.m_int = 200 + self.assertEqual(ptrToObj.m_internalInteger.m_int, 200) + + # Pass smart pointer as argument to a method, return value is the value of m_integer of + # passed Obj inside the smart pointer. + result = ptrToObj.takeSharedPtrToObj(ptrToObj) + self.assertEqual(result, 100) + + # Pass an Integer as an argument that returns itself. + result = ptrToObj.takeInteger(ptrToObj.m_internalInteger) + self.assertEqual(integerCount(), 2) + result = None + self.assertEqual(integerCount(), 1) + + # Make a copy of the shared pointer, object count should not change. + ptrToObj2 = copy(ptrToObj) + self.assertEqual(objCount(), 1) + + # Delete the first shared pointer, object count should not change because the second + # one still has a reference. + del ptrToObj + self.assertEqual(objCount(), 1) + + # Delete the second smart pointer, object should be deleted. + del ptrToObj2 + self.assertEqual(objCount(), 0) + self.assertEqual(integerCount(), 0) + + def testIntegerSmartPointer(self): + # Uncomment to see more debug info about creation of objects and ref counts. + # Registry.getInstance().setShouldPrint(True) + + # Create Obj. + o = Obj() + self.assertEqual(objCount(), 1) + + # Create a shared pointer to an Integer together with an Integer. + ptrToInteger = o.giveSharedPtrToInteger() + self.assertEqual(objCount(), 1) + self.assertEqual(integerCount(), 2) + + # Get a wrapper to the Integer inside of the shared pointer, integer count should not + # change. + integer = ptrToInteger.data() + self.assertEqual(integerCount(), 2) + integer.m_int = 50 + self.assertEqual(integer.m_int, 50) + + # Set and get a member value via shared pointer (like operator->). + ptrToInteger.m_int = 100 + self.assertEqual(ptrToInteger.m_int, 100) + + # Pass smart pointer as argument to a method, return value is the value of m_int of + # passed Integer inside the smart pointer. + result = o.takeSharedPtrToInteger(ptrToInteger) + self.assertEqual(result, 100) + + # Make a copy of the shared pointer, integer count should not change. + ptrToInteger2 = copy(ptrToInteger) + self.assertEqual(integerCount(), 2) + + # Delete the first shared pointer, integer count should not change because the second + # one still has a reference. + del ptrToInteger + self.assertEqual(integerCount(), 2) + + # Delete the second smart pointer, integer should be deleted. + del ptrToInteger2 + self.assertEqual(objCount(), 1) + self.assertEqual(integerCount(), 1) + + # Delete the original object which was used to create the integer. + del o + self.assertEqual(objCount(), 0) + self.assertEqual(integerCount(), 0) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/smartbinding/typesystem_smart.xml b/sources/shiboken2/tests/smartbinding/typesystem_smart.xml new file mode 100644 index 000000000..a2654730d --- /dev/null +++ b/sources/shiboken2/tests/smartbinding/typesystem_smart.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/sources/shiboken2/tests/sphinxtabletest.cpp b/sources/shiboken2/tests/sphinxtabletest.cpp new file mode 100644 index 000000000..6a8ac7703 --- /dev/null +++ b/sources/shiboken2/tests/sphinxtabletest.cpp @@ -0,0 +1,332 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "sphinxtabletest.h" +#include "qtdocgenerator.h" +#include +#include + +QString SphinxTableTest::transformXml(const char* xml) +{ + return QtXmlToSphinx(m_generator, xml).result(); +} + +void SphinxTableTest::setUp() +{ + m_generator = new QtDocGenerator; +} + +void SphinxTableTest::tearDown() +{ + delete m_generator; +} + +void SphinxTableTest::testEmptyString() +{ + const char* xml = ""; + QCOMPARE(transformXml(xml), QString()); +} + +void SphinxTableTest::testSimpleTable() +{ + const char* xml = "\ +\ +
\ + \ + Header 1\ + \ + \ + Header 2\ + \ +
\ + \ + \ + 1 1\ + \ + \ + 1 2\ + \ + \ + \ + \ + 2 1\ + \ + \ + 2 2\ + \ + \ +
"; + QCOMPARE(transformXml(xml), QString("\ + +--------+--------+\n\ + |Header 1|Header 2|\n\ + +--------+--------+\n\ + |1 1 |1 2 |\n\ + +--------+--------+\n\ + |2 1 |2 2 |\n\ + +--------+--------+\n\ +\n")); +} + +void SphinxTableTest::testColSpan() +{ + const char* xml = "\ +\ +
\ + \ + Header 1\ + \ + \ + Header 2\ + \ +
\ + \ + \ + I'm a big text!\ + \ + \ + \ + \ + 2 1\ + \ + \ + 2 2\ + \ + \ +
"; + QCOMPARE(transformXml(xml), QString("\ + +---------------+--------+\n\ + |Header 1 |Header 2|\n\ + +---------------+--------+\n\ + |I'm a big text! |\n\ + +---------------+--------+\n\ + |2 1 |2 2 |\n\ + +---------------+--------+\n\ +\n")); +} + + +void SphinxTableTest::testRowSpan() +{ + const char* xml = "\ +\ +
\ + \ + Header 1\ + \ + \ + Header 2\ + \ +
\ + \ + \ + 1.1\ + \ + \ + 1.2\ + \ + \ + \ + \ + 2 2\ + \ + \ +
"; + QCOMPARE(transformXml(xml), QString("\ + +--------+--------+\n\ + |Header 1|Header 2|\n\ + +--------+--------+\n\ + |1.1 |1.2 |\n\ + + +--------+\n\ + | |2 2 |\n\ + +--------+--------+\n\ +\n")); +} + + +void SphinxTableTest::testComplexTable() +{ + const char* xml = "\ +\ +
\ + \ + Header 1\ + \ + \ + Header 2\ + \ + \ + Header 3\ + \ +
\ + \ + \ + 1.1\ + \ + \ + 1.2\ + \ + \ + \ + \ + 2 2\ + \ + \ + 2 3\ + \ + \ +
"; + QCOMPARE(transformXml(xml), QString("\ + +--------+--------+--------+\n\ + |Header 1|Header 2|Header 3|\n\ + +--------+--------+--------+\n\ + |1.1 |1.2 |\n\ + + +--------+--------+\n\ + | |2 2 |2 3 |\n\ + +--------+--------+--------+\n\ +\n")); +} + +void SphinxTableTest::testRowSpan2() +{ + const char* xml = "\ +\ +
\ + h1\ + h2\ + h3\ + h4\ +
\ + \ + A\ + B\ + C\ + D\ + \ + \ + E\ + F\ + \ + \ + E\ + F\ + \ + \ + E\ + F\ + \ + \ + E\ + F\ + \ + \ + E\ + F\ + \ +
"; + QCOMPARE(transformXml(xml), QString("\ + +--+--+--+--+\n\ + |h1|h2|h3|h4|\n\ + +--+--+--+--+\n\ + |A |B |C |D |\n\ + + + +--+--+\n\ + | | |E |F |\n\ + + + +--+--+\n\ + | | |E |F |\n\ + + + +--+--+\n\ + | | |E |F |\n\ + + + +--+--+\n\ + | | |E |F |\n\ + + + +--+--+\n\ + | | |E |F |\n\ + +--+--+--+--+\n\ +\n")); +} + +void SphinxTableTest::testBrokenTable() +{ + const char* xml = "\ +\ +
\ + \ + Header 1\ + \ + \ + Header 2\ + \ +
\ + \ + \ + 1.1\ + \ + \ + 1.2\ + \ + \ + \ + \ + 2 2\ + \ + \ + 2 3\ + \ + \ + 2 4\ + \ + \ + 2 5\ + \ + \ + \ + \ + 3 1\ + \ + \ + 3 2\ + \ + \ + 3 3\ + \ + \ +
"; + QCOMPARE(transformXml(xml), QString("\ + +--------+------------+\n\ + |Header 1|Header 2 |\n\ + +--------+------------+\n\ + |1.1 |1.2 |\n\ + +--------+------------+\n\ + |2 2 2 3 2 4 2 5|\n\ + +--------+------------+\n\ + |3 1 |3 2 3 3 |\n\ + +--------+------------+\n\ +\n")); +} + + +QTEST_APPLESS_MAIN( SphinxTableTest ) + +#include "sphinxtabletest.moc" diff --git a/sources/shiboken2/tests/sphinxtabletest.h b/sources/shiboken2/tests/sphinxtabletest.h new file mode 100644 index 000000000..4779b75cd --- /dev/null +++ b/sources/shiboken2/tests/sphinxtabletest.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 SPHINXTABLETEST_H +#define SPHINXTABLETEST_H + +#include + +class QtDocGenerator; +class SphinxTableTest : public QObject { + Q_OBJECT + +private slots: + void setUp(); + void tearDown(); + void testEmptyString(); + void testSimpleTable(); + void testRowSpan(); + void testColSpan(); + void testComplexTable(); + void testRowSpan2(); + void testBrokenTable(); +private: + QtDocGenerator* m_generator; + + QString transformXml(const char* xml); +}; + +#endif diff --git a/sources/shiboken2/tests/test_generator/CMakeLists.txt b/sources/shiboken2/tests/test_generator/CMakeLists.txt new file mode 100644 index 000000000..5f5099897 --- /dev/null +++ b/sources/shiboken2/tests/test_generator/CMakeLists.txt @@ -0,0 +1,68 @@ +project(test_generator) + +set(dummy_generator_SRC dummygenerator.cpp) +add_library(dummy_generator SHARED ${dummy_generator_SRC}) +target_link_libraries(dummy_generator ${APIEXTRACTOR_LIBRARY} ${QT_QTCORE_LIBRARY} genrunner) +set_property(TARGET dummy_generator PROPERTY PREFIX "") + +add_executable(dummygenerator main.cpp) +set(DUMMYGENERATOR_EXECUTABLE dummygenerator${generator_SUFFIX}) +set_target_properties(dummygenerator PROPERTIES OUTPUT_NAME ${DUMMYGENERATOR_EXECUTABLE}) +target_link_libraries(dummygenerator ${Qt5Core_LIBRARIES}) + +configure_file(dummygentestconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/dummygentestconfig.h" @ONLY) + +get_filename_component(APIEXTRACTOR_LIBRARY_DIRS ${APIEXTRACTOR_LIBRARY} PATH) +if(WIN32) + set(PATH_SEP ";") + find_program(APIEXTRACTOR_BINARY apiextractor.dll HINTS ${APIEXTRACTOR_LIBRARY_DIRS}) + get_filename_component(APIEXTRACTOR_BINARY_DIR ${APIEXTRACTOR_BINARY} PATH) + set(APIEXTRACTOR_LIBRARY_DIRS "${APIEXTRACTOR_LIBRARY_DIRS}${PATH_SEP}${APIEXTRACTOR_BINARY_DIR}") +else() + set(PATH_SEP ":") +endif() + +set(ENV_PATH "${generatorrunner_BINARY_DIR}${PATH_SEP}${CMAKE_CURRENT_BINARY_DIR}${PATH_SEP}$ENV{PATH}${PATH_SEP}${APIEXTRACTOR_LIBRARY_DIRS}") +set(ENV_QT_PLUGIN_PATH "${CMAKE_CURRENT_BINARY_DIR}${PATH_SEP}$ENV{QT_PLUGIN_PATH}") +if(WIN32) + string(REPLACE "\\;" ";" ENV_PATH "${ENV_PATH}") + string(REPLACE ";" "\\;" ENV_PATH "${ENV_PATH}") + string(REPLACE "\\;" ";" ENV_QT_PLUGIN_PATH "${ENV_QT_PLUGIN_PATH}") + string(REPLACE ";" "\\;" ENV_QT_PLUGIN_PATH "${ENV_QT_PLUGIN_PATH}") +endif() + +macro(m_add_test testname) + if(CMAKE_VERSION VERSION_LESS 2.8) + add_test(${testname} ${CMAKE_COMMAND} -DTEST=${testname} + -DWORKDIR=${CMAKE_CURRENT_BINARY_DIR} + -DENV_PATH=${ENV_PATH} -DENV_QT_PLUGIN_PATH=${ENV_QT_PLUGIN_PATH} + -P ${CMAKE_CURRENT_SOURCE_DIR}/run_test.cmake) + else() + add_test(${testname} ${testname}) + set_property(TEST ${testname} PROPERTY ENVIRONMENT "PATH=${ENV_PATH}" "QT_PLUGIN_PATH=${ENV_QT_PLUGIN_PATH}") + endif() +endmacro() + +macro(declare_test testname) + qt4_automoc("${testname}.cpp") + add_executable(${testname} "${testname}.cpp") + include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(${testname} + ${QT_QTTEST_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${Qt5Test_LIBRARIES} + ${Qt5Core_LIBRARIES} + ) + m_add_test(${testname}) +endmacro(declare_test testname) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/test_global.h" + "${CMAKE_CURRENT_BINARY_DIR}/test_global.h" COPYONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/test_typesystem.xml" + "${CMAKE_CURRENT_BINARY_DIR}/test_typesystem.xml" COPYONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/dummygentest-project.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/dummygentest-project.txt" @ONLY) +declare_test(dummygentest) + +add_dependencies(dummygenerator generatorrunner) + diff --git a/sources/shiboken2/tests/test_generator/dummygenerator.cpp b/sources/shiboken2/tests/test_generator/dummygenerator.cpp new file mode 100644 index 000000000..40d9fb771 --- /dev/null +++ b/sources/shiboken2/tests/test_generator/dummygenerator.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 +#include "dummygenerator.h" + +EXPORT_GENERATOR_PLUGIN(new DummyGenerator) + +using namespace std; + +QString +DummyGenerator::fileNameForClass(const AbstractMetaClass* metaClass) const +{ + return QString("%1_generated.txt").arg(metaClass->name().toLower()); +} + +void +DummyGenerator::generateClass(QTextStream& s, const AbstractMetaClass* metaClass) +{ + s << "// Generated code for class: " << qPrintable(metaClass->name()) << endl; +} + +bool +DummyGenerator::doSetup(const QMap& args) +{ + if (args.contains("dump-arguments") && !args["dump-arguments"].isEmpty()) { + QFile logFile(args["dump-arguments"]); + logFile.open(QIODevice::WriteOnly | QIODevice::Text); + QTextStream out(&logFile); + for (QMap::const_iterator it = args.cbegin(), end = args.cend(); it != end; ++it) { + const QString& key = it.key(); + if (key == "arg-1") + out << "header-file"; + else if (key == "arg-2") + out << "typesystem-file"; + else + out << key; + if (!args[key].isEmpty()) + out << " = " << args[key]; + out << endl; + } + } + return true; +} + diff --git a/sources/shiboken2/tests/test_generator/dummygenerator.h b/sources/shiboken2/tests/test_generator/dummygenerator.h new file mode 100644 index 000000000..5ab95a925 --- /dev/null +++ b/sources/shiboken2/tests/test_generator/dummygenerator.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 DUMMYGENERATOR_H +#define DUMMYGENERATOR_H + +#include "generator.h" + +class GENRUNNER_API DummyGenerator : public Generator +{ +public: + DummyGenerator() {} + ~DummyGenerator() {} + bool doSetup(const QMap& args); + const char* name() const { return "DummyGenerator"; } + +protected: + void writeFunctionArguments(QTextStream&, const AbstractMetaFunction*, Options) const {} + void writeArgumentNames(QTextStream&, const AbstractMetaFunction*, Options) const {} + QString fileNameForClass(const AbstractMetaClass* metaClass) const; + void generateClass(QTextStream& s, const AbstractMetaClass* metaClass); + void finishGeneration() {} +}; + +#endif // DUMMYGENERATOR_H diff --git a/sources/shiboken2/tests/test_generator/dummygentest-project.txt.in b/sources/shiboken2/tests/test_generator/dummygentest-project.txt.in new file mode 100644 index 000000000..0a076d8bd --- /dev/null +++ b/sources/shiboken2/tests/test_generator/dummygentest-project.txt.in @@ -0,0 +1,20 @@ +[generator-project] + +generator-set = dummy +header-file = @CMAKE_CURRENT_BINARY_DIR@/test_global.h +typesystem-file = @CMAKE_CURRENT_BINARY_DIR@/test_typesystem.xml +output-directory = /tmp/output + +dump-arguments = @CMAKE_CURRENT_BINARY_DIR@/dummygen-args.log + +include-path = /include/path/location1 +include-path = /include/path/location2 + +typesystem-path = /typesystem/path/location1 +typesystem-path = /typesystem/path/location2 + +api-version = 1.2.3 +debug = sparse + +no-suppress-warnings + diff --git a/sources/shiboken2/tests/test_generator/dummygentest.cpp b/sources/shiboken2/tests/test_generator/dummygentest.cpp new file mode 100644 index 000000000..ae028e2c8 --- /dev/null +++ b/sources/shiboken2/tests/test_generator/dummygentest.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 "dummygentest.h" +#include "dummygenerator.h" +#include "dummygentestconfig.h" +#include +#include +#include + +#define GENERATED_CONTENTS "// Generated code for class: Dummy" + +void DummyGenTest::initTestCase() +{ + int argc = 0; + char* argv[] = {NULL}; + QCoreApplication app(argc, argv); + workDir = QDir::currentPath(); + + headerFilePath = workDir + "/test_global.h"; + typesystemFilePath = workDir + "/test_typesystem.xml"; + projectFilePath = workDir + "/dummygentest-project.txt"; + generatedFilePath = QString("%1/dummy/dummy_generated.txt").arg(QDir::tempPath()); +} + +void DummyGenTest::testCallGenRunnerWithFullPathToDummyGenModule() +{ + QStringList args; + args.append("--generator-set=" DUMMYGENERATOR_BINARY_DIR "/dummy_generator" MODULE_EXTENSION); + args.append(QString("--output-directory=%1").arg(QDir::tempPath())); + args.append(headerFilePath); + args.append(typesystemFilePath); + int result = QProcess::execute("generatorrunner", args); + QCOMPARE(result, 0); + + QFile generatedFile(generatedFilePath); + generatedFile.open(QIODevice::ReadOnly); + QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed()); + generatedFile.close(); + + QVERIFY(generatedFile.remove()); +} + +void DummyGenTest::testCallGenRunnerWithNameOfDummyGenModule() +{ + QStringList args; + args.append("--generator-set=dummy"); + args.append(QString("--output-directory=%1").arg(QDir::tempPath())); + args.append(headerFilePath); + args.append(typesystemFilePath); + int result = QProcess::execute("generatorrunner", args); + QCOMPARE(result, 0); + + QFile generatedFile(generatedFilePath); + generatedFile.open(QIODevice::ReadOnly); + QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed()); + generatedFile.close(); + + QVERIFY(generatedFile.remove()); +} + +void DummyGenTest::testCallDummyGeneratorExecutable() +{ + QStringList args; + args.append(QString("--output-directory=%1").arg(QDir::tempPath())); + args.append(headerFilePath); + args.append(typesystemFilePath); + int result = QProcess::execute(DUMMYGENERATOR_BINARY, args); + QCOMPARE(result, 0); + + QFile generatedFile(generatedFilePath); + generatedFile.open(QIODevice::ReadOnly); + QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed()); + generatedFile.close(); + + QVERIFY(generatedFile.remove()); +} + +void DummyGenTest::testProjectFileArgumentsReading() +{ + QStringList args(QString("--project-file=%1/dummygentest-project.txt").arg(workDir)); + int result = QProcess::execute("generatorrunner", args); + QCOMPARE(result, 0); + + QFile logFile(workDir + "/dummygen-args.log"); + logFile.open(QIODevice::ReadOnly); + QStringList logContents; + while (!logFile.atEnd()) + logContents << logFile.readLine().trimmed(); + logContents.sort(); + QCOMPARE(logContents[0], QString("api-version = 1.2.3")); + QCOMPARE(logContents[1], QString("debug = sparse")); + QVERIFY(logContents[2].startsWith("dump-arguments = ")); + QVERIFY(logContents[2].endsWith("dummygen-args.log")); + QCOMPARE(logContents[3], QString("generator-set = dummy")); + QVERIFY(logContents[4].startsWith("header-file = ")); + QVERIFY(logContents[4].endsWith("test_global.h")); + QCOMPARE(logContents[5], + QDir::toNativeSeparators(QString("include-paths = /include/path/location1%1/include/path/location2").arg(PATH_SPLITTER))); + QCOMPARE(logContents[6], QString("no-suppress-warnings")); + QCOMPARE(logContents[7], QString("output-directory = /tmp/output")); + QVERIFY(logContents[8].startsWith("project-file = ")); + QVERIFY(logContents[8].endsWith("dummygentest-project.txt")); + QVERIFY(logContents[9].startsWith("typesystem-file = ")); + QVERIFY(logContents[9].endsWith("test_typesystem.xml")); + QCOMPARE(logContents[10], + QDir::toNativeSeparators(QString("typesystem-paths = /typesystem/path/location1%1/typesystem/path/location2").arg(PATH_SPLITTER))); +} + +QTEST_APPLESS_MAIN(DummyGenTest) + +#include "dummygentest.moc" + diff --git a/sources/shiboken2/tests/test_generator/dummygentest.h b/sources/shiboken2/tests/test_generator/dummygentest.h new file mode 100644 index 000000000..be8ca42af --- /dev/null +++ b/sources/shiboken2/tests/test_generator/dummygentest.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 DUMMYGENTABLETEST_H +#define DUMMYGENTABLETEST_H + +#include + +class DummyGenerator; + +class DummyGenTest : public QObject +{ + Q_OBJECT + +private: + QString workDir; + QString headerFilePath; + QString typesystemFilePath; + QString generatedFilePath; + QString projectFilePath; + +private slots: + void initTestCase(); + void testCallGenRunnerWithFullPathToDummyGenModule(); + void testCallGenRunnerWithNameOfDummyGenModule(); + void testCallDummyGeneratorExecutable(); + void testProjectFileArgumentsReading(); +}; + +#endif + diff --git a/sources/shiboken2/tests/test_generator/dummygentestconfig.h.in b/sources/shiboken2/tests/test_generator/dummygentestconfig.h.in new file mode 100644 index 000000000..9da17dcd3 --- /dev/null +++ b/sources/shiboken2/tests/test_generator/dummygentestconfig.h.in @@ -0,0 +1,15 @@ +#ifndef DUMMYGENTESTCONFIG_H +#define DUMMYGENTESTCONFIG_H + +#define MODULE_EXTENSION "@CMAKE_SHARED_LIBRARY_SUFFIX@" +#define DUMMYGENERATOR_BINARY "@DUMMYGENERATOR_EXECUTABLE@" +#define DUMMYGENERATOR_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@" + +#ifdef _WINDOWS + #define PATH_SPLITTER ";" +#else + #define PATH_SPLITTER ":" +#endif + +#endif // DUMMYGENTESTCONFIG_H + diff --git a/sources/shiboken2/tests/test_generator/main.cpp b/sources/shiboken2/tests/test_generator/main.cpp new file mode 100644 index 000000000..5c46ea006 --- /dev/null +++ b/sources/shiboken2/tests/test_generator/main.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $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 + +int main(int argc, char *argv[]) +{ + QStringList args; + args.append("--generator-set=dummy"); + for (int i = 1; i < argc; i++) + args.append(argv[i]); + return QProcess::execute("generatorrunner", args); +} + diff --git a/sources/shiboken2/tests/test_generator/run_test.cmake b/sources/shiboken2/tests/test_generator/run_test.cmake new file mode 100644 index 000000000..34a821d80 --- /dev/null +++ b/sources/shiboken2/tests/test_generator/run_test.cmake @@ -0,0 +1,11 @@ +# The tests are run through this script due to a limitation +# on versions of CMake lesser than 2.8, that prevent setting +# environment variables for tests from working. + +set(ENV{PATH} "${ENV_PATH}") +set(ENV{QT_PLUGIN_PATH} "${ENV_QT_PLUGIN_PATH}") +execute_process(COMMAND ${TEST} WORKING_DIRECTORY "${WORKDIR}" RESULT_VARIABLE OK) + +if(NOT OK EQUAL 0) + message(SEND_ERROR "${TEST} failed!") +endif() diff --git a/sources/shiboken2/tests/test_generator/test_global.h b/sources/shiboken2/tests/test_generator/test_global.h new file mode 100644 index 000000000..6a95200cf --- /dev/null +++ b/sources/shiboken2/tests/test_generator/test_global.h @@ -0,0 +1 @@ +struct Dummy {}; diff --git a/sources/shiboken2/tests/test_generator/test_typesystem.xml b/sources/shiboken2/tests/test_generator/test_typesystem.xml new file mode 100644 index 000000000..c19a4e95e --- /dev/null +++ b/sources/shiboken2/tests/test_generator/test_typesystem.xml @@ -0,0 +1,3 @@ + + + -- cgit v1.2.3