diff --git a/.gitignore b/.gitignore index aae05641..59228a2f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ *.lo *.o *.obj +*.pdb +*.cbt # Precompiled Headers *.gch @@ -43,6 +45,8 @@ ui_*.h *.jsc Makefile* *build-* +*resource.rc +*.FileListAbsolute.txt # CMake CMakeLists.txt.user @@ -82,9 +86,29 @@ Thumbs.db # Visual Studio Code .vscode/* +*.tlog + # Doxygen doxygen/html/* doxygen.log # Backup files *.bak +generated_cpp +generator/.vs +*.log +*.sln +*.vcxproj +*.filters +*.user +*.stash +*.tmp +generate.bat +generator/release + +/.vs/ +*/.vs +*/debug/* +*/release/* +src/.vs +lib diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..13566b81 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.vimrc b/.vimrc new file mode 100644 index 00000000..d5a9f893 --- /dev/null +++ b/.vimrc @@ -0,0 +1 @@ +set expandtab diff --git a/COPYING b/COPYING index 5ab7695a..c00103de 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,5 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 + 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 @@ -10,7 +10,7 @@ as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -112,7 +112,7 @@ modification follow. Pay close attention to the difference between a 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 + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other @@ -432,7 +432,7 @@ 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 + 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. @@ -455,7 +455,7 @@ 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 + END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries diff --git a/PythonQt.pro b/PythonQt.pro index fb297153..819e6f39 100644 --- a/PythonQt.pro +++ b/PythonQt.pro @@ -1,4 +1,6 @@ TEMPLATE = subdirs -CONFIG += ordered SUBDIRS = generator src extensions tests examples +tests.depends += src extensions +extensions.depends += src +examples.depends += src extensions diff --git a/build/PythonQt.prf b/build/PythonQt.prf index 5ce12467..208c1074 100644 --- a/build/PythonQt.prf +++ b/build/PythonQt.prf @@ -11,5 +11,8 @@ CONFIG(debug, debug|release) { DEBUG_EXT = } -win32::LIBS += $$DESTDIR/../lib/PythonQt-Qt5-Python$${PYTHON_VERSION}$${DEBUG_EXT}.lib -unix::LIBS += -L$$DESTDIR/../lib -lPythonQt-Qt5-Python$${PYTHON_VERSION}$${DEBUG_EXT} +PYTHONQT_LIB_NAME=PythonQt-Qt$${QT_MAJOR_VERSION}-Python$${PYTHON_VERSION}$${DEBUG_EXT} + +win32-g++: LIBS += $$DESTDIR/../lib/$${PYTHONQT_LIB_NAME}.dll +win32-*msvc*: LIBS += $$DESTDIR/../lib/$${PYTHONQT_LIB_NAME}.lib +unix: LIBS += -L$$DESTDIR/../lib -l$${PYTHONQT_LIB_NAME} diff --git a/build/PythonQt_QtAll.prf b/build/PythonQt_QtAll.prf index 10d9056f..eb80789c 100644 --- a/build/PythonQt_QtAll.prf +++ b/build/PythonQt_QtAll.prf @@ -9,5 +9,7 @@ CONFIG(debug, debug|release) { DEBUG_EXT = } -win32::LIBS += $$DESTDIR/../lib/PythonQt_QtAll-Qt5-Python$${PYTHON_VERSION}$${DEBUG_EXT}.lib -unix::LIBS += -L$$DESTDIR/../lib -lPythonQt_QtAll-Qt5-Python$${PYTHON_VERSION}$${DEBUG_EXT} \ No newline at end of file + +win32-g++: LIBS += $$DESTDIR/../lib/PythonQt_QtAll-Qt5-Python$${PYTHON_VERSION}$${DEBUG_EXT}.dll +win32-msvc*: LIBS += $$DESTDIR/../lib/PythonQt_QtAll-Qt5-Python$${PYTHON_VERSION}$${DEBUG_EXT}.lib +unix: LIBS += -L$$DESTDIR/../lib -lPythonQt_QtAll-Qt5-Python$${PYTHON_VERSION}$${DEBUG_EXT} \ No newline at end of file diff --git a/build/common.prf b/build/common.prf index 013c59f5..4d8f9e42 100644 --- a/build/common.prf +++ b/build/common.prf @@ -25,47 +25,39 @@ PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_$${QT_MAJOR_VERSION}$${QT_MINOR_VERSION} !exists($$PYTHONQT_GENERATED_PATH) { - contains( QT_MAJOR_VERSION, 5 ) { - contains( QT_MINOR_VERSION, 10 ) { - PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_56 - } - else:contains( QT_MINOR_VERSION, 11 ) { - PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_511 - } - else:contains( QT_MINOR_VERSION, 1 ) { - PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_50 - } - else:contains( QT_MINOR_VERSION, 2 ) { + # For Qt5 we know that the older generated wrappers work with the later + # versions, even (apparently) Qt5.15, so: + equals(QT_MAJOR_VERSION, 5) { + # Qt5: have 5.0, 5.3, 5.4, 5.6 and 5.11 at present: + lessThan(QT_MINOR_VERSION, 3) { # 5.1, 5.2 PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_50 } - else:contains( QT_MINOR_VERSION, 3 ) { - PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_53 - } - else:contains( QT_MINOR_VERSION, 4 ) { - PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_54 - } - else:contains( QT_MINOR_VERSION, 5 ) { + else: lessThan(QT_MINOR_VERSION, 6) { # 5.5 PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_54 - } - else:contains( QT_MINOR_VERSION, 6 ) { - PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_56 - } - else:contains( QT_MINOR_VERSION, 7 ) { - PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_56 } - else:contains( QT_MINOR_VERSION, 8 ) { + else: lessThan(QT_MINOR_VERSION, 11) { # 5.7, 5.8, 5.9, 5.10 PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_56 } - else:contains( QT_MINOR_VERSION, 9 ) { - PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_56 - } - else { - PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_56 + else { # >5.11 + # LATEST Qt5 generated files: + PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp_511 } } + + !exists($$PYTHONQT_GENERATED_PATH) { + error("No generated sources exist for Qt$${QT_VERSION}") + } } } -VERSION = 3.2.0 +!build_pass { + message("Qt version: Qt$${QT_VERSION}") + message("Using generated sources files from $${PYTHONQT_GENERATED_PATH}") +} +VERSION = 3.2.0 win32: CONFIG += skip_target_version_ext +gcc|win32-clang-msvc:QMAKE_CXXFLAGS += -Wno-deprecated-declarations -Wuninitialized -Winit-self -pedantic +win32-clang-msvc:QMAKE_CXXFLAGS += -Wno-unused-command-line-argument +#Do not issue warning to system includes +gcc:!isEmpty(QT_INSTALL_HEADERS): QMAKE_CXXFLAGS += -isystem $$[QT_INSTALL_HEADERS] diff --git a/build/python.prf b/build/python.prf index fe720091..aae26277 100644 --- a/build/python.prf +++ b/build/python.prf @@ -2,45 +2,112 @@ # Change this variable to your python version (2.6, 2.7, 3.3, ...) -PYTHON_VERSION=$$(PYTHON_VERSION) isEmpty( PYTHON_VERSION ) { - win32:PYTHON_VERSION=27 - unix:PYTHON_VERSION=2.7 + PYTHON_VERSION=$$(PYTHON_VERSION) +} +isEmpty( PYTHON_VERSION ) { + PYTHON_VERSION=2.7 +} + +isEmpty( PYTHON_DIR ) { + PYTHON_DIR=$$(PYTHON_DIR) +} +!isEmpty( PYTHON_DIR ) { + PYTHON_DIR=$${PYTHON_DIR}/ } - -macx { - # for macx you need to have the Python development kit installed as framework - INCLUDEPATH += /System/Library/Frameworks/Python.framework/Headers - LIBS += -F/System/Library/Frameworks -framework Python -} else:win32 { - # for windows install a Python development kit or build Python yourself from the sources - # Make sure that you set the environment variable PYTHON_PATH to point to your - # python installation (or the python sources/header files when building from source). - # Make sure that you set the environment variable PYTHON_LIB to point to - # the directory where the python libs are located. - # - # When using the prebuild Python installer, this will be: - # set PYTHON_PATH = c:\Python26 - # set PYTHON_LIB = c:\Python26\libs - # - # When using the python sources, this will be something like: - # set PYTHON_PATH = c:\yourDir\Python-2.6.1\ - # set PYTHON_LIB = c:\yourDir\Python-2.6.1\PCbuild8\Win32 - - # check if debug or release - CONFIG(debug, debug|release) { - DEBUG_EXT = _d - } else { - DEBUG_EXT = - } - - win32:INCLUDEPATH += $$(PYTHON_PATH)/PC $$(PYTHON_PATH)/include - win32:LIBS += $$(PYTHON_LIB)/python$${PYTHON_VERSION}$${DEBUG_EXT}.lib -} else:unix { - # on linux, python-config is used to autodetect Python. - # make sure that you have installed a matching python-dev package. +PYTHON_VERSION_MAJOR=$$section(PYTHON_VERSION, ., 0, 0) +PYTHON_VERSION_MINOR=$$section(PYTHON_VERSION, ., 1, 1) + +!equals(PYTHON_VERSION, $${PYTHON_VERSION_MAJOR}.$${PYTHON_VERSION_MINOR}) { + error("Failed to parse PYTHON_VERSION:\"$$PYTHON_VERSION\"") +} else { + message(Using Python version $${PYTHON_VERSION}) +} + + +# Python 2.x has problems: +# 1) https://wiki.gentoo.org/wiki/Project:Python/Strict_aliasing +# 2) deprecated implicit cast of string literals to char* +equals(PYTHON_VERSION_MAJOR, 2) { + gcc:QMAKE_CXXFLAGS *= -fno-strict-aliasing -Wno-write-strings + # Qt 5.4 adds this option, but this is not compatible with the Python API + msvc: QMAKE_CXXFLAGS -= -Zc:strictStrings +} + +contains(PKGCONFIG, "python.*"){ +# If `pkg-config` is configured, use `qmake PKGCONFIG+=python3.8-embed CONFIG+=...` +# or `PKGCONFIG+=python2.7m`-like form for older versions, +# see `pkg-config --list-all | grep python` for details. +# This can help with GNU/Linux (including macOS with Homebrew), MSYS2/MinGW environment, +# and also with OpenEmbedded and other cross-builds + CONFIG += link_pkgconfig + PYTHON_PKGCONFIG = $$member($$unique($$find(PKGCONFIG, "python.*")), 1, 1) + # add rpath + PYTHON_LIBDIR = $$system($$pkgConfigExecutable() --libs-only-L $$PYTHON_PKGCONFIG) + QMAKE_RPATHDIR += $$replace(PYTHON_LIBDIR,-L,) +} else:macx:isEmpty(PYTHON_DIR){ + # for macx you need to have the Python development kit installed as framework + INCLUDEPATH += /System/Library/Frameworks/Python.framework/Headers + LIBS += -F/System/Library/Frameworks -framework Python +} else:win32 { + # for windows install a Python development kit or build Python yourself from the sources + # Make sure that you set the environment variable PYTHON_PATH to point to your + # python installation (or the python sources/header files when building from source). + # Make sure that you set the environment variable PYTHON_LIB to point to + # the directory where the python libs are located. + # + # When using the prebuild Python installer, this will be: + # set PYTHON_PATH = c:\Python26 + # set PYTHON_LIB = c:\Python26\libs + # + # When using the python sources, this will be something like: + # set PYTHON_PATH = c:\yourDir\Python-2.6.1\ + # set PYTHON_LIB = c:\yourDir\Python-2.6.1\PCbuild8\Win32 + + # check if debug or release + CONFIG(debug, debug|release) { + DEBUG_EXT = _d + } else { + DEBUG_EXT = + } + + isEmpty(PYTHON_PATH):PYTHON_PATH=$(PYTHON_PATH) + isEmpty(PYTHON_PATH)|!exists("$$PYTHON_PATH\\include") | !exists("$$PYTHON_PATH\\libs\\") { + error("PYTHON_PATH must be set to correct folder with \\libs and \\include subfolders ") + } + + #We need to destinguish 64-bit build to add a workaround option + #The only known problematic case is MinGW with external (MSVC-built) Python2 + mingw:equals(PYTHON_VERSION_MAJOR, 2): isEmpty(QMAKE_TARGET.arch):system(\ + $$system_quote($$system_path($${PYTHON_PATH}/python.exe)) -c \ + $$system_quote(import sysconfig;exit(0 if 0 <= sysconfig.get_platform().find(\'win-amd64\') else 1))\ + ):DEFINES += MS_WIN64 + + INCLUDEPATH += $$shell_path($${PYTHON_PATH}/include) + + LIBS += $$shell_path(-L$${PYTHON_PATH}/libs) + LIBS += -lpython$${PYTHON_VERSION_MAJOR}$${PYTHON_VERSION_MINOR}$${DEBUG_EXT} + + # Hack for "CONFIG+=testcase" and 'make check' to add python's dll to PATH + deppath += $$shell_path($${PYTHON_PATH}) + +} else:unix { + # on linux, python-config is used to autodetect Python. + # make sure that you have installed a matching python-dev package. - unix:LIBS += $$system(python$${PYTHON_VERSION}-config --ldflags) - unix:QMAKE_CXXFLAGS += $$system(python$${PYTHON_VERSION}-config --includes) -} + PYTHON_CONFIG = $${PYTHON_DIR}/bin/python$${PYTHON_VERSION}-config + PYTHON_CONFIG_OPTIONS_LIBS = --libs + equals(PYTHON_VERSION_MAJOR, 3):!lessThan(PYTHON_VERSION_MINOR, 8) { + # Since 3.8 `--embed` is needed + PYTHON_CONFIG_OPTIONS_LIBS += --embed + } + LIBS += $$system($${PYTHON_CONFIG} $${PYTHON_CONFIG_OPTIONS_LIBS}) + QMAKE_CXXFLAGS += $$system($${PYTHON_CONFIG} --includes) + PYTHON_LFLAGS = $$system($${PYTHON_CONFIG} --ldflags) + QMAKE_LFLAGS += $${PYTHON_LFLAGS} + # add rpath + PYTHON_LIBDIR = $$find(PYTHON_LFLAGS,-L.*) + PYTHON_RPATH = $$replace(PYTHON_LIBDIR,-L,) + QMAKE_RPATHDIR += $$PYTHON_RPATH +} diff --git a/examples/CPPPyWrapperExample/CPPPyWrapperExample.pro b/examples/CPPPyWrapperExample/CPPPyWrapperExample.pro index 9d52a9e1..16434995 100644 --- a/examples/CPPPyWrapperExample/CPPPyWrapperExample.pro +++ b/examples/CPPPyWrapperExample/CPPPyWrapperExample.pro @@ -9,9 +9,7 @@ DESTDIR = ../../lib include ( ../../build/common.prf ) include ( ../../build/PythonQt.prf ) -contains(QT_MAJOR_VERSION, 5) { - QT += widgets -} +QT += widgets SOURCES += \ CPPPyWrapperExample.cpp diff --git a/examples/PyCPPWrapperExample/PyCPPWrapperExample.pro b/examples/PyCPPWrapperExample/PyCPPWrapperExample.pro index 05fe3da9..7ada7319 100644 --- a/examples/PyCPPWrapperExample/PyCPPWrapperExample.pro +++ b/examples/PyCPPWrapperExample/PyCPPWrapperExample.pro @@ -12,9 +12,7 @@ DESTDIR = ../../lib include ( ../../build/common.prf ) include ( ../../build/PythonQt.prf ) -contains(QT_MAJOR_VERSION, 5) { - QT += widgets -} +QT += widgets HEADERS += \ CustomObjects.h diff --git a/examples/PyCustomMetaTypeExample/PyCustomMetaTypeExample.pro b/examples/PyCustomMetaTypeExample/PyCustomMetaTypeExample.pro index 69db9b5a..952449f5 100644 --- a/examples/PyCustomMetaTypeExample/PyCustomMetaTypeExample.pro +++ b/examples/PyCustomMetaTypeExample/PyCustomMetaTypeExample.pro @@ -12,9 +12,7 @@ DESTDIR = ../../lib include ( ../../build/common.prf ) include ( ../../build/PythonQt.prf ) -contains(QT_MAJOR_VERSION, 5) { - QT += widgets -} +QT += widgets HEADERS += \ CustomObject.h diff --git a/examples/PyDecoratorsExample/PyDecoratorsExample.pro b/examples/PyDecoratorsExample/PyDecoratorsExample.pro index 7367f220..06bb8de4 100644 --- a/examples/PyDecoratorsExample/PyDecoratorsExample.pro +++ b/examples/PyDecoratorsExample/PyDecoratorsExample.pro @@ -12,9 +12,7 @@ DESTDIR = ../../lib include ( ../../build/common.prf ) include ( ../../build/PythonQt.prf ) -contains(QT_MAJOR_VERSION, 5) { - QT += widgets -} +QT += widgets HEADERS += \ PyExampleDecorators.h diff --git a/examples/PyGettingStarted/PyGettingStarted.pro b/examples/PyGettingStarted/PyGettingStarted.pro index 1a5fee84..bf1d4d05 100644 --- a/examples/PyGettingStarted/PyGettingStarted.pro +++ b/examples/PyGettingStarted/PyGettingStarted.pro @@ -14,9 +14,7 @@ CONFIG += console include ( ../../build/common.prf ) include ( ../../build/PythonQt.prf ) -contains(QT_MAJOR_VERSION, 5) { - QT += widgets -} +QT += widgets SOURCES += \ main.cpp diff --git a/examples/PyGuiExample/PyGuiExample.pro b/examples/PyGuiExample/PyGuiExample.pro index 7baa529b..bd200da0 100644 --- a/examples/PyGuiExample/PyGuiExample.pro +++ b/examples/PyGuiExample/PyGuiExample.pro @@ -11,9 +11,7 @@ mac:CONFIG -= app_bundle DESTDIR = ../../lib -contains(QT_MAJOR_VERSION, 5) { - QT += widgets -} +QT += widgets include ( ../../build/common.prf ) include ( ../../build/PythonQt.prf ) diff --git a/examples/PyLauncher/PyLauncher.pro b/examples/PyLauncher/PyLauncher.pro index f1f98b40..e8b9686b 100644 --- a/examples/PyLauncher/PyLauncher.pro +++ b/examples/PyLauncher/PyLauncher.pro @@ -11,9 +11,7 @@ mac:CONFIG -= app_bundle DESTDIR = ../../lib -contains(QT_MAJOR_VERSION, 5) { - QT += widgets -} +QT += widgets include ( ../../build/common.prf ) include ( ../../build/PythonQt.prf ) diff --git a/examples/PyScriptingConsole/PyScriptingConsole.pro b/examples/PyScriptingConsole/PyScriptingConsole.pro index ef7a1955..b2b7b511 100644 --- a/examples/PyScriptingConsole/PyScriptingConsole.pro +++ b/examples/PyScriptingConsole/PyScriptingConsole.pro @@ -15,9 +15,7 @@ include ( ../../build/common.prf ) include ( ../../build/PythonQt.prf ) include ( ../../build/PythonQt_QtAll.prf ) -contains(QT_MAJOR_VERSION, 5) { - QT += widgets -} +QT += widgets HEADERS += \ PyExampleObject.h diff --git a/extensions/PythonQt_QtAll/PythonQt_QtAll.cpp b/extensions/PythonQt_QtAll/PythonQt_QtAll.cpp index f6dcd17a..50a0ccec 100644 --- a/extensions/PythonQt_QtAll/PythonQt_QtAll.cpp +++ b/extensions/PythonQt_QtAll/PythonQt_QtAll.cpp @@ -117,7 +117,5 @@ namespace PythonQt_QtAll #ifdef PYTHONQT_WITH_UITOOLS PythonQt_init_QtUiTools(0); #endif - }; -}; - - + } +} diff --git a/extensions/PythonQt_QtAll/PythonQt_QtAll.h b/extensions/PythonQt_QtAll/PythonQt_QtAll.h index 7f1de8f3..689e2e83 100644 --- a/extensions/PythonQt_QtAll/PythonQt_QtAll.h +++ b/extensions/PythonQt_QtAll/PythonQt_QtAll.h @@ -47,6 +47,6 @@ namespace PythonQt_QtAll { //! initialize the Qt binding PYTHONQT_QTALL_EXPORT void init(); -}; +} #endif diff --git a/extensions/PythonQt_QtAll/PythonQt_QtAll.pro b/extensions/PythonQt_QtAll/PythonQt_QtAll.pro index 4bf5da46..ade1b36a 100644 --- a/extensions/PythonQt_QtAll/PythonQt_QtAll.pro +++ b/extensions/PythonQt_QtAll/PythonQt_QtAll.pro @@ -1,19 +1,26 @@ # get external pythonqtall config or enable all by default +isEmpty( PYTHONQTALL_CONFIG ) { + PYTHONQTALL_CONFIG = $$(PYTHONQTALL_CONFIG) +} + isEmpty( PYTHONQTALL_CONFIG ) { message("using default PythonQt_QtAll Configuration") CONFIG += PythonQtCore - CONFIG += PythonQtGui - CONFIG += PythonQtSvg - CONFIG += PythonQtSql - CONFIG += PythonQtNetwork - CONFIG += PythonQtOpengl - CONFIG += PythonQtXml - CONFIG += PythonQtXmlpatterns - CONFIG += PythonQtMultimedia - CONFIG += PythonQtQml - CONFIG += PythonQtQuick - CONFIG += PythonQtUiTools + qtHaveModule(gui):qtHaveModule(widgets):CONFIG += PythonQtGui + qtHaveModule(svg):CONFIG += PythonQtSvg + qtHaveModule(sql):CONFIG += PythonQtSql + qtHaveModule(network):CONFIG += PythonQtNetwork + lessThan(QT_MAJOR_VERSION, 6) { + # module is empty in Qt6 + qtHaveModule(opengl):CONFIG += PythonQtOpengl + } + qtHaveModule(xml):CONFIG += PythonQtXml + qtHaveModule(xmlpatterns):CONFIG += PythonQtXmlpatterns + qtHaveModule(multimedia):CONFIG += PythonQtMultimedia + qtHaveModule(qml):CONFIG += PythonQtQml + qtHaveModule(quick):CONFIG += PythonQtQuick + qtHaveModule(uitools):CONFIG += PythonQtUiTools qtHaveModule(webkit):CONFIG += PythonQtWebKit } else { @@ -31,15 +38,21 @@ include ( ../../build/common.prf ) include ( ../../build/PythonQt.prf ) TARGET = $$replace(TARGET, PythonXY, Python$${PYTHON_VERSION}) -CONFIG += dll qt +CONFIG += qt strict_c++ + +!static:!staticlib { + CONFIG += dll + # Force linker to complain on undefined references for dll/so/dylib build when possible + QMAKE_LFLAGS_SHLIB += $$QMAKE_LFLAGS_NOUNDEF +} DEFINES += PYTHONQT_QTALL_EXPORTS HEADERS += \ - PythonQt_QtAll.h + $$PWD/PythonQt_QtAll.h SOURCES += \ - PythonQt_QtAll.cpp + $$PWD/PythonQt_QtAll.cpp unix { CONFIG += create_pc create_prl no_install_prl @@ -52,87 +65,91 @@ unix { QMAKE_PKGCONFIG_VERSION = $$VERSION } -unix: target.path = /lib +unix: target.path = $${INSTALL_PREFIX}/lib win32: target.path = / headers.files = $${HEADERS} -headers.path = /include +headers.path = $${INSTALL_PREFIX}/include INSTALLS += target headers +defineTest(Xinclude) { + f=$$PYTHONQT_GENERATED_PATH/$$1/$${1}.pri + exists($$f):include($$f):export(HEADERS):export(SOURCES):export(DEFINES) + +} + + PythonQtCore { DEFINES += PYTHONQT_WITH_CORE - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_core/com_trolltech_qt_core.pri) + Xinclude (com_trolltech_qt_core) + QT += core } PythonQtGui { DEFINES += PYTHONQT_WITH_GUI - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_gui/com_trolltech_qt_gui.pri) + Xinclude (com_trolltech_qt_gui) QT += gui widgets printsupport } PythonQtSvg { DEFINES += PYTHONQT_WITH_SVG - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_svg/com_trolltech_qt_svg.pri) - QT +=svg + Xinclude (com_trolltech_qt_svg) + QT += svg + !lessThan(QT_MAJOR_VERSION,6): QT += svgwidgets } PythonQtSql { DEFINES += PYTHONQT_WITH_SQL - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_sql/com_trolltech_qt_sql.pri) + Xinclude (com_trolltech_qt_sql) QT += sql } PythonQtNetwork { DEFINES += PYTHONQT_WITH_NETWORK - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_network/com_trolltech_qt_network.pri) + Xinclude (com_trolltech_qt_network) QT += network } PythonQtOpengl { DEFINES += PYTHONQT_WITH_OPENGL - PythonQtCore: include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_opengl/com_trolltech_qt_opengl.pri) QT += opengl -} - -PythonQtXml { - DEFINES += PYTHONQT_WITH_XML - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_xml/com_trolltech_qt_xml.pri) + PythonQtCore: Xinclude (com_trolltech_qt_opengl) QT += xml } PythonQtXmlpatterns { DEFINES += PYTHONQT_WITH_XMLPATTERNS - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_xmlpatterns/com_trolltech_qt_xmlpatterns.pri) + Xinclude (com_trolltech_qt_xmlpatterns) QT += xmlpatterns } PythonQtMultimedia { DEFINES += PYTHONQT_WITH_MULTIMEDIA - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_multimedia/com_trolltech_qt_multimedia.pri) - QT += multimedia multimediawidgets + Xinclude (com_trolltech_qt_multimedia) + QT += multimedia multimediawidgets } PythonQtQml { DEFINES += PYTHONQT_WITH_QML - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_qml/com_trolltech_qt_qml.pri) + Xinclude (com_trolltech_qt_qml) QT += qml } PythonQtQuick { DEFINES += PYTHONQT_WITH_QUICK - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_quick/com_trolltech_qt_quick.pri) + Xinclude (com_trolltech_qt_quick) QT += quick quickwidgets } PythonQtUiTools { DEFINES += PYTHONQT_WITH_UITOOLS - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_uitools/com_trolltech_qt_uitools.pri) + Xinclude (com_trolltech_qt_uitools) QT += uitools } PythonQtWebKit { DEFINES += PYTHONQT_WITH_WEBKIT - include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_webkit/com_trolltech_qt_webkit.pri) + Xinclude (com_trolltech_qt_webkit) QT += webkit webkitwidgets } diff --git a/generator/LICENSE.LGPL b/generator/LICENSE.LGPL index 9a30e8ce..22bc77aa 100644 --- a/generator/LICENSE.LGPL +++ b/generator/LICENSE.LGPL @@ -1,4 +1,4 @@ - GNU LESSER GENERAL PUBLIC LICENSE + GNU LESSER GENERAL PUBLIC LICENSE The Qt GUI Toolkit is Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). Contact: Nokia Corporation (qt-info@nokia.com) @@ -8,8 +8,8 @@ ------------------------------------------------------------------------- - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 + 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 @@ -20,7 +20,7 @@ as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -122,7 +122,7 @@ modification follow. Pay close attention to the difference between a 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 + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other @@ -442,7 +442,7 @@ 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 + 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. @@ -465,7 +465,7 @@ 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 + END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries diff --git a/generator/abstractmetabuilder.cpp b/generator/abstractmetabuilder.cpp index ba605259..faf16aee 100644 --- a/generator/abstractmetabuilder.cpp +++ b/generator/abstractmetabuilder.cpp @@ -54,7 +54,9 @@ #include #include #include -#include +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) +# include +#endif #include #include @@ -148,12 +150,17 @@ AbstractMetaBuilder::AbstractMetaBuilder() { } +AbstractMetaBuilder::~AbstractMetaBuilder() +{ + qDeleteAll(m_meta_classes); +} + void AbstractMetaBuilder::checkFunctionModifications() { TypeDatabase *types = TypeDatabase::instance(); SingleTypeEntryHash entryHash = types->entries(); QList entries = entryHash.values(); - foreach (TypeEntry *entry, entries) { + for (TypeEntry *entry : entries) { if (entry == 0) continue; if (!entry->isComplex() || entry->codeGeneration() == TypeEntry::GenerateNothing) @@ -162,7 +169,7 @@ void AbstractMetaBuilder::checkFunctionModifications() ComplexTypeEntry *centry = static_cast(entry); FunctionModificationList modifications = centry->functionModifications(); - foreach (FunctionModification modification, modifications) { + for (FunctionModification modification : modifications) { QString signature = modification.signature; QString name = signature.trimmed(); @@ -175,7 +182,7 @@ void AbstractMetaBuilder::checkFunctionModifications() AbstractMetaFunctionList functions = clazz->functions(); bool found = false; QStringList possibleSignatures; - foreach (AbstractMetaFunction *function, functions) { + for (AbstractMetaFunction *function : functions) { if (function->minimalSignature() == signature && function->implementingClass() == clazz) { found = true; break; @@ -358,34 +365,28 @@ void AbstractMetaBuilder::traverseBinaryArithmeticOperator(FunctionModelItem ite } void AbstractMetaBuilder::fixQObjectForScope(TypeDatabase *types, - NamespaceModelItem scope) + NamespaceModelItem scope) { - foreach (ClassModelItem item, scope->classes()) { + for (ClassModelItem item : scope->classes()) { QString qualified_name = item->qualifiedName().join("::"); TypeEntry *entry = types->findType(qualified_name); if (entry) { - if (isQObject(qualified_name) && entry->isComplex()) { - ((ComplexTypeEntry *) entry)->setQObject(true); - } - } + if (isQObject(qualified_name) && entry->isComplex()) { + ((ComplexTypeEntry *) entry)->setQObject(true); + } + } } - foreach (NamespaceModelItem item, scope->namespaceMap().values()) { + for (NamespaceModelItem item : scope->namespaceMap().values()) { if (scope != item) - fixQObjectForScope(types, item); + fixQObjectForScope(types, item); } } -static bool class_less_than(AbstractMetaClass *a, AbstractMetaClass *b) -{ - return a->name() < b->name(); -} - - void AbstractMetaBuilder::sortLists() { - qSort(m_meta_classes.begin(), m_meta_classes.end(), class_less_than); - foreach (AbstractMetaClass *cls, m_meta_classes) { + m_meta_classes.sort(); + for (AbstractMetaClass *cls : m_meta_classes) { cls->sortFunctions(); } } @@ -400,11 +401,15 @@ bool AbstractMetaBuilder::build() return false; QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); +# if QT_VERSION < QT_VERSION_CHECK(6,0,0) + stream.setCodec(QTextCodec::codecForName("UTF-8")); + /* Note required in Qt6: see the same call in asttoxml.cpp */ +# endif QByteArray contents = stream.readAll().toUtf8(); file.close(); Control control; + control.setSkipFunctionBody(true); Parser p(&control); pool __pool; @@ -425,14 +430,23 @@ bool AbstractMetaBuilder::build() // Start the generation... - foreach (ClassModelItem item, typeMap.values()) { + + // First automatically add all enums marked as QEnum into the TypeDatabase + // (if they don't contain an entry already). If there is an QEnum entry, + // the enum is obviously meant for scripting. + for (ClassModelItem item : typeMap.values()) { + autoAddQEnumsForClassItem(item); + } + + + for (ClassModelItem item : typeMap.values()) { AbstractMetaClass *cls = traverseClass(item); addAbstractMetaClass(cls); } QHash namespaceMap = m_dom->namespaceMap(); - foreach (NamespaceModelItem item, namespaceMap.values()) { + for (NamespaceModelItem item : namespaceMap.values()) { AbstractMetaClass *meta_class = traverseNamespace(item); if (meta_class) m_meta_classes << meta_class; @@ -442,7 +456,7 @@ bool AbstractMetaBuilder::build() // Some trickery to support global-namespace enums... QHash enumMap = m_dom->enumMap(); m_current_class = 0; - foreach (EnumModelItem item, enumMap) { + for (EnumModelItem item : enumMap) { AbstractMetaEnum *meta_enum = traverseEnum(item, 0, QSet()); if (meta_enum) { @@ -479,7 +493,7 @@ bool AbstractMetaBuilder::build() // Go through all typedefs to see if we have defined any // specific typedefs to be used as classes. TypeAliasList typeAliases = m_dom->typeAliases(); - foreach (TypeAliasModelItem typeAlias, typeAliases) { + for (TypeAliasModelItem typeAlias : typeAliases) { AbstractMetaClass *cls = traverseTypeAlias(typeAlias); addAbstractMetaClass(cls); } @@ -487,14 +501,14 @@ bool AbstractMetaBuilder::build() - foreach (AbstractMetaClass *cls, m_meta_classes) { + for (AbstractMetaClass *cls : m_meta_classes) { if (!cls->isInterface() && !cls->isNamespace()) { setupInheritance(cls); } } - foreach (AbstractMetaClass *cls, m_meta_classes) { + for (AbstractMetaClass *cls : m_meta_classes) { cls->fixFunctions(); if (cls->typeEntry() == 0) { @@ -511,7 +525,7 @@ bool AbstractMetaBuilder::build() } QList entries = TypeDatabase::instance()->entries().values(); - foreach (const TypeEntry *entry, entries) { + for (const TypeEntry *entry : entries) { if (entry->isPrimitive()) continue; @@ -547,25 +561,26 @@ bool AbstractMetaBuilder::build() { FunctionList hash_functions = m_dom->findFunctions("qHash"); - foreach (FunctionModelItem item, hash_functions) { + for (FunctionModelItem item : hash_functions) { registerHashFunction(item); } } { FunctionList hash_functions = m_dom->findFunctions("operator<<"); - foreach (FunctionModelItem item, hash_functions) { + for (FunctionModelItem item : hash_functions) { registerToStringCapability(item); } } { FunctionList compare_operators = m_dom->findFunctions("operator==") + + m_dom->findFunctions("operator!=") + m_dom->findFunctions("operator<=") + m_dom->findFunctions("operator>=") + m_dom->findFunctions("operator<") + m_dom->findFunctions("operator>"); - foreach (FunctionModelItem item, compare_operators) { + for (FunctionModelItem item : compare_operators) { traverseCompareOperator(item); } } @@ -576,21 +591,20 @@ bool AbstractMetaBuilder::build() + m_dom->findFunctions("operator/") + m_dom->findFunctions("operator*") + m_dom->findFunctions("operator&") + m_dom->findFunctions("operator|") + m_dom->findFunctions("operator%") + m_dom->findFunctions("operator^"); - foreach (FunctionModelItem item, stream_operators) { + for (FunctionModelItem item : stream_operators) { traverseBinaryArithmeticOperator(item); } } { FunctionList stream_operators = m_dom->findFunctions("operator<<") + m_dom->findFunctions("operator>>"); - foreach (FunctionModelItem item, stream_operators) { + for (FunctionModelItem item : stream_operators) { traverseStreamOperator(item); } } - figureOutEnumValues(); checkFunctionModifications(); - foreach (AbstractMetaClass *cls, m_meta_classes) { + for (AbstractMetaClass *cls : m_meta_classes) { setupEquals(cls); setupComparable(cls); setupClonable(cls); @@ -603,6 +617,33 @@ bool AbstractMetaBuilder::build() return true; } +void AbstractMetaBuilder::autoAddQEnumsForClassItem(ClassModelItem class_item) +{ + // also do this for sub-classes: + for (ClassModelItem sub_class : class_item->classMap().values()) { + autoAddQEnumsForClassItem(sub_class); + } + + auto qEnumDeclarations = class_item->qEnumDeclarations(); + for (EnumModelItem enum_item : class_item->enumMap().values()) { + if (enum_item) { + const auto& names = enum_item->qualifiedName(); + QString qualified_name = names.join("::"); + QString enum_name = enum_item->name(); + + bool hasQEnumDeclaration = qEnumDeclarations.contains(qualified_name) + || qEnumDeclarations.contains(enum_name); + + TypeEntry* type_entry = TypeDatabase::instance()->findType(qualified_name); + if (hasQEnumDeclaration && !type_entry) { + // automatically add enum type declared as Q_ENUM + type_entry = new EnumTypeEntry(QStringList(names.mid(0, names.size() - 1)).join("::"), names.last()); + TypeDatabase::instance()->addType(type_entry); + } + } + } +} + void AbstractMetaBuilder::addAbstractMetaClass(AbstractMetaClass *cls) { @@ -611,7 +652,15 @@ void AbstractMetaBuilder::addAbstractMetaClass(AbstractMetaClass *cls) cls->setOriginalAttributes(cls->attributes()); if (cls->typeEntry()->isContainer()) { - m_templates << cls; + QString name = cls->typeEntry()->name(); + if (cls->functions().size() || cls->baseClassNames().size()) { + if (!m_templates.contains(name)) { + m_templates[name] = cls; + } + else { + ReportHandler::warning(QString("Duplicate container type template '%1'").arg(name)); + } + } } else { m_meta_classes << cls; if (cls->typeEntry()->designatedInterface()) { @@ -650,24 +699,35 @@ AbstractMetaClass *AbstractMetaBuilder::traverseNamespace(NamespaceModelItem nam .arg(meta_class->package()) .arg(namespace_item->name())); - traverseEnums(model_dynamic_cast(namespace_item), meta_class, namespace_item->enumsDeclarations()); + traverseEnums(model_dynamic_cast(namespace_item), meta_class, namespace_item->qEnumDeclarations()); traverseFunctions(model_dynamic_cast(namespace_item), meta_class); // traverseClasses(model_dynamic_cast(namespace_item)); + // collect all include files (since namespace items might come from different files) + QSet includeFiles; + for (const auto& item : namespace_item->enums()) { + includeFiles.insert(item->fileName()); + } + for (const auto& item : namespace_item->functions()) { + includeFiles.insert(item->fileName()); + } + // (should we do this for typeAliases and inner namespaces too?) + pushScope(model_dynamic_cast(namespace_item)); m_namespace_prefix = currentScope()->qualifiedName().join("::"); ClassList classes = namespace_item->classes(); - foreach (ClassModelItem cls, classes) { + for (ClassModelItem cls : classes) { AbstractMetaClass *mjc = traverseClass(cls); addAbstractMetaClass(mjc); + includeFiles.insert(cls->fileName()); } // Go through all typedefs to see if we have defined any // specific typedefs to be used as classes. TypeAliasList typeAliases = namespace_item->typeAliases(); - foreach (TypeAliasModelItem typeAlias, typeAliases) { + for (TypeAliasModelItem typeAlias : typeAliases) { AbstractMetaClass *cls = traverseTypeAlias(typeAlias); addAbstractMetaClass(cls); } @@ -676,7 +736,7 @@ AbstractMetaClass *AbstractMetaBuilder::traverseNamespace(NamespaceModelItem nam // Traverse namespaces recursively QList inner_namespaces = namespace_item->namespaceMap().values(); - foreach (const NamespaceModelItem &ni, inner_namespaces) { + for (const NamespaceModelItem &ni : inner_namespaces) { AbstractMetaClass *mjc = traverseNamespace(ni); addAbstractMetaClass(mjc); } @@ -691,224 +751,13 @@ AbstractMetaClass *AbstractMetaBuilder::traverseNamespace(NamespaceModelItem nam QFileInfo info(namespace_item->fileName()); type->setInclude(Include(Include::IncludePath, info.fileName())); } - - return meta_class; -} - -struct Operator -{ - enum Type { Plus, ShiftLeft, None }; - - Operator() : type(None) { } - - int calculate(int x) { - switch (type) { - case Plus: return x + value; - case ShiftLeft: return x << value; - case None: return x; - } - return x; + // namespace items might come from different include files: + for (const QString& oneIncludeFile : includeFiles) { + QFileInfo info(oneIncludeFile); + type->addExtraInclude(Include(Include::IncludePath, info.fileName())); } - Type type; - int value; -}; - - - -Operator findOperator(QString *s) { - const char *names[] = { - "+", - "<<" - }; - - for (int i=0; i 0) { - bool ok; - QString right = str.mid(splitPoint + name.length()); - Operator op; - op.value = right.toInt(&ok); - if (ok) { - op.type = Operator::Type(i); - *s = str.left(splitPoint).trimmed(); - return op; - } - } - } - return Operator(); -} - -int AbstractMetaBuilder::figureOutEnumValue(const QString &stringValue, - int oldValuevalue, - AbstractMetaEnum *meta_enum, - AbstractMetaFunction *meta_function) -{ - if (stringValue.isEmpty()) - return oldValuevalue; - - QStringList stringValues = stringValue.split("|"); - - int returnValue = 0; - - bool matched = false; - - for (int i=0; i 0 && s.at(0) == QLatin1Char('0')) - v = s.toUInt(&ok, 0); - else - v = s.toInt(&ok); - - if (ok) { - matched = true; - - } else if (m_enum_values.contains(s)) { - v = m_enum_values[s]->value(); - matched = true; - - } else { - AbstractMetaEnumValue *ev = 0; - - if (meta_enum && (ev = meta_enum->values().find(s))) { - v = ev->value(); - matched = true; - - } else if (meta_enum && (ev = meta_enum->enclosingClass()->findEnumValue(s, meta_enum))) { - v = ev->value(); - matched = true; - - } else { - /* - if (meta_enum) - ReportHandler::warning("unhandled enum value: " + s + " in " - + meta_enum->enclosingClass()->name() + "::" - + meta_enum->name()); - else - ReportHandler::warning("unhandled enum value: Unknown enum"); - */ - } - } - - if (matched) - returnValue |= op.calculate(v); - } - - if (!matched) { - /* not helpful... - QString warn = QString("unmatched enum %1").arg(stringValue); - - if (meta_function != 0) { - warn += QString(" when parsing default value of '%1' in class '%2'") - .arg(meta_function->name()) - .arg(meta_function->implementingClass()->name()); - } - - ReportHandler::warning(warn); - */ - returnValue = oldValuevalue; - } - - return returnValue; -} - -void AbstractMetaBuilder::figureOutEnumValuesForClass(AbstractMetaClass *meta_class, - QSet *classes) -{ - AbstractMetaClass *base = meta_class->baseClass(); - - if (base != 0 && !classes->contains(base)) - figureOutEnumValuesForClass(base, classes); - - if (classes->contains(meta_class)) - return; - - AbstractMetaEnumList enums = meta_class->enums(); - foreach (AbstractMetaEnum *e, enums) { - if (!e) { - ReportHandler::warning("bad enum in class " + meta_class->name()); - continue; - } - AbstractMetaEnumValueList lst = e->values(); - int value = 0; - for (int i=0; istringValue(), value, e); - lst.at(i)->setValue(value); - value++; - } - - // Check for duplicate values... - EnumTypeEntry *ete = e->typeEntry(); - if (!ete->forceInteger()) { - QHash entries; - foreach (AbstractMetaEnumValue *v, lst) { - - bool vRejected = ete->isEnumValueRejected(v->name()); - - AbstractMetaEnumValue *current = entries.value(v->value()); - if (current) { - bool currentRejected = ete->isEnumValueRejected(current->name()); - if (!currentRejected && !vRejected) { - /* Removed because I don't see the sense of rejecting duplicate values... - ReportHandler::warning( - QString("duplicate enum values: %1::%2, %3 and %4 are %5, already rejected: (%6)") - .arg(meta_class->name()) - .arg(e->name()) - .arg(v->name()) - .arg(entries[v->value()]->name()) - .arg(v->value()) - .arg(ete->enumValueRejections().join(", "))); - continue; - */ - } - } - - if (!vRejected) - entries[v->value()] = v; - } - - // Entries now contain all the original entries, no - // rejected ones... Use this to generate the enumValueRedirection table. - foreach (AbstractMetaEnumValue *reject, lst) { - if (!ete->isEnumValueRejected(reject->name())) - continue; - - AbstractMetaEnumValue *used = entries.value(reject->value()); - if (!used) { - ReportHandler::warning( - QString::fromLatin1("Rejected enum has no alternative...: %1::%2") - .arg(meta_class->name()) - .arg(reject->name())); - continue; - } - ete->addEnumValueRedirection(reject->name(), used->name()); - } - - } - } - - - - *classes += meta_class; -} - - -void AbstractMetaBuilder::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; - foreach (AbstractMetaClass *c, m_meta_classes) { - figureOutEnumValuesForClass(c, &classes); - } + return meta_class; } @@ -941,6 +790,8 @@ AbstractMetaEnum *AbstractMetaBuilder::traverseEnum(EnumModelItem enum_item, Abs return 0; } + static_cast(type_entry)->setEnumClass(enum_item->isEnumClass()); + AbstractMetaEnum *meta_enum = createMetaEnum(); if ( enumsDeclarations.contains(qualified_name) || enumsDeclarations.contains(enum_name)) { @@ -957,7 +808,7 @@ AbstractMetaEnum *AbstractMetaBuilder::traverseEnum(EnumModelItem enum_item, Abs ReportHandler::debugMedium(QString(" - traversing enum %1").arg(meta_enum->fullName())); - foreach (EnumeratorModelItem value, enum_item->enumerators()) { + for (EnumeratorModelItem value : enum_item->enumerators()) { if (meta_enum->typeEntry()->isEnumValueRejected(value->name())) { continue; } @@ -969,7 +820,7 @@ AbstractMetaEnum *AbstractMetaBuilder::traverseEnum(EnumModelItem enum_item, Abs meta_enum->addEnumValue(meta_enum_value); ReportHandler::debugFull(" - " + meta_enum_value->name() + " = " - + meta_enum_value->value()); + + QString::number(meta_enum_value->value())); // Add into global register... if (enclosing) @@ -1089,17 +940,18 @@ AbstractMetaClass *AbstractMetaBuilder::traverseClass(ClassModelItem class_item) template_args.append(param_type); } meta_class->setTemplateArguments(template_args); - - parseQ_Property(meta_class, class_item->propertyDeclarations()); + meta_class->setHasActualDeclaration(class_item->hasActualDeclaration()); traverseFunctions(model_dynamic_cast(class_item), meta_class); - traverseEnums(model_dynamic_cast(class_item), meta_class, class_item->enumsDeclarations()); + traverseEnums(model_dynamic_cast(class_item), meta_class, class_item->qEnumDeclarations()); traverseFields(model_dynamic_cast(class_item), meta_class); + parseQ_Property(meta_class, class_item->propertyDeclarations()); + // Inner classes { QList inner_classes = class_item->classMap().values(); - foreach (const ClassModelItem &ci, inner_classes) { + for (const ClassModelItem &ci : inner_classes) { AbstractMetaClass *cl = traverseClass(ci); if (cl) { cl->setEnclosingClass(meta_class); @@ -1112,7 +964,7 @@ AbstractMetaClass *AbstractMetaBuilder::traverseClass(ClassModelItem class_item) // Go through all typedefs to see if we have defined any // specific typedefs to be used as classes. TypeAliasList typeAliases = class_item->typeAliases(); - foreach (TypeAliasModelItem typeAlias, typeAliases) { + for (TypeAliasModelItem typeAlias : typeAliases) { AbstractMetaClass *cls = traverseTypeAlias(typeAlias); if (cls != 0) { cls->setEnclosingClass(meta_class); @@ -1123,8 +975,9 @@ AbstractMetaClass *AbstractMetaBuilder::traverseClass(ClassModelItem class_item) m_current_class = old_current_class; - // Set the default include file name - if (!type->include().isValid()) { + // Set the default include file name. In case we saw an template instance earlier, + // overwrite the include file when we see the actual declaration. + if (!type->include().isValid() || class_item->hasActualDeclaration()) { QFileInfo info(class_item->fileName()); type->setInclude(Include(Include::IncludePath, info.fileName())); } @@ -1187,7 +1040,7 @@ AbstractMetaField *AbstractMetaBuilder::traverseField(VariableModelItem field, c void AbstractMetaBuilder::traverseFields(ScopeModelItem scope_item, AbstractMetaClass *meta_class) { - foreach (VariableModelItem field, scope_item->variables()) { + for (VariableModelItem field : scope_item->variables()) { AbstractMetaField *meta_field = traverseField(field, meta_class); if (meta_field) { @@ -1218,7 +1071,7 @@ void AbstractMetaBuilder::setupFunctionDefaults(AbstractMetaFunction *meta_funct void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scope_item, AbstractMetaClass *meta_class) { - foreach (FunctionModelItem function, scope_item->functions()) { + for (FunctionModelItem function : scope_item->functions()) { AbstractMetaFunction *meta_function = traverseFunction(function); if (meta_function) { @@ -1236,7 +1089,7 @@ void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scope_item, AbstractM } } else if (QPropertySpec *write = meta_class->propertySpecForWrite(meta_function->name())) { - if (write->type() == meta_function->arguments().at(0)->type()->typeEntry()) { + if (meta_function->arguments().size() == 1 && write->type() == meta_function->arguments().at(0)->type()->typeEntry()) { *meta_function += AbstractMetaAttributes::PropertyWriter; meta_function->setPropertySpec(write); // printf("%s is writer for %s\n", @@ -1256,8 +1109,15 @@ void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scope_item, AbstractM bool isInvalidDestructor = meta_function->isDestructor() && meta_function->isPrivate(); bool isInvalidConstructor = meta_function->isConstructor() && (meta_function->isPrivate() || meta_function->isInvalid()); + if (isInvalidConstructor && meta_function->arguments().size() == 1 && + meta_class->qualifiedCppName() == meta_function->arguments().at(0)->type()->typeEntry()->qualifiedCppName()) + { + // deleted or private copy constructor, it seems copying is not allowed + meta_class->typeEntry()->setNoCopy(true); + } if ((isInvalidDestructor || isInvalidConstructor) - && !meta_class->hasNonPrivateConstructor()) { + && !meta_class->hasNonPrivateConstructor()) + { *meta_class += AbstractMetaAttributes::Final; } else if (meta_function->isConstructor() && !meta_function->isPrivate()) { *meta_class -= AbstractMetaAttributes::Final; @@ -1302,6 +1162,7 @@ void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scope_item, AbstractM if (!meta_function->isPublic()) { meta_class->setHasPublicDestructor(false); } + meta_class->setHasVirtualDestructor(meta_function->isVirtual()); } } } @@ -1329,13 +1190,7 @@ bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass *meta_class) TypeParser::Info info = TypeParser::parse(complete_name); QString base_name = info.qualified_name.join("::"); - AbstractMetaClass *templ = 0; - foreach (AbstractMetaClass *c, m_templates) { - if (c->typeEntry()->name() == base_name) { - templ = c; - break; - } - } + AbstractMetaClass *templ = m_templates.value(base_name); if (templ == 0) templ = m_meta_classes.findClass(base_name); @@ -1406,8 +1261,11 @@ bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass *meta_class) if (types->isClassRejected(base_classes.at(i))) continue; + AbstractMetaClass *base_class = m_meta_classes.findClass(base_classes.at(i)); + if (base_class) { + meta_class->addSuperClass(base_class); + } if (i != primary) { - AbstractMetaClass *base_class = m_meta_classes.findClass(base_classes.at(i)); if (base_class == 0) { ReportHandler::warning(QString("class not found for setup inheritance '%1'").arg(base_classes.at(i))); return false; @@ -1426,7 +1284,7 @@ bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass *meta_class) meta_class->addInterface(iface); AbstractMetaClassList interfaces = iface->interfaces(); - foreach (AbstractMetaClass *iface, interfaces) + for (AbstractMetaClass *iface : interfaces) meta_class->addInterface(iface); } } @@ -1434,11 +1292,11 @@ bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass *meta_class) return true; } -void AbstractMetaBuilder::traverseEnums(ScopeModelItem scope_item, AbstractMetaClass *meta_class, const QStringList &enumsDeclarations) +void AbstractMetaBuilder::traverseEnums(ScopeModelItem scope_item, AbstractMetaClass *meta_class, const QSet &qEnumDeclarations) { EnumList enums = scope_item->enums(); - foreach (EnumModelItem enum_item, enums) { - AbstractMetaEnum *meta_enum = traverseEnum(enum_item, meta_class, QSet::fromList(enumsDeclarations)); + for (EnumModelItem enum_item : enums) { + AbstractMetaEnum* meta_enum = traverseEnum(enum_item, meta_class, qEnumDeclarations); if (meta_enum) { meta_enum->setOriginalAttributes(meta_enum->attributes()); meta_class->addEnum(meta_enum); @@ -1470,6 +1328,25 @@ AbstractMetaFunction *AbstractMetaBuilder::traverseFunction(FunctionModelItem fu return 0; } + // Also filter out functions with template parameters in classes without template arguments + // (we don't support templated classes directly, but derived classes might derive from template instantiations) + if (function_item->templateParameters().size() && m_current_class->templateArguments().empty()) { + return 0; + } + + if (function_item->isAuto()) { + /*TODO: it might work just to output 'auto', but this would require + * understanding what AbstractMetabuild::translateType() does and + * changing it. auto is only used once anyway. + */ + ReportHandler::warning(QString("%1: skipping auto function type '%2'") + .arg(function_name) + .arg(function_item->type().toString())); + m_rejected_functions[class_name + "::" + function_name + " " + function_item->type().toString()] = + UnmatchedReturnType; + return 0; + } + QString cast_type; if (function_name.startsWith("operator")) { @@ -1485,6 +1362,8 @@ AbstractMetaFunction *AbstractMetaBuilder::traverseFunction(FunctionModelItem fu AbstractMetaFunction *meta_function = createMetaFunction(); meta_function->setConstant(function_item->isConstant()); + meta_function->setConstexpr(function_item->isConstexpr()); + meta_function->setAuto(function_item->isAuto()); meta_function->setException(function_item->exception()); ReportHandler::debugMedium(QString(" - %2()").arg(function_name)); @@ -1617,14 +1496,22 @@ AbstractMetaFunction *AbstractMetaBuilder::traverseFunction(FunctionModelItem fu } } - // If we where not able to translate the default argument make it + // If we were not able to translate the default argument make it // reset all default arguments before this one too. - for (int i=0; isetDefaultValueExpression(QString()); + } - if (ReportHandler::debugLevel() == ReportHandler::FullDebug) - foreach(AbstractMetaArgument *arg, meta_arguments) + if (ReportHandler::debugLevel() == ReportHandler::FullDebug) { + for (AbstractMetaArgument *arg : meta_arguments) { ReportHandler::debugFull(" - " + arg->toString()); + } + } + + if (function_item->isDeleted()) { + meta_function->setInvalid(true); + return meta_function; + } return meta_function; } @@ -1662,12 +1549,12 @@ AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, boo } - if (typei.isFunctionPointer()) { + if (typei.isFunctionPointer() || typei.isRvalueReference()) { // function pointers or r-value references are not supported *ok = false; return 0; } - TypeParser::Info typeInfo = TypeParser::parse(typei.toString()); + TypeParser::Info typeInfo = TypeParser::parse(typei.toString(/*parsable=*/true)); if (typeInfo.is_busted) { *ok = false; return 0; @@ -1689,6 +1576,7 @@ AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, boo newInfo.setQualifiedName(typei.qualifiedName()); newInfo.setReference(typei.isReference()); newInfo.setVolatile(typei.isVolatile()); + newInfo.setMutable(typei.isMutable()); AbstractMetaType *elementType = translateType(newInfo, ok); if (!(*ok)) @@ -1751,7 +1639,7 @@ AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, boo // of the parameters. if (type == 0 && m_current_class != 0) { QList template_args = m_current_class->templateArguments(); - foreach (TypeEntry *te, template_args) { + for (TypeEntry *te : template_args) { if (te->name() == qualified_name) type = te; } @@ -1825,7 +1713,7 @@ AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, boo meta_type->setInstantiationInCpp(false); } else { - foreach (const TypeParser::Info &ta, typeInfo.template_instantiations) { + for (const TypeParser::Info &ta : typeInfo.template_instantiations) { TypeInfo info; info.setConstant(ta.is_constant); info.setReference(ta.is_reference); @@ -1944,6 +1832,7 @@ QString AbstractMetaBuilder::translateDefaultValue(ArgumentModelItem item, Abstr AbstractMetaFunction *fnc, AbstractMetaClass *implementing_class, int argument_index) { + Q_UNUSED(type) QString function_name = fnc->name(); QString class_name = implementing_class->name(); @@ -2050,7 +1939,7 @@ bool AbstractMetaBuilder::inheritTemplate(AbstractMetaClass *subclass, QList targs = info.template_instantiations; QList template_types; - foreach (const TypeParser::Info &i, targs) { + for (const TypeParser::Info &i : targs) { TypeEntry *t = TypeDatabase::instance()->findType(i.qualified_name.join("::")); if (t != 0) { @@ -2064,7 +1953,7 @@ bool AbstractMetaBuilder::inheritTemplate(AbstractMetaClass *subclass, } AbstractMetaFunctionList funcs = subclass->functions(); - foreach (const AbstractMetaFunction *function, template_class->functions()) { + for (const AbstractMetaFunction *function : template_class->functions()) { if (function->isModifiedRemoved(TypeSystem::All)) continue; @@ -2080,7 +1969,7 @@ bool AbstractMetaBuilder::inheritTemplate(AbstractMetaClass *subclass, continue; } - foreach (AbstractMetaArgument *argument, function->arguments()) { + for (AbstractMetaArgument *argument : function->arguments()) { AbstractMetaType *atype = argument->type(); AbstractMetaArgument *arg = argument->copy(); @@ -2154,7 +2043,7 @@ bool AbstractMetaBuilder::inheritTemplate(AbstractMetaClass *subclass, } // Clean up - foreach (AbstractMetaType *type, template_types) { + for (AbstractMetaType *type : template_types) { delete type; } @@ -2180,11 +2069,33 @@ void AbstractMetaBuilder::parseQ_Property(AbstractMetaClass *meta_class, const Q QStringList qualifiedScopeName = currentScope()->qualifiedName(); bool ok = false; AbstractMetaType *type = 0; - QString scope; + int pIndex = 0; + QString typeName = l.value(pIndex++); + bool isConst = false; + if (typeName == "const") { + // use the next part as the type name + typeName = l.value(pIndex++); + isConst = true; + } + QString propertyName = l.value(pIndex++); + QString modifiers; + while (typeName.endsWith("*") || typeName.endsWith("&")) { + modifiers.insert(0, typeName.at(typeName.length() - 1)); + typeName.chop(1); + } + while (propertyName.startsWith("*") || propertyName.startsWith("&")) { + modifiers.append(propertyName.at(0)); + propertyName.remove(0, 1); + if (propertyName.isEmpty() && pIndex < l.size()) { + propertyName = l.value(pIndex++); + } + } for (int j=qualifiedScopeName.size(); j>=0; --j) { - scope = j > 0 ? QStringList(qualifiedScopeName.mid(0, j)).join("::") + "::" : QString(); + QStringList scope(qualifiedScopeName.mid(0, j)); TypeInfo info; - info.setQualifiedName((scope + l.at(0)).split("::")); + info.setIndirections(modifiers.count('*')); + info.setReference(modifiers.contains('&')); // r-value reference seems improbable for a property... + info.setQualifiedName(scope + QStringList(typeName)); type = translateType(info, &ok); if (type != 0 && ok) { @@ -2193,18 +2104,16 @@ void AbstractMetaBuilder::parseQ_Property(AbstractMetaClass *meta_class, const Q } if (type == 0 || !ok) { - ReportHandler::warning(QString("Unable to decide type of property: '%1' in class '%2'") - .arg(l.at(0)).arg(meta_class->name())); + ReportHandler::warning(QString("Unable to decide type '%1' of property '%2' in class '%3'") + .arg(typeName).arg(propertyName).arg(meta_class->name())); continue; } - QString typeName = scope + l.at(0); - QPropertySpec *spec = new QPropertySpec(type->typeEntry()); - spec->setName(l.at(1)); + spec->setName(propertyName); spec->setIndex(i); - for (int pos=2; pos+1setRead(l.at(pos+1)); else if (l.at(pos) == QLatin1String("WRITE")) @@ -2221,7 +2130,7 @@ void AbstractMetaBuilder::parseQ_Property(AbstractMetaClass *meta_class, const Q } static void hide_functions(const AbstractMetaFunctionList &l) { - foreach (AbstractMetaFunction *f, l) { + for (AbstractMetaFunction *f : l) { FunctionModification mod; mod.signature = f->minimalSignature(); mod.modifiers = FunctionModification::Private; @@ -2239,7 +2148,7 @@ static void remove_function(AbstractMetaFunction *f) { static AbstractMetaFunctionList filter_functions(const AbstractMetaFunctionList &lst, QSet *signatures) { AbstractMetaFunctionList functions; - foreach (AbstractMetaFunction *f, lst) { + for (AbstractMetaFunction *f : lst) { QString signature = f->minimalSignature(); int start = signature.indexOf(QLatin1Char('(')) + 1; int end = signature.lastIndexOf(QLatin1Char(')')); @@ -2264,7 +2173,7 @@ void AbstractMetaBuilder::setupEquals(AbstractMetaClass *cls) AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::ClassImplements | AbstractMetaClass::NotRemovedFromTargetLang); - foreach (AbstractMetaFunction *f, functions) { + for (AbstractMetaFunction *f : functions) { if (f->name() == op_equals) equals << f; else if (f->name() == op_nequals) @@ -2303,7 +2212,7 @@ void AbstractMetaBuilder::setupComparable(AbstractMetaClass *cls) AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::ClassImplements | AbstractMetaClass::NotRemovedFromTargetLang); - foreach (AbstractMetaFunction *f, functions) { + for (AbstractMetaFunction *f : functions) { if (f->name() == op_greater) greater << f; else if (f->name() == op_greater_eq) @@ -2364,7 +2273,7 @@ void AbstractMetaBuilder::setupClonable(AbstractMetaClass *cls) QString op_assign = QLatin1String("operator_assign"); AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::ClassImplements); - foreach (AbstractMetaFunction *f, functions) { + for (AbstractMetaFunction *f : functions) { if ((f->name() == op_assign || f->isConstructor()) && f->isPublic()) { AbstractMetaArgumentList arguments = f->arguments(); if (arguments.size() == 1) { @@ -2448,55 +2357,112 @@ void AbstractMetaBuilder::dumpLog() AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted() const { - AbstractMetaClassList res; - - AbstractMetaClassList classes = m_meta_classes; - qSort(classes); - - QSet noDependency; - QHash* > hash; - foreach (AbstractMetaClass *cls, classes) { - QSet *depends = new QSet(); + /* This function is the standard topological sort of a Directed Acyclic + * Graph (a DAG). It outputs a partially ordered list of the nodes in the + * graph such that a node is output after all of its children. + * + * In the previous implementation it seemed to account for around 68-69% of + * the entire run time of pythonqt_generator however this might be an + * artefact of the profiling technique used as these changes make not + * significant difference to the run time of the generator. + * + * However the previous implementation also leaked memory and modified a + * QHash while iterating over it with a QHashIterator; a potentially fatal + * "use after free". + * + * This version is somewhat like the python equivalent using list + * comprehensions. + */ + + /* Build a hash list of QSet for each class. 'class' is represented + * by a pointer to the AbstractMetaClass from m_meta_classes. + */ + ReportHandler::debugSparse(QString("TSORT: %1 meta classes") + .arg(m_meta_classes.count())); + QHash> classes; + classes.reserve(m_meta_classes.count()); + + for (auto cls : m_meta_classes) { + /* Add the baseClass and the interfaces the class uses. The latter + * are stored in an AbstractMetaClassList which is uses a QList, so: + */ + auto entry(classes.insert(cls, +# if QT_VERSION < QT_VERSION_CHECK(5,14,0) + QSet::fromList(cls->interfaces()) +# else + QSet(cls->interfaces().cbegin(), + cls->interfaces().cend()) +# endif + )); if (cls->baseClass()) - depends->insert(cls->baseClass()); - - foreach (AbstractMetaClass *interface, cls->interfaces()) { - AbstractMetaClass *impl = interface->primaryInterfaceImplementor(); - if (impl == cls) - continue; - depends->insert(impl); - } - - if (depends->empty()) { - noDependency.insert(cls); - } else { - hash.insert(cls, depends); - } - } - - while (!noDependency.empty()) { - foreach (AbstractMetaClass *cls, noDependency.values()) { - if(!cls->isInterface()) - res.append(cls); - noDependency.remove(cls); - QHashIterator* > i(hash); - while (i.hasNext()) { - i.next(); - i.value()->remove(cls); - if (i.value()->empty()) { - AbstractMetaClass *key = i.key(); - noDependency.insert(key); - hash.remove(key); - delete(i.value()); - } - } - } - } - - if (!noDependency.empty() || !hash.empty()) { - qWarning("dependency graph was cyclic."); - } - - return res; + entry.value().insert(cls->baseClass()); + entry.value().remove(cls); // may come from interfaces + } + + /* This and the qFatals below are fatal internal errors in the code of + * pythonqt_generator. + */ + if (m_meta_classes.count() != classes.count()) + qFatal("TOPO SORT: duplicate meta classes (%lld != %lld)", + static_cast(m_meta_classes.count()), + static_cast(classes.count())); + + /* Loop: output all the classes with no remaining dependencies to the + * result and then also remove those now output classes from the remaining + * classes in the hash table. + */ + AbstractMetaClassList result; + result.reserve(classes.count()); + QSet handled; + handled.reserve(classes.count()); + int interfaceClasses(0), depthFromLeaf(0); + + while (!classes.empty()) { + handled.clear(); + int iFCount(0); + + /* Output classes where all children have already been output (initially + * the leaf nodes): + */ + for (auto i(classes.cbegin()); i != classes.cend(); ++i) + if (i.value().empty()) + handled.insert(i.key()); + + /* Something must have been done; if not this is not a DAG because + * there is a cycle. + */ + if (handled.empty()) + qFatal("TOPOSORT: %lld cyclic meta classes @depth %d.", + static_cast(classes.count()), depthFromLeaf); + + /* Remove all 'handled' from the hash table. */ + for (auto cls : handled) + if (!classes.remove(cls)) + qFatal("TOPO SORT: class remove failed @depth %d.", + depthFromLeaf); + + /* Then remove the 'handled' set from the classes values: */ + for (QSet &set : classes) + set -= handled; + + /* Output only those handled classes there are not interfaces: */ + for (auto cls : handled) { + if (!cls->isInterface()) + result.append(cls); + else + ++iFCount; + } + + ReportHandler::debugSparse( + QString("TSORT: depth %1: %2 classes (%3 interface)") + .arg(depthFromLeaf).arg(handled.count()).arg(iFCount)); + interfaceClasses += iFCount; + ++depthFromLeaf; + } + + ReportHandler::debugSparse(QString( + "TSORT: %1 result classes, %2 interface classes)") + .arg(result.count()).arg(interfaceClasses)); + return result; } diff --git a/generator/abstractmetabuilder.h b/generator/abstractmetabuilder.h index f4c00b11..5fa72da6 100644 --- a/generator/abstractmetabuilder.h +++ b/generator/abstractmetabuilder.h @@ -62,7 +62,7 @@ class AbstractMetaBuilder }; AbstractMetaBuilder(); - virtual ~AbstractMetaBuilder() {}; + virtual ~AbstractMetaBuilder(); AbstractMetaClassList classes() const { return m_meta_classes; } AbstractMetaClassList classesTopologicalSorted() const; @@ -82,9 +82,7 @@ class AbstractMetaBuilder bool build(); - void figureOutEnumValuesForClass(AbstractMetaClass *meta_class, QSet *classes); - int figureOutEnumValue(const QString &name, int value, AbstractMetaEnum *meta_enum, AbstractMetaFunction *meta_function = 0); - void figureOutEnumValues(); + void autoAddQEnumsForClassItem(ClassModelItem item); void addAbstractMetaClass(AbstractMetaClass *cls); AbstractMetaClass *traverseTypeAlias(TypeAliasModelItem item); @@ -92,7 +90,7 @@ class AbstractMetaBuilder bool setupInheritance(AbstractMetaClass *meta_class); AbstractMetaClass *traverseNamespace(NamespaceModelItem item); AbstractMetaEnum *traverseEnum(EnumModelItem item, AbstractMetaClass *enclosing, const QSet &enumsDeclarations); - void traverseEnums(ScopeModelItem item, AbstractMetaClass *parent, const QStringList &enumsDeclarations); + void traverseEnums(ScopeModelItem item, AbstractMetaClass *parent, const QSet &enumsDeclarations); void traverseFunctions(ScopeModelItem item, AbstractMetaClass *parent); void traverseFields(ScopeModelItem item, AbstractMetaClass *parent); void traverseStreamOperator(FunctionModelItem function_item); @@ -127,7 +125,7 @@ class AbstractMetaBuilder bool isEnum(const QStringList &qualified_name); void fixQObjectForScope (TypeDatabase *types, - NamespaceModelItem item); + NamespaceModelItem item); // QtScript QSet qtMetaTypeDeclaredTypeNames() const @@ -150,7 +148,7 @@ class AbstractMetaBuilder QString m_file_name; AbstractMetaClassList m_meta_classes; - AbstractMetaClassList m_templates; + QHash m_templates; FileModelItem m_dom; QSet m_used_types; diff --git a/generator/abstractmetalang.cpp b/generator/abstractmetalang.cpp index 41d1b56b..67fc4d2a 100644 --- a/generator/abstractmetalang.cpp +++ b/generator/abstractmetalang.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include // for std::stable_sort + #include "abstractmetalang.h" #include "reporthandler.h" @@ -53,7 +55,7 @@ AbstractMetaType *AbstractMetaType::copy() const cpy->setConstant(isConstant()); cpy->setReference(isReference()); cpy->setIndirections(indirections()); - cpy->setInstantiations(instantiations()); + cpy->setInstantiations(instantiations()); cpy->setArrayElementCount(arrayElementCount()); cpy->setOriginalTypeDescription(originalTypeDescription()); cpy->setOriginalTemplateType(originalTemplateType() ? originalTemplateType()->copy() : 0); @@ -313,6 +315,8 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const if (type()) cpy->setType(type()->copy()); cpy->setConstant(isConstant()); + cpy->setConstexpr(isConstexpr()); + cpy->setAuto(isAuto()); cpy->setException(exception()); cpy->setOriginalAttributes(originalAttributes()); @@ -840,17 +844,17 @@ AbstractMetaFunctionList AbstractMetaClass::queryFunctionsByName(const QString & QString AbstractMetaClass::getDefaultNonZeroFunction() const { - foreach(const AbstractMetaFunction* fun, queryFunctionsByName("isEmpty")) { + for (const AbstractMetaFunction* fun : queryFunctionsByName("isEmpty")) { if (fun->actualMinimumArgumentCount()==0 && fun->isPublic()) { return "isEmpty"; } } - foreach(const AbstractMetaFunction* fun, queryFunctionsByName("isValid")) { + for (const AbstractMetaFunction* fun : queryFunctionsByName("isValid")) { if (fun->actualMinimumArgumentCount() == 0 && fun->isPublic()) { return "isValid"; } } - foreach(const AbstractMetaFunction* fun, queryFunctionsByName("isNull")) { + for (const AbstractMetaFunction* fun : queryFunctionsByName("isNull")) { if (fun->actualMinimumArgumentCount() == 0 && fun->isPublic()) { return "isNull"; } @@ -972,7 +976,7 @@ AbstractMetaFunctionList AbstractMetaClass::virtualOverrideFunctions() const void AbstractMetaClass::sortFunctions() { - qSort(m_functions.begin(), m_functions.end(), function_sorter); + std::sort(m_functions.begin(), m_functions.end(), function_sorter); } void AbstractMetaClass::setFunctions(const AbstractMetaFunctionList &functions) @@ -1090,7 +1094,7 @@ void AbstractMetaClass::addFunction(AbstractMetaFunction *function) if (!function->isDestructor()) { m_functions << function; // seems like this is not needed and takes a lot of performance - //qSort(m_functions.begin(), m_functions.end(), function_sorter); + //std::sort(m_functions.begin(), m_functions.end(), function_sorter); } @@ -1173,21 +1177,34 @@ QPropertySpec *AbstractMetaClass::propertySpecForReset(const QString &name) cons return 0; } +bool AbstractMetaClass::hasVirtualDestructor() const +{ + if (m_has_virtual_destructor) { + return true; + } + else { + // check all super classes + for (int i = 0; i < m_super_classes.size(); ++i) { + AbstractMetaClass* super_class = m_super_classes.at(i); + if (super_class->hasVirtualDestructor()) { + return true; + } + } + } + return false; +} + static bool functions_contains(const AbstractMetaFunctionList &l, const AbstractMetaFunction *func) { foreach (const AbstractMetaFunction *f, l) { - if ((f->compareTo(func) & AbstractMetaFunction::PrettySimilar) == AbstractMetaFunction::PrettySimilar) + 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; @@ -1205,13 +1222,13 @@ AbstractMetaField *AbstractMetaField::copy() const return returned; } - +/* UNUSED 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, uint type) { AbstractMetaFunction *f = new AbstractMetaFunction; @@ -1623,20 +1640,21 @@ void AbstractMetaClass::fixFunctions() AbstractMetaClass *super_class = baseClass(); AbstractMetaFunctionList funcs = functions(); + AbstractMetaClassList interfaceClasses = interfaces(); // printf("fix functions for %s\n", qPrintable(name())); if (super_class != 0) super_class->fixFunctions(); int iface_idx = 0; - while (super_class || iface_idx < interfaces().size()) { -// printf(" - base: %s\n", qPrintable(super_class->name())); + while (super_class || iface_idx < interfaceClasses.size()) { // Since we always traverse the complete hierarchy we are only // interested in what each super class implements, not what // we may have propagated from their base classes again. AbstractMetaFunctionList super_funcs; if (super_class) { +// printf(" - base: %s\n", qPrintable(super_class->name())); // Super classes can never be final if (super_class->isFinalInTargetLang()) { @@ -1645,7 +1663,10 @@ void AbstractMetaClass::fixFunctions() } super_funcs = super_class->queryFunctions(AbstractMetaClass::ClassImplements); } else { - super_funcs = interfaces().at(iface_idx)->queryFunctions(AbstractMetaClass::NormalFunctions); + AbstractMetaClass *iface_class = interfaceClasses.at(iface_idx); +// printf(" - iface: %s\n", qPrintable(iface_class->name())); + iface_class->fixFunctions(); + super_funcs = iface_class->queryFunctions(AbstractMetaClass::NormalFunctions); } QSet funcs_to_add; @@ -1802,12 +1823,16 @@ void AbstractMetaClass::fixFunctions() foreach (AbstractMetaFunction *f, funcs_to_add) funcs << f->copy(); - if (super_class) + if (super_class) { + interfaceClasses += super_class->interfaces(); super_class = super_class->baseClass(); - else + } else { iface_idx++; + } } +// printf("end fix functions for %s\n", qPrintable(name())); + bool hasPrivateConstructors = false; bool hasPublicConstructors = false; foreach (AbstractMetaFunction *func, funcs) { @@ -1994,3 +2019,9 @@ AbstractMetaClass *AbstractMetaClassList::findClass(const QString &name) const return 0; } + + +void AbstractMetaClassList::sort(void) +{ + std::stable_sort(begin(), end(), AbstractMetaClass::less_than); +} diff --git a/generator/abstractmetalang.h b/generator/abstractmetalang.h index d1b93756..f161c5c7 100644 --- a/generator/abstractmetalang.h +++ b/generator/abstractmetalang.h @@ -71,6 +71,7 @@ class AbstractMetaClassList : public QList AbstractMetaClass *findClass(const QString &name) const; AbstractMetaEnumValue *findEnumValue(const QString &string) const; AbstractMetaEnum *findEnum(const EnumTypeEntry *entry) const; + void sort(); }; @@ -79,7 +80,7 @@ class AbstractMetaClassList : public QList class AbstractMetaAttributes { public: - AbstractMetaAttributes() : m_attributes(0) { }; + AbstractMetaAttributes() = default; enum Attribute { None = 0x00000000, @@ -153,8 +154,8 @@ class AbstractMetaAttributes bool wasFriendly() const { return m_originalAttributes & Friendly; } private: - uint m_attributes; - uint m_originalAttributes; + uint m_attributes{}; + uint m_originalAttributes{}; }; @@ -180,11 +181,6 @@ class AbstractMetaType }; AbstractMetaType() : - m_type_entry(0), - m_array_element_count(0), - m_array_element_type(0), - m_original_template_type(0), - m_pattern(InvalidPattern), m_constant(false), m_reference(false), m_cpp_instantiation(true), @@ -203,7 +199,7 @@ class AbstractMetaType // true when use pattern is container bool hasInstantiations() const { return !m_instantiations.isEmpty(); } void addInstantiation(AbstractMetaType *inst) { m_instantiations << inst; } - void setInstantiations(const QList &insts) { m_instantiations = insts; } + void setInstantiations(const QList &insts) { m_instantiations = insts; } QList instantiations() const { return m_instantiations; } void setInstantiationInCpp(bool incpp) { m_cpp_instantiation = incpp; } bool hasInstantiationInCpp() const { return hasInstantiations() && m_cpp_instantiation; } @@ -294,16 +290,16 @@ class AbstractMetaType const AbstractMetaType *originalTemplateType() const { return m_original_template_type; } private: - const TypeEntry *m_type_entry; + const TypeEntry *m_type_entry{}; QList m_instantiations; QString m_package; QString m_original_type_description; - int m_array_element_count; - AbstractMetaType *m_array_element_type; - const AbstractMetaType *m_original_template_type; + int m_array_element_count{}; + AbstractMetaType *m_array_element_type{}; + const AbstractMetaType *m_original_template_type{}; - TypeUsagePattern m_pattern; + TypeUsagePattern m_pattern{InvalidPattern}; uint m_constant : 1; uint m_reference : 1; uint m_cpp_instantiation : 1; @@ -314,7 +310,7 @@ class AbstractMetaType class AbstractMetaVariable { public: - AbstractMetaVariable() : m_type(0) { } + AbstractMetaVariable() = default; AbstractMetaType *type() const { return m_type; } void setType(AbstractMetaType *type) { m_type = type; } @@ -324,7 +320,7 @@ class AbstractMetaVariable private: QString m_name; - AbstractMetaType *m_type; + AbstractMetaType *m_type{}; }; @@ -332,7 +328,7 @@ class AbstractMetaVariable class AbstractMetaArgument : public AbstractMetaVariable { public: - AbstractMetaArgument() : m_argument_index(0) { }; + AbstractMetaArgument() = default; QString defaultValueExpression() const { return m_expression; } void setDefaultValueExpression(const QString &expr) { m_expression = expr; } @@ -357,14 +353,14 @@ class AbstractMetaArgument : public AbstractMetaVariable QString m_expression; QString m_original_expression; - int m_argument_index; + int m_argument_index{}; }; class AbstractMetaField : public AbstractMetaVariable, public AbstractMetaAttributes { public: - AbstractMetaField(); + AbstractMetaField() = default; ~AbstractMetaField(); const AbstractMetaClass *enclosingClass() const { return m_class; } @@ -378,9 +374,9 @@ class AbstractMetaField : public AbstractMetaVariable, public AbstractMetaAttrib AbstractMetaField *copy() const; private: - mutable AbstractMetaFunction *m_getter; - mutable AbstractMetaFunction *m_setter; - const AbstractMetaClass *m_class; + mutable AbstractMetaFunction *m_getter{}; + mutable AbstractMetaFunction *m_setter{}; + const AbstractMetaClass *m_class{}; }; @@ -413,15 +409,9 @@ class AbstractMetaFunction : public AbstractMetaAttributes NotEqual = 0x00001000 }; - AbstractMetaFunction() - : m_function_type(NormalFunction), - m_type(0), - m_class(0), - m_implementing_class(0), - m_declaring_class(0), - m_interface_class(0), - m_property_spec(0), + AbstractMetaFunction() : m_constant(false), + m_constexpr(false), m_invalid(false) { } @@ -499,6 +489,12 @@ class AbstractMetaFunction : public AbstractMetaAttributes bool isConstant() const { return m_constant; } void setConstant(bool constant) { m_constant = constant; } + bool isConstexpr() const { return m_constexpr; } + void setConstexpr(bool constant) { m_constexpr = constant; } + + bool isAuto() const { return m_auto; } + void setAuto(bool isAuto) { m_auto = isAuto; } + QString exception() const { return m_exception; } void setException(const QString &exception) { m_exception = exception; } QString toString() const { return m_name; } @@ -552,16 +548,18 @@ class AbstractMetaFunction : public AbstractMetaAttributes mutable QString m_cached_minimal_signature; mutable QString m_cached_modified_name; - FunctionType m_function_type; - AbstractMetaType *m_type; - const AbstractMetaClass *m_class; - const AbstractMetaClass *m_implementing_class; - const AbstractMetaClass *m_declaring_class; - const AbstractMetaClass *m_interface_class; - QPropertySpec *m_property_spec; + FunctionType m_function_type{NormalFunction}; + AbstractMetaType *m_type{}; + const AbstractMetaClass *m_class{}; + const AbstractMetaClass *m_implementing_class{}; + const AbstractMetaClass *m_declaring_class{}; + const AbstractMetaClass *m_interface_class{}; + QPropertySpec *m_property_spec{}; AbstractMetaArgumentList m_arguments; QString m_exception; uint m_constant : 1; + uint m_constexpr : 1; + uint m_auto : 1; uint m_invalid : 1; }; @@ -569,10 +567,7 @@ class AbstractMetaFunction : public AbstractMetaAttributes class AbstractMetaEnumValue { public: - AbstractMetaEnumValue() - : m_value_set(false), m_value(0) - { - } + AbstractMetaEnumValue() = default; int value() const { return m_value; } void setValue(int value) { m_value_set = true; m_value = value; } @@ -589,8 +584,8 @@ class AbstractMetaEnumValue QString m_name; QString m_string_value; - bool m_value_set; - int m_value; + bool m_value_set{}; + int m_value{}; }; @@ -603,7 +598,7 @@ class AbstractMetaEnumValueList : public QList class AbstractMetaEnum : public AbstractMetaAttributes { public: - AbstractMetaEnum() : m_type_entry(0), m_class(0), m_has_qenums_declaration(false) {} + AbstractMetaEnum() : m_has_qenums_declaration(false) {} AbstractMetaEnumValueList values() const { return m_enum_values; } void addEnumValue(AbstractMetaEnumValue *enumValue) { m_enum_values << enumValue; } @@ -625,8 +620,8 @@ class AbstractMetaEnum : public AbstractMetaAttributes private: AbstractMetaEnumValueList m_enum_values; - EnumTypeEntry *m_type_entry; - AbstractMetaClass *m_class; + EnumTypeEntry *m_type_entry{}; + AbstractMetaClass *m_class{}; uint m_has_qenums_declaration : 1; uint m_reserved : 31; @@ -674,17 +669,13 @@ class AbstractMetaClass : public AbstractMetaAttributes m_has_nonprivateconstructor(false), m_functions_fixed(false), m_has_public_destructor(true), + m_has_virtual_destructor(false), m_force_shell_class(false), m_has_hash_function(false), m_has_equals_operator(false), m_has_clone_operator(false), m_is_type_alias(false), - m_enclosing_class(0), - m_base_class(0), - m_template_base_class(0), - m_extracted_interface(0), - m_primary_interface_implementor(0), - m_type_entry(0), + m_has_actual_declaration(false), m_qDebug_stream_function(0) { } @@ -709,6 +700,8 @@ class AbstractMetaClass : public AbstractMetaAttributes void setHasNonPrivateConstructor(bool on) { m_has_nonprivateconstructor = on; } bool hasPublicDestructor() const { return m_has_public_destructor; } void setHasPublicDestructor(bool on) { m_has_public_destructor = on; } + bool hasVirtualDestructor() const; + void setHasVirtualDestructor(bool on) { m_has_virtual_destructor = on; } QString destructorException() const { return m_destructor_exception; } void setDestructorException(const QString &exception) { m_destructor_exception = exception; } @@ -749,6 +742,10 @@ class AbstractMetaClass : public AbstractMetaAttributes AbstractMetaClass *baseClass() const { return m_base_class; } void setBaseClass(AbstractMetaClass *base_class) { m_base_class = base_class; } + // this lists _all_ super classes of this class + QList superClasses() const { return m_super_classes; } + void addSuperClass(AbstractMetaClass *super_class) { m_super_classes.append(super_class); } + const AbstractMetaClass *enclosingClass() const { return m_enclosing_class; } void setEnclosingClass(AbstractMetaClass *cl) { m_enclosing_class = cl; } @@ -800,6 +797,9 @@ class AbstractMetaClass : public AbstractMetaAttributes void setHasCloneOperator(bool on) { m_has_clone_operator = on; } bool hasCloneOperator() const { return m_has_clone_operator; } + void setHasActualDeclaration(bool on) { m_has_actual_declaration = on; } + bool hasActualDeclaration() const { return m_has_actual_declaration; } + QString getDefaultNonZeroFunction() const; void addPropertySpec(QPropertySpec *spec) { m_property_specs << spec; } @@ -840,6 +840,11 @@ class AbstractMetaClass : public AbstractMetaAttributes return qualifiedCppName() < a.qualifiedCppName(); } + static bool less_than(const AbstractMetaClass *cl, + const AbstractMetaClass *cr) { + return cl->name() < cr->name(); + } + private: uint m_namespace : 1; uint m_qobject : 1; @@ -849,23 +854,26 @@ class AbstractMetaClass : public AbstractMetaAttributes uint m_has_nonprivateconstructor : 1; uint m_functions_fixed : 1; uint m_has_public_destructor : 1; + uint m_has_virtual_destructor : 1; uint m_force_shell_class : 1; uint m_has_hash_function : 1; uint m_has_equals_operator : 1; uint m_has_clone_operator :1; uint m_is_type_alias : 1; - uint m_reserved : 19; + uint m_has_actual_declaration : 1; + uint m_reserved : 17; QString m_destructor_exception; - const AbstractMetaClass *m_enclosing_class; - AbstractMetaClass *m_base_class; - const AbstractMetaClass *m_template_base_class; + const AbstractMetaClass *m_enclosing_class{}; + AbstractMetaClass *m_base_class{}; + QList m_super_classes; + const AbstractMetaClass *m_template_base_class{}; AbstractMetaFunctionList m_functions; AbstractMetaFieldList m_fields; AbstractMetaEnumList m_enums; AbstractMetaClassList m_interfaces; - AbstractMetaClass *m_extracted_interface; - AbstractMetaClass *m_primary_interface_implementor; + AbstractMetaClass *m_extracted_interface{}; + AbstractMetaClass *m_primary_interface_implementor{}; QList m_property_specs; AbstractMetaFunctionList m_equals_functions; AbstractMetaFunctionList m_nequals_functions; @@ -877,7 +885,7 @@ class AbstractMetaClass : public AbstractMetaAttributes QStringList m_base_class_names; QList m_template_args; - ComplexTypeEntry *m_type_entry; + ComplexTypeEntry *m_type_entry{}; FunctionModelItem m_qDebug_stream_function; }; @@ -915,8 +923,8 @@ class QPropertySpec { QString m_write; QString m_designable; QString m_reset; - const TypeEntry *m_type; - int m_index; + const TypeEntry *m_type{}; + int m_index{-1}; }; inline AbstractMetaFunctionList AbstractMetaClass::allVirtualFunctions() const diff --git a/generator/asttoxml.cpp b/generator/asttoxml.cpp index 0c351ac7..eb3913b8 100644 --- a/generator/asttoxml.cpp +++ b/generator/asttoxml.cpp @@ -47,7 +47,9 @@ #include #include -#include +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) +# include +#endif #include void astToXML(QString name) { @@ -57,7 +59,18 @@ void astToXML(QString name) { return; QTextStream stream(&file); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) stream.setCodec(QTextCodec::codecForName("UTF-8")); +#else + /* NOTE, for Qt6: + * + * stream.setEncoding(QStringConverter::Utf8) + * + * is the default but will be overridden if the UTF-16 BOM is seen. This + * is almost certainly the correct behavior because the BOM isn't valid in + * a text stream otherwise. + */ +#endif QByteArray contents = stream.readAll().toUtf8(); file.close(); @@ -73,9 +86,9 @@ void astToXML(QString name) { QFile outputFile; if (!outputFile.open(stdout, QIODevice::WriteOnly)) - { - return; - } + { + return; + } QXmlStreamWriter s( &outputFile); s.setAutoFormatting( true ); @@ -83,12 +96,12 @@ void astToXML(QString name) { s.writeStartElement("code"); QHash namespaceMap = dom->namespaceMap(); - foreach (NamespaceModelItem item, namespaceMap.values()) { + for (NamespaceModelItem item : namespaceMap.values()) { writeOutNamespace(s, item); } QHash typeMap = dom->classMap(); - foreach (ClassModelItem item, typeMap.values()) { + for (ClassModelItem item : typeMap.values()) { writeOutClass(s, item); } s.writeEndElement(); @@ -100,17 +113,17 @@ void writeOutNamespace(QXmlStreamWriter &s, NamespaceModelItem &item) { s.writeAttribute("name", item->name()); QHash namespaceMap = item->namespaceMap(); - foreach (NamespaceModelItem namespaceItem, namespaceMap.values()) { + for (NamespaceModelItem namespaceItem : namespaceMap.values()) { writeOutNamespace(s, namespaceItem); } QHash typeMap = item->classMap(); - foreach (ClassModelItem classItem, typeMap.values()) { + for (ClassModelItem classItem : typeMap.values()) { writeOutClass(s, classItem); } QHash enumMap = item->enumMap(); - foreach (EnumModelItem enumItem, enumMap.values()) { + for (EnumModelItem enumItem : enumMap.values()) { writeOutEnum(s, enumItem); } @@ -160,17 +173,17 @@ void writeOutClass(QXmlStreamWriter &s, ClassModelItem &item) { s.writeAttribute("name", qualified_name); QHash enumMap = item->enumMap(); - foreach (EnumModelItem enumItem, enumMap.values()) { + for (EnumModelItem enumItem : enumMap.values()) { writeOutEnum(s, enumItem); } - QHash functionMap = item->functionMap(); - foreach (FunctionModelItem funcItem, functionMap.values()) { + QMultiHash functionMap = item->functionMap(); + for (FunctionModelItem funcItem : functionMap.values()) { writeOutFunction(s, funcItem); } QHash typeMap = item->classMap(); - foreach (ClassModelItem classItem, typeMap.values()) { + for (ClassModelItem classItem : typeMap.values()) { writeOutClass(s, classItem); } s.writeEndElement(); diff --git a/generator/generator.cpp b/generator/generator.cpp index d170726d..0babb905 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp @@ -42,7 +42,6 @@ #include "generator.h" #include "reporthandler.h" #include "fileout.h" - #include #include #include @@ -62,7 +61,7 @@ void Generator::generate() return; } - qStableSort(m_classes); + m_classes.sort(); foreach (AbstractMetaClass *cls, m_classes) { if (!shouldGenerate(cls)) @@ -86,7 +85,7 @@ void Generator::printClasses() QTextStream s(stdout); AbstractMetaClassList classes = m_classes; - qSort(classes); + classes.sort(); foreach (AbstractMetaClass *cls, classes) { if (!shouldGenerate(cls)) diff --git a/generator/generator.h b/generator/generator.h index dfb342e8..84205b17 100644 --- a/generator/generator.h +++ b/generator/generator.h @@ -42,10 +42,7 @@ #ifndef GENERATOR_H #define GENERATOR_H -#include "metajava.h" -#include "typesystem.h" - -#include "codemodel.h" +#include "abstractmetalang.h" #include #include @@ -54,10 +51,10 @@ class Generator : public QObject { Q_OBJECT - Q_PROPERTY(QString outputDirectory READ outputDirectory WRITE setOutputDirectory); + Q_PROPERTY(QString outputDirectory READ outputDirectory WRITE setOutputDirectory) public: - enum Option { + enum Option:uint32_t { NoOption = 0x00000000, BoxedPrimitive = 0x00000001, ExcludeConst = 0x00000002, @@ -120,6 +117,8 @@ class Generator : public QObject { return m_qmetatype_declared_typenames; } protected: + + void verifyDirectoryFor(const QFile &file); AbstractMetaClassList m_classes; diff --git a/generator/generator.pri b/generator/generator.pri index c8a651a0..490e265c 100644 --- a/generator/generator.pri +++ b/generator/generator.pri @@ -2,25 +2,35 @@ isEmpty(GENERATORPATH):GENERATORPATH = $$PWD INCLUDEPATH += $$GENERATORPATH TEMPLATE = app +#CONFIG += cmdline -- does not work as expected with old Qt versions, f.e. is missing in 5.9 +CONFIG += console +CONFIG -= app_bundle + TARGET += DEPENDPATH += $$GENERATORPATH tests parser -mac:CONFIG -= app_bundle INCLUDEPATH += $$GENERATORPATH/. INCLUDEPATH += $$GENERATORPATH/../common -unix:CONFIG += debug_and_release - -CONFIG += console RESOURCES += generator.qrc include($$GENERATORPATH/parser/rxx.pri) include($$GENERATORPATH/parser/rpp/rpp.pri) -win32-msvc2005:{ +CONFIG += strict_c++ +win32-msvc*{ +#Disable warning C4996 (deprecated declarations) QMAKE_CXXFLAGS += -wd4996 QMAKE_CFLAGS += -wd4996 +#Disable warnings for external headers + greaterThan(QMAKE_MSC_VER, 1599):QMAKE_CXXFLAGS += -external:anglebrackets -external:W0 -external:templates- } +#Do not issue warning to Qt's system includes +gcc:!isEmpty(QT_INSTALL_HEADERS): QMAKE_CXXFLAGS += -isystem $$[QT_INSTALL_HEADERS] +gcc|win32-clang-msvc:QMAKE_CXXFLAGS += -Wno-deprecated-declarations -pedantic -Winit-self -Wuninitialized +clang|win32-clang-msvc: QMAKE_CXXFLAGS += -Wno-nested-anon-types -Wno-gnu-anonymous-struct -Wno-unused-private-field +win32-clang-msvc:QMAKE_CXXFLAGS += -Wno-language-extension-token -Wno-microsoft-enum-value + # Input HEADERS += \ @@ -58,7 +68,12 @@ SOURCES += \ -QT = core xml +QT += core xml + +greaterThan(QT_MAJOR_VERSION, 5) { + QT += core5compat + message("WARNING: Qt module core5compat for XML handling in typesystem.cpp") +} win32-msvc.net { QMAKE_CXXFLAGS += /Zm500 diff --git a/generator/generator.pro b/generator/generator.pro index 9e2ae506..c159e23b 100644 --- a/generator/generator.pro +++ b/generator/generator.pro @@ -1,10 +1,8 @@ TARGET = pythonqt_generator -CONFIG -= debug -CONFIG += release DESTDIR = . include(generator.pri) - +DEFINES += QT_NO_CAST_TO_ASCII # Input HEADERS += \ diff --git a/generator/generatorsetqtscript.cpp b/generator/generatorsetqtscript.cpp index abedf346..e9655646 100644 --- a/generator/generatorsetqtscript.cpp +++ b/generator/generatorsetqtscript.cpp @@ -55,11 +55,22 @@ QString GeneratorSetQtScript::usage() { QString usage = "QtScript:\n" " --nothing-to-report-yet \n"; + " --max-classes-per-file= \n"; return usage; } bool GeneratorSetQtScript::readParameters(const QMap args) { + if (args.contains("max-classes-per-file")) { + bool ok; + int n = args.value("max-classes-per-file").toInt(&ok); + if (ok && n > 0) { + maxClassesPerFile = n; + } + else { + printf("Invalid value for option --max-classes-per-file (must be number > 0)\n"); + } + } return GeneratorSet::readParameters(args); } @@ -78,10 +89,10 @@ QString GeneratorSetQtScript::generate() { AbstractMetaClassList classes = builder.classesTopologicalSorted(); QSet declaredTypeNames = builder.qtMetaTypeDeclaredTypeNames(); - PriGenerator priGenerator; + PriGenerator priGenerator(maxClassesPerFile); priGenerator.setOutputDirectory(outDir); - SetupGenerator setupGenerator; + SetupGenerator setupGenerator(maxClassesPerFile); setupGenerator.setOutputDirectory(outDir); setupGenerator.setQtMetaTypeDeclaredTypeNames(declaredTypeNames); setupGenerator.setClasses(classes); @@ -102,10 +113,10 @@ QString GeneratorSetQtScript::generate() { return QString("Classes in typesystem: %1\n" "Generated:\n" - " - header....: %4 (%5)\n" - " - impl......: %6 (%7)\n" - " - modules...: %8 (%9)\n" - " - pri.......: %10 (%11)\n" + " - header....: %2 (%3)\n" + " - impl......: %4 (%5)\n" + " - modules...: %6 (%7)\n" + " - pri.......: %8 (%9)\n" ) .arg(builder.classes().size()) diff --git a/generator/generatorsetqtscript.h b/generator/generatorsetqtscript.h index 55795e48..06d83690 100644 --- a/generator/generatorsetqtscript.h +++ b/generator/generatorsetqtscript.h @@ -62,6 +62,7 @@ class GeneratorSetQtScript : public GeneratorSet private: MetaQtScriptBuilder builder; + int maxClassesPerFile{30}; }; diff --git a/generator/main.cpp b/generator/main.cpp index 9961665f..e438bcd9 100644 --- a/generator/main.cpp +++ b/generator/main.cpp @@ -39,21 +39,62 @@ ** ****************************************************************************/ +#include + #include "main.h" #include "asttoxml.h" #include "reporthandler.h" #include "typesystem.h" #include "generatorset.h" #include "fileout.h" +#include "control.h" #include +#include +#include +#include +#include void displayHelp(GeneratorSet *generatorSet); +static unsigned int getQtVersion(const QString& commandLineIncludes) +{ + QRegularExpression re("#define\\s+QTCORE_VERSION\\s+0x([0-9a-f]+)", QRegularExpression::CaseInsensitiveOption); + for (const QString& includeDir : Preprocess::getIncludeDirectories(commandLineIncludes)) { + QFileInfo fi(QDir(includeDir), "qtcoreversion.h"); + if (fi.exists()) { + QString filePath = fi.absoluteFilePath(); + QFile f(filePath); + if (f.open(QIODevice::ReadOnly)) { + QTextStream ts(&f); + QString content = ts.readAll(); + f.close(); + auto match = re.match(content); + if (match.isValid()) { + unsigned int result; + bool ok; + result = match.captured(1).toUInt(&ok, 16); + if (!ok) { + printf("Could not parse Qt version in file [%s] (looked for #define QTCORE_VERSION)\n", + qPrintable(filePath)); + } + return result; + } + } + } + } + printf("Error: Could not find Qt version (looked for qtcoreversion.h in %s)\n", + qPrintable(commandLineIncludes)); + return 0; +} + + #include int main(int argc, char *argv[]) { - GeneratorSet *gs = GeneratorSet::getInstance(); + ReportHandler::setContext("Arguments"); + + QScopedPointer gs(GeneratorSet::getInstance()); QString default_file = ":/trolltech/generator/qtscript_masterinclude.h"; QString default_system = ":/trolltech/generator/build_all.txt"; @@ -64,6 +105,7 @@ int main(int argc, char *argv[]) QStringList rebuild_classes; QMap args; + unsigned int qtVersion{}; int argNum = 0; for (int i=1; isetRebuildClasses(classes); } + if (args.contains("qt-version")) { + bool ok; + qtVersion = TypeSystem::qtVersionFromString(args.value("qt-version"), ok); + if (!ok || qtVersion < 0x050000) { + printf("Invalid Qt version specified, will look into header files for version...\n"); + qtVersion = 0; + } + } + fileName = args.value("arg-1"); typesystemFileName = args.value("arg-2"); if (args.contains("arg-3")) - displayHelp(gs); + displayHelp(&*gs); if (fileName.isEmpty()) fileName = default_file; @@ -127,19 +182,33 @@ int main(int argc, char *argv[]) typesystemFileName = default_system; if (fileName.isEmpty() || typesystemFileName.isEmpty() ) - displayHelp(gs); + displayHelp(&*gs); if (!gs->readParameters(args)) - displayHelp(gs); + displayHelp(&*gs); printf("Please wait while source files are being generated...\n"); + if (!qtVersion) { + printf("Trying to determine Qt version...\n"); + qtVersion = getQtVersion(args.value("include-paths")); + if (!qtVersion) + { + fprintf(stderr, "Aborting\n"); // the error message was printed by getQtVersion + return 1; + } + printf("Determined Qt version is %d.%d.%d\n", qtVersion >> 16, (qtVersion >> 8) & 0xFF, qtVersion & 0xFF); + } + printf("Parsing typesystem file [%s]\n", qPrintable(typesystemFileName)); - if (!TypeDatabase::instance()->parseFile(typesystemFileName)) + fflush(stdout); + ReportHandler::setContext("Typesystem"); + if (!TypeDatabase::instance()->parseFile(typesystemFileName, qtVersion)) qFatal("Cannot parse file: '%s'", qPrintable(typesystemFileName)); printf("PreProcessing - Generate [%s] using [%s] and include-paths [%s]\n", qPrintable(pp_file), qPrintable(fileName), qPrintable(args.value("include-paths"))); + ReportHandler::setContext("Preprocess"); if (!Preprocess::preprocess(fileName, pp_file, args.value("include-paths"))) { fprintf(stderr, "Preprocessor failed on file: '%s'\n", qPrintable(fileName)); return 1; @@ -148,16 +217,19 @@ int main(int argc, char *argv[]) if (args.contains("ast-to-xml")) { printf("Running ast-to-xml on file [%s] using pp_file [%s] and include-paths [%s]\n", qPrintable(fileName), qPrintable(pp_file), qPrintable(args.value("include-paths"))); + ReportHandler::setContext(QString("AST-to-XML")); astToXML(pp_file); return 0; } printf("Building model using [%s]\n", qPrintable(pp_file)); + ReportHandler::setContext("Build"); gs->buildModel(pp_file); if (args.contains("dump-object-tree")) { gs->dumpObjectTree(); return 0; } + ReportHandler::setContext("Generate"); printf("%s\n", qPrintable(gs->generate())); printf("Done, %d warnings (%d known issues)\n", ReportHandler::warningCount(), @@ -175,11 +247,13 @@ void displayHelp(GeneratorSet* generatorSet) { printf("Available options:\n\n"); printf("General:\n"); printf(" --debug-level=[sparse|medium|full] \n" + " --print-parser-errors \n" " --dump-object-tree \n" " --help, -h or -? \n" " --no-suppress-warnings \n" " --output-directory=[dir] \n" " --include-paths=[%c%c...] \n" + " --qt-version=x.y.z \n" " --print-stdout \n", path_splitter, path_splitter); diff --git a/generator/main.h b/generator/main.h index 15fc6dc1..388e9250 100644 --- a/generator/main.h +++ b/generator/main.h @@ -49,25 +49,9 @@ struct Preprocess { - static bool preprocess(const QString &sourceFile, const QString &targetFile, const QString &commandLineIncludes = QString()) - { - rpp::pp_environment env; - rpp::pp preprocess(env); - - rpp::pp_null_output_iterator null_out; - - const char *ppconfig = ":/trolltech/generator/parser/rpp/pp-qt-configuration"; - - QFile file(ppconfig); - if (!file.open(QFile::ReadOnly)) { - fprintf(stderr, "Preprocessor configuration file not found '%s'\n", ppconfig); - return false; - } - - QByteArray ba = file.readAll(); - file.close(); - preprocess.operator() (ba.constData(), ba.constData() + ba.size(), null_out); + static QStringList getIncludeDirectories(const QString& commandLineIncludes) + { QStringList includes; includes << QString("."); @@ -113,7 +97,29 @@ struct Preprocess includes << (qtdir + "/QtOpenGL"); includes << qtdir; } - foreach (QString include, includes) { + return includes; + } + + static bool preprocess(const QString &sourceFile, const QString &targetFile, const QString &commandLineIncludes = QString()) + { + rpp::pp_environment env; + rpp::pp preprocess(env); + + rpp::pp_null_output_iterator null_out; + + const char *ppconfig = ":/trolltech/generator/parser/rpp/pp-qt-configuration"; + + QFile file(ppconfig); + if (!file.open(QFile::ReadOnly)) { + fprintf(stderr, "Preprocessor configuration file not found '%s'\n", ppconfig); + return false; + } + + QByteArray ba = file.readAll(); + file.close(); + preprocess.operator() (ba.constData(), ba.constData() + ba.size(), null_out); + + foreach (QString include, getIncludeDirectories(commandLineIncludes)) { preprocess.push_include_path(QDir::toNativeSeparators(include).toStdString()); } diff --git a/generator/parser/ast.cpp b/generator/parser/ast.cpp index 55357304..6e89ab0a 100644 --- a/generator/parser/ast.cpp +++ b/generator/parser/ast.cpp @@ -48,5 +48,5 @@ QString AST::toString(TokenStream *stream) const { const Token &tk = stream->token((int) start_token); const Token &end_tk = stream->token ((int) end_token); - return QString::fromLatin1(tk.text + tk.position, end_tk.position - tk.position); + return QString::fromLatin1(tk.text + tk.position, static_cast(end_tk.position - tk.position)); } diff --git a/generator/parser/ast.h b/generator/parser/ast.h index 9fdca2e9..6afcbf92 100644 --- a/generator/parser/ast.h +++ b/generator/parser/ast.h @@ -221,15 +221,15 @@ struct AST QString toString(TokenStream *stream) const; - int kind; + int kind{}; - std::size_t start_token; - std::size_t end_token; + std::size_t start_token{}; + std::size_t end_token{}; }; struct TypeSpecifierAST: public AST { - const ListNode *cv; + const ListNode *cv{}; }; struct StatementAST: public AST @@ -248,277 +248,281 @@ struct AccessSpecifierAST: public DeclarationAST { DECLARE_AST_NODE(AccessSpecifier) - const ListNode *specs; + const ListNode *specs{}; }; struct AsmDefinitionAST: public DeclarationAST { DECLARE_AST_NODE(AsmDefinition) - const ListNode *cv; + const ListNode *cv{}; }; struct BaseClauseAST: public AST // ### kill me { DECLARE_AST_NODE(BaseClause) - const ListNode *base_specifiers; + const ListNode *base_specifiers{}; }; struct BaseSpecifierAST: public AST { DECLARE_AST_NODE(BaseSpecifier) - std::size_t virt; - std::size_t access_specifier; - NameAST *name; + std::size_t virt{}; + std::size_t access_specifier{}; + NameAST *name{}; }; struct BinaryExpressionAST: public ExpressionAST { DECLARE_AST_NODE(BinaryExpression) - std::size_t op; - ExpressionAST *left_expression; - ExpressionAST *right_expression; + std::size_t op{}; + ExpressionAST *left_expression{}; + ExpressionAST *right_expression{}; }; struct CastExpressionAST: public ExpressionAST { DECLARE_AST_NODE(CastExpression) - TypeIdAST *type_id; - ExpressionAST *expression; + TypeIdAST *type_id{}; + ExpressionAST *expression{}; }; struct ClassMemberAccessAST: public ExpressionAST { DECLARE_AST_NODE(ClassMemberAccess) - std::size_t op; - NameAST *name; + std::size_t op{}; + NameAST *name{}; }; struct ClassSpecifierAST: public TypeSpecifierAST { DECLARE_AST_NODE(ClassSpecifier) - WinDeclSpecAST *win_decl_specifiers; - std::size_t class_key; - NameAST *name; - BaseClauseAST *base_clause; - const ListNode *member_specs; + WinDeclSpecAST *win_decl_specifiers{}; + std::size_t class_key{}; + NameAST *name{}; + BaseClauseAST *base_clause{}; + const ListNode *member_specs{}; }; struct ForwardDeclarationSpecifierAST: public TypeSpecifierAST { DECLARE_AST_NODE(ForwardDeclarationSpecifier) - std::size_t class_key; - NameAST *name; - BaseClauseAST *base_clause; + std::size_t class_key{}; + NameAST *name{}; + BaseClauseAST *base_clause{}; }; struct CompoundStatementAST: public StatementAST { DECLARE_AST_NODE(CompoundStatement) - const ListNode *statements; + const ListNode *statements{}; }; struct ConditionAST: public AST { DECLARE_AST_NODE(Condition) - TypeSpecifierAST *type_specifier; - DeclaratorAST *declarator; - ExpressionAST *expression; + TypeSpecifierAST *type_specifier{}; + DeclaratorAST *declarator{}; + ExpressionAST *expression{}; }; struct ConditionalExpressionAST: public ExpressionAST { DECLARE_AST_NODE(ConditionalExpression) - ExpressionAST *condition; - ExpressionAST *left_expression; - ExpressionAST *right_expression; + ExpressionAST *condition{}; + ExpressionAST *left_expression{}; + ExpressionAST *right_expression{}; }; struct CppCastExpressionAST: public ExpressionAST { DECLARE_AST_NODE(CppCastExpression) - std::size_t op; - TypeIdAST *type_id; - ExpressionAST *expression; - const ListNode *sub_expressions; + std::size_t op{}; + TypeIdAST *type_id{}; + ExpressionAST *expression{}; + const ListNode *sub_expressions{}; }; struct CtorInitializerAST: public AST { DECLARE_AST_NODE(CtorInitializer) - std::size_t colon; - const ListNode *member_initializers; + std::size_t colon{}; + const ListNode *member_initializers{}; }; struct DeclarationStatementAST: public StatementAST { DECLARE_AST_NODE(DeclarationStatement) - DeclarationAST *declaration; + DeclarationAST *declaration{}; }; struct DeclaratorAST: public AST { DECLARE_AST_NODE(Declarator) + enum ValueReferenceEnum { UnspecifiedRef, Lvalue, Rvalue }; // "&" or "&&" after member function - DeclaratorAST() { - _override = false; - } - const ListNode *ptr_ops; - DeclaratorAST *sub_declarator; - NameAST *id; - ExpressionAST *bit_expression; - const ListNode *array_dimensions; - ParameterDeclarationClauseAST *parameter_declaration_clause; - const ListNode *fun_cv; - ExceptionSpecificationAST *exception_spec; - bool _override; + DeclaratorAST() = default; + const ListNode *ptr_ops{}; + DeclaratorAST *sub_declarator{}; + NameAST *id{}; + ExpressionAST *bit_expression{}; + const ListNode *array_dimensions{}; + ParameterDeclarationClauseAST *parameter_declaration_clause{}; + const ListNode *fun_cv{}; + ExceptionSpecificationAST *exception_spec{}; + bool _override{}; + bool packedParameter{}; + ValueReferenceEnum valueRef{ UnspecifiedRef }; }; struct DeleteExpressionAST: public ExpressionAST { DECLARE_AST_NODE(DeleteExpression) - std::size_t scope_token; - std::size_t delete_token; - std::size_t lbracket_token; - std::size_t rbracket_token; - ExpressionAST *expression; + std::size_t scope_token{}; + std::size_t delete_token{}; + std::size_t lbracket_token{}; + std::size_t rbracket_token{}; + ExpressionAST *expression{}; }; struct DoStatementAST: public StatementAST { DECLARE_AST_NODE(DoStatement) - StatementAST *statement; - ExpressionAST *expression; + StatementAST *statement{}; + ExpressionAST *expression{}; }; struct ElaboratedTypeSpecifierAST: public TypeSpecifierAST { DECLARE_AST_NODE(ElaboratedTypeSpecifier) - std::size_t type; - NameAST *name; + std::size_t type{}; + NameAST *name{}; }; struct EnumSpecifierAST: public TypeSpecifierAST { DECLARE_AST_NODE(EnumSpecifier) - NameAST *name; - const ListNode *enumerators; + NameAST *name{}; + const ListNode *enumerators{}; + bool is_enum_class{}; }; struct EnumeratorAST: public AST { DECLARE_AST_NODE(Enumerator) - std::size_t id; - ExpressionAST *expression; + std::size_t id{}; + ExpressionAST *expression{}; }; struct ExceptionSpecificationAST: public AST { DECLARE_AST_NODE(ExceptionSpecification) - std::size_t ellipsis; - const ListNode *type_ids; + std::size_t ellipsis{}; + const ListNode *type_ids{}; }; struct ExpressionOrDeclarationStatementAST: public StatementAST { DECLARE_AST_NODE(ExpressionOrDeclarationStatement) - StatementAST *expression; - StatementAST *declaration; + StatementAST *expression{}; + StatementAST *declaration{}; }; struct ExpressionStatementAST: public StatementAST { DECLARE_AST_NODE(ExpressionStatement) - ExpressionAST *expression; + ExpressionAST *expression{}; }; struct FunctionCallAST: public ExpressionAST { DECLARE_AST_NODE(FunctionCall) - ExpressionAST *arguments; + ExpressionAST *arguments{}; }; struct FunctionDefinitionAST: public DeclarationAST { DECLARE_AST_NODE(FunctionDefinition) - const ListNode *storage_specifiers; - const ListNode *function_specifiers; - TypeSpecifierAST *type_specifier; - InitDeclaratorAST *init_declarator; - StatementAST *function_body; - WinDeclSpecAST *win_decl_specifiers; + const ListNode *storage_specifiers{}; + const ListNode *function_specifiers{}; + TypeSpecifierAST *type_specifier{}; + InitDeclaratorAST *init_declarator{}; + StatementAST *function_body{}; + WinDeclSpecAST *win_decl_specifiers{}; }; struct ForStatementAST: public StatementAST { DECLARE_AST_NODE(ForStatement) - StatementAST *init_statement; - ConditionAST *condition; - ExpressionAST *expression; - StatementAST *statement; + StatementAST *init_statement{}; + ConditionAST *condition{}; + ExpressionAST *expression{}; + StatementAST *statement{}; }; struct IfStatementAST: public StatementAST { DECLARE_AST_NODE(IfStatement) - ConditionAST *condition; - StatementAST *statement; - StatementAST *else_statement; + ConditionAST *condition{}; + StatementAST *statement{}; + StatementAST *else_statement{}; }; struct IncrDecrExpressionAST: public ExpressionAST { DECLARE_AST_NODE(IncrDecrExpression) - std::size_t op; + std::size_t op{}; }; struct InitDeclaratorAST: public AST { DECLARE_AST_NODE(InitDeclarator) - DeclaratorAST *declarator; - InitializerAST *initializer; + DeclaratorAST *declarator{}; + InitializerAST *initializer{}; }; struct InitializerAST: public AST { DECLARE_AST_NODE(Initializer) - InitializerClauseAST *initializer_clause; - ExpressionAST *expression; + InitializerClauseAST *initializer_clause{}; + ExpressionAST *expression{}; + bool isDefault{}; + bool isDeleted{}; }; struct InitializerClauseAST: public AST { DECLARE_AST_NODE(InitializerClause) - ExpressionAST *expression; + ExpressionAST *expression{}; }; struct LabeledStatementAST: public StatementAST @@ -530,150 +534,150 @@ struct LinkageBodyAST: public AST { DECLARE_AST_NODE(LinkageBody) - const ListNode *declarations; + const ListNode *declarations{}; }; struct LinkageSpecificationAST: public DeclarationAST { DECLARE_AST_NODE(LinkageSpecification) - std::size_t extern_type; - LinkageBodyAST *linkage_body; - DeclarationAST *declaration; + std::size_t extern_type{}; + LinkageBodyAST *linkage_body{}; + DeclarationAST *declaration{}; }; struct MemInitializerAST: public AST { DECLARE_AST_NODE(MemInitializer) - NameAST *initializer_id; - ExpressionAST *expression; + NameAST *initializer_id{}; + ExpressionAST *expression{}; }; struct NameAST: public AST { DECLARE_AST_NODE(Name) - bool global; - const ListNode *qualified_names; - UnqualifiedNameAST *unqualified_name; + bool global{}; + const ListNode *qualified_names{}; + UnqualifiedNameAST *unqualified_name{}; }; struct NamespaceAST: public DeclarationAST { DECLARE_AST_NODE(Namespace) - std::size_t namespace_name; - LinkageBodyAST *linkage_body; + std::size_t namespace_name{}; + LinkageBodyAST *linkage_body{}; }; struct NamespaceAliasDefinitionAST: public DeclarationAST { DECLARE_AST_NODE(NamespaceAliasDefinition) - std::size_t namespace_name; - NameAST *alias_name; + std::size_t namespace_name{}; + NameAST *alias_name{}; }; struct NewDeclaratorAST: public AST { DECLARE_AST_NODE(NewDeclarator) - PtrOperatorAST *ptr_op; - NewDeclaratorAST *sub_declarator; - const ListNode *expressions; + PtrOperatorAST *ptr_op{}; + NewDeclaratorAST *sub_declarator{}; + const ListNode *expressions{}; }; struct NewExpressionAST: public ExpressionAST { DECLARE_AST_NODE(NewExpression) - std::size_t scope_token; - std::size_t new_token; - ExpressionAST *expression; - TypeIdAST *type_id; - NewTypeIdAST *new_type_id; - NewInitializerAST *new_initializer; + std::size_t scope_token{}; + std::size_t new_token{}; + ExpressionAST *expression{}; + TypeIdAST *type_id{}; + NewTypeIdAST *new_type_id{}; + NewInitializerAST *new_initializer{}; }; struct NewInitializerAST: public AST { DECLARE_AST_NODE(NewInitializer) - ExpressionAST *expression; + ExpressionAST *expression{}; }; struct NewTypeIdAST: public AST { DECLARE_AST_NODE(NewTypeId) - TypeSpecifierAST *type_specifier; - NewInitializerAST *new_initializer; - NewDeclaratorAST *new_declarator; + TypeSpecifierAST *type_specifier{}; + NewInitializerAST *new_initializer{}; + NewDeclaratorAST *new_declarator{}; }; struct OperatorAST: public AST { DECLARE_AST_NODE(Operator) - std::size_t op; - std::size_t open; - std::size_t close; + std::size_t op{}; + std::size_t open{}; + std::size_t close{}; }; struct OperatorFunctionIdAST: public AST { DECLARE_AST_NODE(OperatorFunctionId) - OperatorAST *op; - TypeSpecifierAST *type_specifier; - const ListNode *ptr_ops; + OperatorAST *op{}; + TypeSpecifierAST *type_specifier{}; + const ListNode *ptr_ops{}; }; struct ParameterDeclarationAST: public AST { DECLARE_AST_NODE(ParameterDeclaration) - TypeSpecifierAST *type_specifier; - DeclaratorAST *declarator; - ExpressionAST *expression; + TypeSpecifierAST *type_specifier{}; + DeclaratorAST *declarator{}; + ExpressionAST *expression{}; }; struct ParameterDeclarationClauseAST: public AST { DECLARE_AST_NODE(ParameterDeclarationClause) - const ListNode *parameter_declarations; - std::size_t ellipsis; + const ListNode *parameter_declarations{}; + std::size_t ellipsis{}; }; struct PostfixExpressionAST: public ExpressionAST { DECLARE_AST_NODE(PostfixExpression) - TypeSpecifierAST *type_specifier; - ExpressionAST *expression; - const ListNode *sub_expressions; + TypeSpecifierAST *type_specifier{}; + ExpressionAST *expression{}; + const ListNode *sub_expressions{}; }; struct PrimaryExpressionAST: public ExpressionAST { DECLARE_AST_NODE(PrimaryExpression) - StringLiteralAST *literal; - std::size_t token; - StatementAST *expression_statement; - ExpressionAST *sub_expression; - NameAST *name; + StringLiteralAST *literal{}; + std::size_t token{}; + StatementAST *expression_statement{}; + ExpressionAST *sub_expression{}; + NameAST *name{}; }; struct PtrOperatorAST: public AST { DECLARE_AST_NODE(PtrOperator) - const ListNode *cv; - std::size_t op; - PtrToMemberAST *mem_ptr; + const ListNode *cv{}; + std::size_t op{}; + PtrToMemberAST *mem_ptr{}; }; struct PtrToMemberAST: public AST @@ -685,100 +689,102 @@ struct ReturnStatementAST: public StatementAST { DECLARE_AST_NODE(ReturnStatement) - ExpressionAST *expression; + ExpressionAST *expression{}; }; struct SimpleDeclarationAST: public DeclarationAST { DECLARE_AST_NODE(SimpleDeclaration) - const ListNode *storage_specifiers; - const ListNode *function_specifiers; - TypeSpecifierAST *type_specifier; - const ListNode *init_declarators; - WinDeclSpecAST *win_decl_specifiers; + const ListNode *storage_specifiers{}; + const ListNode *function_specifiers{}; + TypeSpecifierAST *type_specifier{}; + const ListNode *init_declarators{}; + WinDeclSpecAST *win_decl_specifiers{}; }; struct SimpleTypeSpecifierAST: public TypeSpecifierAST { DECLARE_AST_NODE(SimpleTypeSpecifier) - const ListNode *integrals; - std::size_t type_of; - TypeIdAST *type_id; - ExpressionAST *expression; - NameAST *name; + const ListNode *integrals{}; + std::size_t type_of{}; + TypeIdAST *type_id{}; + ExpressionAST *expression{}; + NameAST *name{}; + bool is_auto{}; }; struct SizeofExpressionAST: public ExpressionAST { DECLARE_AST_NODE(SizeofExpression) - std::size_t sizeof_token; - TypeIdAST *type_id; - ExpressionAST *expression; + std::size_t sizeof_token{}; + TypeIdAST *type_id{}; + ExpressionAST *expression{}; }; struct StringLiteralAST: public AST { DECLARE_AST_NODE(StringLiteral) - const ListNode *literals; + const ListNode *literals{}; }; struct SubscriptExpressionAST: public ExpressionAST { DECLARE_AST_NODE(SubscriptExpression) - ExpressionAST *subscript; + ExpressionAST *subscript{}; }; struct SwitchStatementAST: public StatementAST { DECLARE_AST_NODE(SwitchStatement) - ConditionAST *condition; - StatementAST *statement; + ConditionAST *condition{}; + StatementAST *statement{}; }; struct TemplateArgumentAST: public AST { DECLARE_AST_NODE(TemplateArgument) - TypeIdAST *type_id; - ExpressionAST *expression; + TypeIdAST *type_id{}; + ExpressionAST *expression{}; + bool variadic{}; }; struct TemplateDeclarationAST: public DeclarationAST { DECLARE_AST_NODE(TemplateDeclaration) - std::size_t exported; - const ListNode *template_parameters; - DeclarationAST* declaration; + std::size_t exported{}; + const ListNode *template_parameters{}; + DeclarationAST* declaration{}; }; struct TemplateParameterAST: public AST { DECLARE_AST_NODE(TemplateParameter) - TypeParameterAST *type_parameter; - ParameterDeclarationAST *parameter_declaration; + TypeParameterAST *type_parameter{}; + ParameterDeclarationAST *parameter_declaration{}; }; struct ThrowExpressionAST: public ExpressionAST { DECLARE_AST_NODE(ThrowExpression) - std::size_t throw_token; - ExpressionAST *expression; + std::size_t throw_token{}; + ExpressionAST *expression{}; }; struct TranslationUnitAST: public AST { DECLARE_AST_NODE(TranslationUnit) - const ListNode *declarations; + const ListNode *declarations{}; }; struct TryBlockStatementAST: public StatementAST @@ -790,85 +796,85 @@ struct TypeIdAST: public AST { DECLARE_AST_NODE(TypeId) - TypeSpecifierAST *type_specifier; - DeclaratorAST *declarator; + TypeSpecifierAST *type_specifier{}; + DeclaratorAST *declarator{}; }; struct TypeIdentificationAST: public ExpressionAST { DECLARE_AST_NODE(TypeIdentification) - std::size_t typename_token; - NameAST *name; - ExpressionAST *expression; + std::size_t typename_token{}; + NameAST *name{}; + ExpressionAST *expression{}; }; struct TypeParameterAST: public AST { DECLARE_AST_NODE(TypeParameter) - std::size_t type; - NameAST *name; - TypeIdAST *type_id; - const ListNode *template_parameters; - NameAST *template_name; + std::size_t type{}; + NameAST *name{}; + TypeIdAST *type_id{}; + const ListNode *template_parameters{}; + NameAST *template_name{}; }; struct TypedefAST: public DeclarationAST { DECLARE_AST_NODE(Typedef) - TypeSpecifierAST *type_specifier; - const ListNode *init_declarators; + TypeSpecifierAST *type_specifier{}; + const ListNode *init_declarators{}; }; struct UnaryExpressionAST: public ExpressionAST { DECLARE_AST_NODE(UnaryExpression) - std::size_t op; - ExpressionAST *expression; + std::size_t op{}; + ExpressionAST *expression{}; }; struct UnqualifiedNameAST: public AST { DECLARE_AST_NODE(UnqualifiedName) - std::size_t tilde; - std::size_t id; - OperatorFunctionIdAST *operator_id; - const ListNode *template_arguments; + std::size_t tilde{}; + std::size_t id{}; + OperatorFunctionIdAST *operator_id{}; + const ListNode *template_arguments{}; }; struct UsingAST: public DeclarationAST { DECLARE_AST_NODE(Using) - std::size_t type_name; - NameAST *name; + std::size_t type_name{}; + NameAST *name{}; }; struct UsingDirectiveAST: public DeclarationAST { DECLARE_AST_NODE(UsingDirective) - NameAST *name; + NameAST *name{}; }; struct WhileStatementAST: public StatementAST { DECLARE_AST_NODE(WhileStatement) - ConditionAST *condition; - StatementAST *statement; + ConditionAST *condition{}; + StatementAST *statement{}; }; struct WinDeclSpecAST: public AST { DECLARE_AST_NODE(WinDeclSpec) - std::size_t specifier; - std::size_t modifier; + std::size_t specifier{}; + std::size_t modifier{}; }; struct QPropertyAST : public DeclarationAST @@ -880,7 +886,7 @@ struct QEnumsAST : public DeclarationAST { DECLARE_AST_NODE(QEnumsAST) - bool isQEnum; + bool isQEnum{}; }; template diff --git a/generator/parser/binder.cpp b/generator/parser/binder.cpp index 502ecc44..cfc8d3bb 100644 --- a/generator/parser/binder.cpp +++ b/generator/parser/binder.cpp @@ -266,7 +266,7 @@ void Binder::declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_ { name_cc.run(id); warnHere(); - std::cerr << "** WARNING scope not found for symbol:" + std::cerr << "** WARNING scope not found for symbol: " << qPrintable(name_cc.name()) << std::endl; return; } @@ -282,7 +282,9 @@ void Binder::declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_ fun->setAccessPolicy(_M_current_access); fun->setFunctionType(_M_current_function_type); fun->setName(name_cc.name()); - fun->setAbstract(init_declarator->initializer != 0); + InitializerAST* initializer = init_declarator->initializer; + fun->setDeleted(initializer && initializer->isDeleted); + fun->setAbstract(initializer && !initializer->isDefault && !initializer->isDeleted); // must be "= 0" fun->setConstant(declarator->fun_cv != 0); fun->setException(exceptionSpecToString(declarator->exception_spec)); @@ -363,6 +365,15 @@ void Binder::visitFunctionDefinition(FunctionDefinitionAST *node) Q_ASSERT(node->init_declarator != 0); ScopeModelItem scope = currentScope(); + bool friendWithDefinition = false; + + if (hasFriendSpecifier(node->storage_specifiers) && ast_cast(node)) + { + // check if this function declaration is a "friend" function with implementation body. + // In this case we modify the scope, and remove the "friend" flag later on. + friendWithDefinition = true; + scope = model_static_cast(_M_current_file); + } InitDeclaratorAST *init_declarator = node->init_declarator; DeclaratorAST *declarator = init_declarator->declarator; @@ -382,6 +393,13 @@ void Binder::visitFunctionDefinition(FunctionDefinitionAST *node) } CodeModelFinder finder(model(), this); + if (declarator->valueRef == DeclaratorAST::Rvalue) + { + // rvalue reference methods are ignored, since we can't use them for the wrappers + // (there is usually also a method with lvalue reference binding) + return; + } + ScopeModelItem functionScope = finder.resolveScope(declarator->id, scope); if (! functionScope) { @@ -402,6 +420,12 @@ void Binder::visitFunctionDefinition(FunctionDefinitionAST *node) // << qPrintable(name_cc.name()) << std::endl; return; } + if (p.packedParameter) { + //warnHere(); + //std::cerr << "** Skipping function with packed parameter: " + // << qPrintable(name_cc.name()) << std::endl; + return; + } } Q_ASSERT(! decl_cc.id().isEmpty()); @@ -435,11 +459,30 @@ void Binder::visitFunctionDefinition(FunctionDefinitionAST *node) model_static_cast(_M_current_function)->setVirtual(true); } + if (friendWithDefinition) + { + // unset the friend flag, as we treat this like a stand-alone function definition + _M_current_function->setFriend(false); + // also set the access policy to public, just in case + _M_current_function->setAccessPolicy(CodeModel::Public); + } _M_current_function->setVariadics (decl_cc.isVariadics ()); foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters()) { ArgumentModelItem arg = model()->create(); + + if (_M_current_class && _M_current_class->isTemplateClass()) + { + QStringList qualifiedName = p.type.qualifiedName(); + if (qualifiedName.size() == 1 && !qualifiedName.last().contains('<') && + qualifiedName.last() == _M_current_class->name().split('<').first()) + { + // Fix: add template arguments if the argument type is the current class + // name without template arguments + p.type.setQualifiedName(QStringList(_M_current_class->name())); + } + } arg->setType(qualifyType(p.type, functionScope->qualifiedName())); arg->setName(p.name); arg->setDefaultValue(p.defaultValue); @@ -727,6 +770,7 @@ void Binder::visitClassSpecifier(ClassSpecifierAST *node) name_cc.run(node->name->unqualified_name); _M_context.append(name_cc.name()); visitNodes(this, node->member_specs); + _M_current_class->setHasActualDeclaration(node->member_specs); _M_context.removeLast(); changeCurrentClass(old); @@ -764,6 +808,7 @@ void Binder::visitEnumSpecifier(EnumSpecifierAST *node) _M_current_enum = model()->create(); _M_current_enum->setAccessPolicy(_M_current_access); + _M_current_enum->setEnumClass(node->is_enum_class); updateItemPosition (_M_current_enum->toItem(), node); _M_current_enum->setName(name); _M_current_enum->setScope(enumScope->qualifiedName()); @@ -817,14 +862,14 @@ void Binder::visitQEnums(QEnumsAST *node) const Token &start = _M_token_stream->token((int) node->start_token); const Token &end = _M_token_stream->token((int) node->end_token); QStringList enum_list = QString::fromLatin1(start.text + start.position, - end.position - start.position).split(' '); + static_cast(end.position - start.position)).split(' '); ScopeModelItem scope = currentScope(); for (int i = 0; i < enum_list.size(); ++i) { //if (node->isQEnum) { // std::cout << enum_list.at(i).toLatin1().constData() << std::endl; //} - scope->addEnumsDeclaration(enum_list.at(i)); + scope->addQEnumDeclaration(enum_list.at(i)); } } @@ -833,7 +878,7 @@ void Binder::visitQProperty(QPropertyAST *node) const Token &start = _M_token_stream->token((int) node->start_token); const Token &end = _M_token_stream->token((int) node->end_token); QString property = QString::fromLatin1(start.text + start.position, - end.position - start.position); + static_cast(end.position - start.position)); _M_current_class->addPropertyDeclaration(property); } @@ -847,6 +892,24 @@ void Binder::warnHere() const } } +bool Binder::hasFriendSpecifier(const ListNode* it) +{ + if (it == 0) + return false; + + it = it->toFront(); + const ListNode* end = it; + + do + { + if (decode_token(it->element) == Token_friend) { + return true; + } + it = it->next; + } while (it != end); + return false; +} + void Binder::applyStorageSpecifiers(const ListNode *it, MemberModelItem item) { if (it == 0) @@ -901,6 +964,10 @@ void Binder::applyFunctionSpecifiers(const ListNode *it, FunctionMo default: break; + case Token_constexpr: + item->setConstexpr(true); + break; + case Token_inline: item->setInline(true); break; diff --git a/generator/parser/binder.h b/generator/parser/binder.h index e39210f8..92209239 100644 --- a/generator/parser/binder.h +++ b/generator/parser/binder.h @@ -104,6 +104,7 @@ class Binder: protected DefaultVisitor void declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_declarator); + bool hasFriendSpecifier(const ListNode* it); void applyStorageSpecifiers(const ListNode *storage_specifiers, MemberModelItem item); void applyFunctionSpecifiers(const ListNode *it, FunctionModelItem item); diff --git a/generator/parser/codemodel.cpp b/generator/parser/codemodel.cpp index f70e3085..52b1f33e 100644 --- a/generator/parser/codemodel.cpp +++ b/generator/parser/codemodel.cpp @@ -143,6 +143,7 @@ TypeInfo TypeInfo::combine (const TypeInfo &__lhs, const TypeInfo &__rhs) __result.setConstant (__result.isConstant () || __rhs.isConstant ()); __result.setVolatile (__result.isVolatile () || __rhs.isVolatile ()); + __result.setMutable (__result.isMutable () || __rhs.isMutable ()); __result.setReference (__result.isReference () || __rhs.isReference ()); __result.setRvalueReference (__result.isRvalueReference () || __rhs.isRvalueReference ()); __result.setIndirections (__result.indirections () + __rhs.indirections ()); @@ -174,7 +175,7 @@ TypeInfo TypeInfo::resolveType (TypeInfo const &__type, CodeModelItem __scope) return otherType; } -QString TypeInfo::toString() const +QString TypeInfo::toString(bool parsable) const { QString tmp; @@ -182,8 +183,13 @@ QString TypeInfo::toString() const if (isConstant()) tmp += QLatin1String(" const"); - if (isVolatile()) - tmp += QLatin1String(" volatile"); + if (!parsable) { + if (isVolatile()) + tmp += QLatin1String(" volatile"); + + if (isMutable()) + tmp += QLatin1String(" mutable"); + } if (indirections()) tmp += QString(indirections(), QLatin1Char('*')); @@ -201,7 +207,7 @@ QString TypeInfo::toString() const if (i != 0) tmp += QLatin1String(", "); - tmp += m_arguments.at(i).toString(); + tmp += m_arguments.at(i).toString(parsable); } tmp += QLatin1String(")"); } @@ -216,7 +222,7 @@ QString TypeInfo::toString() const return tmp; } -bool TypeInfo::operator==(const TypeInfo &other) +bool TypeInfo::operator==(const TypeInfo &other) const { if (arrayElements().count() != other.arrayElements().count()) return false; @@ -232,9 +238,9 @@ bool TypeInfo::operator==(const TypeInfo &other) } #endif - return flags == other.flags + return m_flags.equals(other.m_flags) && m_qualifiedName == other.m_qualifiedName - && (!m_functionPointer || m_arguments == other.m_arguments); + && (!m_flags.m_functionPointer || m_arguments == other.m_arguments); } // --------------------------------------------------------------------------- @@ -423,9 +429,9 @@ FunctionList _ScopeModelItem::functions() const return _M_functions.values(); } -void _ScopeModelItem::addEnumsDeclaration(const QString &enumsDeclaration) +void _ScopeModelItem::addQEnumDeclaration(const QString &qEnumDeclaration) { - _M_enumsDeclarations << enumsDeclaration; + _M_qEnumDeclarations.insert(qEnumDeclaration); } FunctionDefinitionList _ScopeModelItem::functionDefinitions() const @@ -675,63 +681,73 @@ void _FunctionModelItem::setException(const QString &exception) bool _FunctionModelItem::isVariadics() const { - return _M_isVariadics; + return _M.isVariadics; } void _FunctionModelItem::setVariadics(bool isVariadics) { - _M_isVariadics = isVariadics; + _M.isVariadics = isVariadics; } bool _FunctionModelItem::isVirtual() const { - return _M_isVirtual; + return _M.isVirtual; } void _FunctionModelItem::setVirtual(bool isVirtual) { - _M_isVirtual = isVirtual; + _M.isVirtual = isVirtual; } bool _FunctionModelItem::isInline() const { - return _M_isInline; + return _M.isInline; } void _FunctionModelItem::setInline(bool isInline) { - _M_isInline = isInline; + _M.isInline = isInline; } bool _FunctionModelItem::isExplicit() const { - return _M_isExplicit; + return _M.isExplicit; } void _FunctionModelItem::setExplicit(bool isExplicit) { - _M_isExplicit = isExplicit; + _M.isExplicit = isExplicit; } bool _FunctionModelItem::isAbstract() const { - return _M_isAbstract; + return _M.isAbstract; } void _FunctionModelItem::setAbstract(bool isAbstract) { - _M_isAbstract = isAbstract; + _M.isAbstract = isAbstract; +} + +bool _FunctionModelItem::isDeleted() const +{ + return _M.isDeleted; +} + +void _FunctionModelItem::setDeleted(bool isDeleted) +{ + _M.isDeleted = isDeleted; } // Qt bool _FunctionModelItem::isInvokable() const { - return _M_isInvokable; + return _M.isInvokable; } void _FunctionModelItem::setInvokable(bool isInvokable) { - _M_isInvokable = isInvokable; + _M.isInvokable = isInvokable; } // --------------------------------------------------------------------------- @@ -899,82 +915,92 @@ void _MemberModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy) bool _MemberModelItem::isStatic() const { - return _M_isStatic; + return _M.isStatic; } void _MemberModelItem::setStatic(bool isStatic) { - _M_isStatic = isStatic; + _M.isStatic = isStatic; } bool _MemberModelItem::isConstant() const { - return _M_isConstant; + return _M.isConstant; } void _MemberModelItem::setConstant(bool isConstant) { - _M_isConstant = isConstant; + _M.isConstant = isConstant; +} + +bool _MemberModelItem::isConstexpr() const +{ + return _M.isConstexpr; +} + +void _MemberModelItem::setConstexpr(bool isConstexpr) +{ + _M.isConstexpr = isConstexpr; } bool _MemberModelItem::isVolatile() const { - return _M_isVolatile; + return _M.isVolatile; } void _MemberModelItem::setVolatile(bool isVolatile) { - _M_isVolatile = isVolatile; + _M.isVolatile = isVolatile; } bool _MemberModelItem::isAuto() const { - return _M_isAuto; + return _M.isAuto; } void _MemberModelItem::setAuto(bool isAuto) { - _M_isAuto = isAuto; + _M.isAuto = isAuto; } bool _MemberModelItem::isFriend() const { - return _M_isFriend; + return _M.isFriend; } void _MemberModelItem::setFriend(bool isFriend) { - _M_isFriend = isFriend; + _M.isFriend = isFriend; } bool _MemberModelItem::isRegister() const { - return _M_isRegister; + return _M.isRegister; } void _MemberModelItem::setRegister(bool isRegister) { - _M_isRegister = isRegister; + _M.isRegister = isRegister; } bool _MemberModelItem::isExtern() const { - return _M_isExtern; + return _M.isExtern; } void _MemberModelItem::setExtern(bool isExtern) { - _M_isExtern = isExtern; + _M.isExtern = isExtern; } bool _MemberModelItem::isMutable() const { - return _M_isMutable; + return _M.isMutable; } void _MemberModelItem::setMutable(bool isMutable) { - _M_isMutable = isMutable; + _M.isMutable = isMutable; } // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/generator/parser/codemodel.h b/generator/parser/codemodel.h index 448cf719..867e368c 100644 --- a/generator/parser/codemodel.h +++ b/generator/parser/codemodel.h @@ -51,6 +51,7 @@ #include #include #include +#include #define DECLARE_MODEL_NODE(k) \ enum { __node_kind = Kind_##k }; \ @@ -124,41 +125,31 @@ class CodeModel void operator = (const CodeModel &other); }; -class TypeInfo +struct TypeInfo { -public: - TypeInfo(const TypeInfo &other) - : flags(other.flags), - m_qualifiedName(other.m_qualifiedName), - m_arrayElements(other.m_arrayElements), - m_arguments(other.m_arguments), - m_rvalue_reference(other.m_rvalue_reference) - { - } - - TypeInfo(): - flags (0), m_rvalue_reference(false) {} - 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 isConstant() const { return m_flags.m_constant; } + void setConstant(bool is) { m_flags.m_constant = is; } - bool isVolatile() const { return m_volatile; } - void setVolatile(bool is) { m_volatile = is; } + bool isVolatile() const { return m_flags.m_volatile; } + void setVolatile(bool is) { m_flags.m_volatile = is; } - bool isReference() const { return m_reference; } - void setReference(bool is) { m_reference = is; } + bool isMutable() const { return m_flags.m_mutable; } + void setMutable(bool is) { m_flags.m_mutable = is; } + + bool isReference() const { return m_flags.m_reference; } + void setReference(bool is) { m_flags.m_reference = is; } bool isRvalueReference() const { return m_rvalue_reference; } void setRvalueReference(bool is) { m_rvalue_reference = is; } - int indirections() const { return m_indirections; } - void setIndirections(int indirections) { m_indirections = indirections; } + int indirections() const { return m_flags.m_indirections; } + void setIndirections(int indirections) { m_flags.m_indirections = indirections; } - bool isFunctionPointer() const { return m_functionPointer; } - void setFunctionPointer(bool is) { m_functionPointer = is; } + bool isFunctionPointer() const { return m_flags.m_functionPointer; } + void setFunctionPointer(bool is) { m_flags.m_functionPointer = is; } QStringList arrayElements() const { return m_arrayElements; } void setArrayElements(const QStringList &arrayElements) { m_arrayElements = arrayElements; } @@ -167,36 +158,41 @@ class TypeInfo void setArguments(const QList &arguments); void addArgument(const TypeInfo &arg) { m_arguments.append(arg); } - bool operator==(const TypeInfo &other); - bool operator!=(const TypeInfo &other) { return !(*this==other); } + bool operator==(const TypeInfo &other) const; + bool operator!=(const TypeInfo &other) const { return !(*this==other); } // ### arrays and templates?? - QString toString() const; + QString toString(bool parsable = false) const; static TypeInfo combine (const TypeInfo &__lhs, const TypeInfo &__rhs); static TypeInfo resolveType (TypeInfo const &__type, CodeModelItem __scope); private: - union - { - uint flags; - - struct - { - uint m_constant: 1; - uint m_volatile: 1; - uint m_reference: 1; - uint m_functionPointer: 1; - uint m_indirections: 6; - uint m_padding: 22; - }; - }; + struct TypeInfo_flags { + uint m_constant: 1; + uint m_constexpr: 1; + uint m_volatile: 1; + uint m_mutable: 1; + uint m_reference: 1; + uint m_functionPointer: 1; + uint m_indirections: 6; + inline bool equals(TypeInfo_flags other) const { + /* m_auto and m_friend don't matter here */ + return m_constant == other.m_constant + && m_constexpr == other.m_constexpr + && m_volatile == other.m_volatile + && m_mutable == other.m_mutable + && m_reference == other.m_reference + && m_functionPointer == other.m_functionPointer + && m_indirections == other.m_indirections; + } + } m_flags {0, 0, 0, 0, 0, 0, 0}; QStringList m_qualifiedName; QStringList m_arrayElements; QList m_arguments; - bool m_rvalue_reference; + bool m_rvalue_reference { false }; }; class _CodeModelItem: public QSharedData @@ -312,8 +308,8 @@ class _ScopeModelItem: public _CodeModelItem TypeAliasModelItem findTypeAlias(const QString &name) const; VariableModelItem findVariable(const QString &name) const; - void addEnumsDeclaration(const QString &enumsDeclaration); - QStringList enumsDeclarations() const { return _M_enumsDeclarations; } + void addQEnumDeclaration(const QString &qEnumDeclaration); + QSet qEnumDeclarations() const { return _M_qEnumDeclarations; } inline QHash classMap() const { return _M_classes; } inline QHash enumMap() const { return _M_enums; } @@ -340,7 +336,7 @@ class _ScopeModelItem: public _CodeModelItem _ScopeModelItem(const _ScopeModelItem &other); void operator = (const _ScopeModelItem &other); - QStringList _M_enumsDeclarations; + QSet _M_qEnumDeclarations; }; class _ClassModelItem: public _ScopeModelItem @@ -359,6 +355,7 @@ class _ClassModelItem: public _ScopeModelItem TemplateParameterList templateParameters() const; void setTemplateParameters(const TemplateParameterList &templateParameters); + bool isTemplateClass() const { return _M_templateParameters.size(); } bool extendsClass(const QString &name) const; @@ -368,6 +365,10 @@ class _ClassModelItem: public _ScopeModelItem void addPropertyDeclaration(const QString &propertyDeclaration); QStringList propertyDeclarations() const { return _M_propertyDeclarations; } + void setHasActualDeclaration(bool flag) { _M_hasActualDeclaration = flag; } + bool hasActualDeclaration() const { return _M_hasActualDeclaration; } + + protected: _ClassModelItem(CodeModel *model, int kind = __node_kind) : _ScopeModelItem(model, kind), _M_classType(CodeModel::Class) {} @@ -379,6 +380,8 @@ class _ClassModelItem: public _ScopeModelItem QStringList _M_propertyDeclarations; + bool _M_hasActualDeclaration{}; + private: _ClassModelItem(const _ClassModelItem &other); void operator = (const _ClassModelItem &other); @@ -468,6 +471,9 @@ class _MemberModelItem: public _CodeModelItem bool isConstant() const; void setConstant(bool isConstant); + bool isConstexpr() const; + void setConstexpr(bool isConstexpr); + bool isVolatile() const; void setVolatile(bool isVolatile); @@ -516,15 +522,16 @@ class _MemberModelItem: public _CodeModelItem { 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 isConstant: 1; + uint isConstexpr: 1; + uint isVolatile: 1; + uint isStatic: 1; + uint isAuto: 1; + uint isFriend: 1; + uint isRegister: 1; + uint isExtern: 1; + uint isMutable: 1; + } _M; uint _M_flags; }; @@ -564,6 +571,9 @@ class _FunctionModelItem: public _MemberModelItem bool isAbstract() const; void setAbstract(bool isAbstract); + bool isDeleted() const; + void setDeleted(bool isDeleted); + bool isVariadics() const; void setVariadics(bool isVariadics); @@ -584,13 +594,14 @@ class _FunctionModelItem: public _MemberModelItem { 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 isVirtual: 1; + uint isInline: 1; + uint isAbstract: 1; + uint isDeleted: 1; + uint isExplicit: 1; + uint isVariadics: 1; + uint isInvokable : 1; // Qt + } _M; uint _M_flags; }; @@ -666,6 +677,9 @@ class _EnumModelItem: public _CodeModelItem CodeModel::AccessPolicy accessPolicy() const; void setAccessPolicy(CodeModel::AccessPolicy accessPolicy); + bool isEnumClass() const { return _M_isEnumClass; } + void setEnumClass(bool isEnumClass) { _M_isEnumClass = isEnumClass; } + EnumeratorList enumerators() const; void addEnumerator(EnumeratorModelItem item); void removeEnumerator(EnumeratorModelItem item); @@ -679,6 +693,7 @@ class _EnumModelItem: public _CodeModelItem private: CodeModel::AccessPolicy _M_accessPolicy; EnumeratorList _M_enumerators; + bool _M_isEnumClass{}; private: _EnumModelItem(const _EnumModelItem &other); diff --git a/generator/parser/codemodel_fwd.h b/generator/parser/codemodel_fwd.h index 35e73ed0..55bf3965 100644 --- a/generator/parser/codemodel_fwd.h +++ b/generator/parser/codemodel_fwd.h @@ -62,7 +62,7 @@ class _TemplateParameterModelItem; class _TypeAliasModelItem; class _VariableModelItem; class _MemberModelItem; -class TypeInfo; +struct TypeInfo; typedef CodeModelPointer<_ArgumentModelItem> ArgumentModelItem; typedef CodeModelPointer<_ClassModelItem> ClassModelItem; diff --git a/generator/parser/codemodel_pointer.h b/generator/parser/codemodel_pointer.h index dc99c6bb..1e34abae 100644 --- a/generator/parser/codemodel_pointer.h +++ b/generator/parser/codemodel_pointer.h @@ -122,16 +122,22 @@ template class CodeModelPointer # if QT_VERSION >= 0x050000 +# if QT_VERSION >= QT_VERSION_CHECK(5,14,0) +# define LOAD loadRelaxed +# else +# define LOAD load +# endif operator T * () const { - return QAtomicPointer::load(); + return QAtomicPointer::LOAD(); } inline bool operator!() const { return !(bool)*this; } operator bool () const { - return (bool)QAtomicPointer::load(); + return (bool)QAtomicPointer::LOAD(); } - inline T *operator->() { return QAtomicPointer::load(); } - inline const T *operator->() const { return QAtomicPointer::load(); } + inline T *operator->() { return QAtomicPointer::LOAD(); } + inline const T *operator->() const { return QAtomicPointer::LOAD(); } +#undef LOAD inline bool operator==(const CodeModelPointer &other) const { return (T*)*this == (T*)other; } inline bool operator!=(const CodeModelPointer &other) const { return (T*)*this != (T*)other; } inline bool operator==(const T *ptr) const { return (T*)*this == ptr; } diff --git a/generator/parser/compiler_utils.cpp b/generator/parser/compiler_utils.cpp index 96de701f..d924f26c 100644 --- a/generator/parser/compiler_utils.cpp +++ b/generator/parser/compiler_utils.cpp @@ -59,6 +59,7 @@ TypeInfo CompilerUtils::typeDescription(TypeSpecifierAST *type_specifier, Declar typeInfo.setQualifiedName (type_cc.qualifiedName ()); typeInfo.setConstant (type_cc.isConstant ()); typeInfo.setVolatile (type_cc.isVolatile ()); + typeInfo.setMutable (type_cc.isMutable ()); typeInfo.setReference (decl_cc.isReference ()); typeInfo.setRvalueReference (decl_cc.isRvalueReference ()); typeInfo.setIndirections (decl_cc.indirection ()); diff --git a/generator/parser/compiler_utils.h b/generator/parser/compiler_utils.h index 183ba94d..01c6f913 100644 --- a/generator/parser/compiler_utils.h +++ b/generator/parser/compiler_utils.h @@ -48,7 +48,6 @@ #include "codemodel.h" class QString; -class QStringList; struct TypeSpecifierAST; struct DeclaratorAST; class TokenStream; diff --git a/generator/parser/control.cpp b/generator/parser/control.cpp index a8e6a35e..f76cc4e6 100644 --- a/generator/parser/control.cpp +++ b/generator/parser/control.cpp @@ -43,6 +43,8 @@ #include "control.h" #include "lexer.h" +bool Control::_M_printErrors = false; + Control::Control() : current_context(0), _M_skipFunctionBody(false), @@ -52,7 +54,7 @@ Control::Control() pushContext(); declareTypedef(findOrInsertName("__builtin_va_list", - strlen("__builtin_va_list")), 0); + strlen("__builtin_va_list")), 0); } Control::~Control() @@ -141,7 +143,10 @@ void Control::clearErrorMessages () void Control::reportError (const ErrorMessage &errmsg) { - _M_error_messages.append(errmsg); + _M_error_messages.append(errmsg); + if (_M_printErrors) { + printf("%s (%s:%d:%d)\n", qPrintable(errmsg.message()), qPrintable(errmsg.fileName()), errmsg.line(), errmsg.column()); + } } // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/generator/parser/control.h b/generator/parser/control.h index c3951714..a5274748 100644 --- a/generator/parser/control.h +++ b/generator/parser/control.h @@ -133,6 +133,9 @@ class Control void declareTypedef(const NameSymbol *name, Declarator *d); bool isTypedef(const NameSymbol *name) const; + static bool printErrors() { return _M_printErrors; } + static void setPrintErrors(bool on) { _M_printErrors = on; } + void reportError (const ErrorMessage &errmsg); QList errorMessages () const; void clearErrorMessages (); @@ -141,6 +144,7 @@ class Control NameTable name_table; QHash stl_typedef_table; bool _M_skipFunctionBody; + static bool _M_printErrors; Lexer *_M_lexer; Parser *_M_parser; diff --git a/generator/parser/declarator_compiler.cpp b/generator/parser/declarator_compiler.cpp index 3dff91cc..4aaafeef 100644 --- a/generator/parser/declarator_compiler.cpp +++ b/generator/parser/declarator_compiler.cpp @@ -64,6 +64,7 @@ void DeclaratorCompiler::run(DeclaratorAST *node) _M_reference = false; _M_rvalue_reference = false; _M_variadics = false; + _M_packed_parameter = false; _M_indirection = 0; if (node) @@ -81,6 +82,7 @@ void DeclaratorCompiler::run(DeclaratorAST *node) _M_function = (node->parameter_declaration_clause != 0); if (node->parameter_declaration_clause && node->parameter_declaration_clause->ellipsis) _M_variadics = true; + _M_packed_parameter = node->packedParameter; visitNodes(this, node->ptr_ops); visit(node->parameter_declaration_clause); @@ -135,7 +137,7 @@ void DeclaratorCompiler::visitPtrOperator(PtrOperatorAST *node) if (node->mem_ptr) { #if defined(__GNUC__) -#warning "ptr to mem -- not implemented" +#pragma GCC warning "ptr to mem -- not implemented" #endif } } @@ -151,6 +153,7 @@ void DeclaratorCompiler::visitParameterDeclaration(ParameterDeclarationAST *node p.name = decl_cc.id(); p.type = CompilerUtils::typeDescription(node->type_specifier, node->declarator, _M_binder); + p.packedParameter = decl_cc.isPackedParameter(); // ignore case a single void parameter if (_M_parameters.isEmpty() && p.name.isEmpty() && p.type.toString() == "void") diff --git a/generator/parser/declarator_compiler.h b/generator/parser/declarator_compiler.h index f3d3578d..6337e1ae 100644 --- a/generator/parser/declarator_compiler.h +++ b/generator/parser/declarator_compiler.h @@ -60,9 +60,10 @@ class DeclaratorCompiler: protected DefaultVisitor TypeInfo type; QString name; QString defaultValueExpression; - bool defaultValue; + bool defaultValue{}; + bool packedParameter{}; - Parameter(): defaultValue(false) {} + Parameter() {} }; public: @@ -76,6 +77,7 @@ class DeclaratorCompiler: protected DefaultVisitor inline bool isVariadics() const { return _M_variadics; } inline bool isReference() const { return _M_reference; } inline bool isRvalueReference() const { return _M_rvalue_reference; } + inline bool isPackedParameter() const { return _M_packed_parameter; } inline int indirection() const { return _M_indirection; } inline QList parameters() const { return _M_parameters; } @@ -91,6 +93,7 @@ class DeclaratorCompiler: protected DefaultVisitor bool _M_reference; bool _M_rvalue_reference; bool _M_variadics; + bool _M_packed_parameter; int _M_indirection; QString _M_id; QStringList _M_array; diff --git a/generator/parser/lexer.cpp b/generator/parser/lexer.cpp index c5c70820..c2b59288 100644 --- a/generator/parser/lexer.cpp +++ b/generator/parser/lexer.cpp @@ -142,7 +142,7 @@ void Lexer::tokenize(const char *contents, std::size_t size) line_table.current_line = 1; do { - if (index == token_stream.size()) + if (index >= token_stream.size()-4) // increase size of token_stream early, in case more than one token is written in one go token_stream.resize(token_stream.size() * 2); Token *current_token = &token_stream[(int) index]; @@ -184,13 +184,13 @@ void Lexer::initialize_scan_table() for (int i=0; i<256; ++i) { if (isspace(i)) - s_scan_table[i] = &Lexer::scan_white_spaces; + s_scan_table[i] = &Lexer::scan_white_spaces; else if (isalpha(i) || i == '_') - s_scan_table[i] = &Lexer::scan_identifier_or_keyword; + s_scan_table[i] = &Lexer::scan_identifier_or_keyword; else if (isdigit(i)) - s_scan_table[i] = &Lexer::scan_int_constant; + s_scan_table[i] = &Lexer::scan_int_constant; else - s_scan_table[i] = &Lexer::scan_invalid_input; + s_scan_table[i] = &Lexer::scan_invalid_input; } s_scan_table[int('L')] = &Lexer::scan_identifier_or_literal; @@ -254,7 +254,7 @@ void Lexer::scan_char_constant() reportError("did not expect newline"); if (*cursor == '\\') - ++cursor; + ++cursor; ++cursor; } @@ -280,7 +280,7 @@ void Lexer::scan_string_constant() reportError("did not expect newline"); if (*cursor == '\\') - ++cursor; + ++cursor; ++cursor; } @@ -309,9 +309,9 @@ void Lexer::scan_white_spaces() while (isspace(*cursor)) { if (*cursor == '\n') - scan_newline(); + scan_newline(); else - ++cursor; + ++cursor; } } @@ -348,7 +348,7 @@ void Lexer::scan_identifier_or_keyword() if (current_token->kind == Token_identifier) { current_token->extra.symbol = - control->findOrInsertName((const char*) cursor, n); + control->findOrInsertName((const char*) cursor, n); } cursor = skip; @@ -376,8 +376,8 @@ void Lexer::scan_int_constant() void Lexer::scan_not() { /* - '!' ::= not - '!=' ::= not_equal + '!' ::= not + '!=' ::= not_equal */ ++cursor; @@ -396,8 +396,8 @@ void Lexer::scan_not() void Lexer::scan_remainder() { /* - '%' ::= remainder - '%=' ::= remainder_equal + '%' ::= remainder + '%=' ::= remainder_equal */ ++cursor; @@ -416,9 +416,9 @@ void Lexer::scan_remainder() void Lexer::scan_and() { /* - '&&' ::= and_and - '&' ::= and - '&=' ::= and_equal + '&&' ::= and_and + '&' ::= and + '&=' ::= and_equal */ ++cursor; @@ -453,8 +453,8 @@ void Lexer::scan_right_paren() void Lexer::scan_star() { /* - '*' ::= star - '*=' ::= star_equal + '*' ::= star + '*=' ::= star_equal */ ++cursor; @@ -473,9 +473,9 @@ void Lexer::scan_star() void Lexer::scan_plus() { /* - '+' ::= plus - '++' ::= incr - '+=' ::= plus_equal + '+' ::= plus + '++' ::= incr + '+=' ::= plus_equal */ ++cursor; @@ -504,10 +504,10 @@ void Lexer::scan_comma() void Lexer::scan_minus() { /* - '-' ::= minus - '--' ::= decr - '-=' ::= minus_equal - '->' ::= left_arrow + '-' ::= minus + '--' ::= decr + '-=' ::= minus_equal + '->' ::= left_arrow */ ++cursor; @@ -526,10 +526,10 @@ void Lexer::scan_minus() ++cursor; token_stream[(int) index++].kind = Token_arrow; if (*cursor == '*') - { - ++cursor; - token_stream[(int) index++].kind = Token_ptrmem; - } + { + ++cursor; + token_stream[(int) index++].kind = Token_ptrmem; + } } else { @@ -540,8 +540,8 @@ void Lexer::scan_minus() void Lexer::scan_dot() { /* - '.' ::= dot - '...' ::= ellipsis + '.' ::= dot + '...' ::= ellipsis */ ++cursor; @@ -562,8 +562,8 @@ void Lexer::scan_dot() void Lexer::scan_divide() { /* - '/' ::= divide - '/=' ::= divide_equal + '/' ::= divide + '/=' ::= divide_equal */ ++cursor; @@ -602,10 +602,10 @@ void Lexer::scan_semicolon() void Lexer::scan_less() { /* - '<' ::= less - '<<' ::= left_shift - '<<=' ::= left_shift_equal - '<=' ::= less_equal + '<' ::= less + '<<' ::= left_shift + '<<=' ::= left_shift_equal + '<=' ::= less_equal */ ++cursor; @@ -618,14 +618,14 @@ void Lexer::scan_less() { ++cursor; if (*cursor == '=') - { - ++cursor; - token_stream[(int) index++].kind = Token_assign; - } + { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else - { - token_stream[(int) index++].kind = Token_shift; - } + { + token_stream[(int) index++].kind = Token_shift_left; + } } else { @@ -636,8 +636,8 @@ void Lexer::scan_less() void Lexer::scan_equal() { /* - '=' ::= equal - '==' ::= equal_equal + '=' ::= equal + '==' ::= equal_equal */ ++cursor; @@ -655,10 +655,10 @@ void Lexer::scan_equal() void Lexer::scan_greater() { /* - '>' ::= greater - '>=' ::= greater_equal - '>>' ::= right_shift - '>>=' ::= right_shift_equal + '>' ::= greater + '>=' ::= greater_equal + '>>' ::= right_shift + '>>=' ::= right_shift_equal */ ++cursor; @@ -671,14 +671,16 @@ void Lexer::scan_greater() { ++cursor; if (*cursor == '=') - { - ++cursor; - token_stream[(int) index++].kind = Token_assign; - } + { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else - { - token_stream[(int) index++].kind = Token_shift; - } + { + // may be replaced by two ">" during parsing + token_stream[(int) index++].kind = Token_shift_right; + token_stream[(int) index++].kind = Token_placeholder; + } } else { @@ -707,8 +709,8 @@ void Lexer::scan_right_bracket() void Lexer::scan_xor() { /* - '^' ::= xor - '^=' ::= xor_equal + '^' ::= xor + '^=' ::= xor_equal */ ++cursor; @@ -732,9 +734,9 @@ void Lexer::scan_left_brace() void Lexer::scan_or() { /* - '|' ::= or - '|=' ::= or_equal - '||' ::= or_or + '|' ::= or + '|=' ::= or_equal + '||' ::= or_or */ ++cursor; if (*cursor == '=') @@ -774,13 +776,12 @@ void Lexer::scan_EOF() void Lexer::scan_invalid_input() { QString errmsg("invalid input: %1"); - errmsg.arg(int(*cursor)); - reportError(errmsg); + reportError(errmsg.arg(int(*cursor))); ++cursor; } void LocationTable::positionAt(std::size_t offset, int max_line, - int *line, int *column) const + int *line, int *column) const { if (!(line && column && max_line != 0)) return; @@ -798,13 +799,13 @@ void LocationTable::positionAt(std::size_t offset, int max_line, middle += half; if (lines[middle] < offset) - { - first = middle; - ++first; - len = len - half - 1; - } + { + first = middle; + ++first; + len = len - half - 1; + } else - len = half; + len = half; } *line = std::max(first, 1); @@ -827,26 +828,26 @@ void Lexer::scanKeyword2() { case 'i': if (*(cursor + 1) == 'f') - { - token_stream[(int) index++].kind = Token_if; - return; - } + { + token_stream[(int) index++].kind = Token_if; + return; + } break; case 'd': if (*(cursor + 1) == 'o') - { - token_stream[(int) index++].kind = Token_do; - return; - } + { + token_stream[(int) index++].kind = Token_do; + return; + } break; case 'o': if (*(cursor + 1) == 'r') - { - token_stream[(int) index++].kind = Token_or; - return; - } + { + token_stream[(int) index++].kind = Token_or; + return; + } break; } @@ -859,68 +860,68 @@ void Lexer::scanKeyword3() { case 'a': if (*(cursor + 1) == 'n' && - *(cursor + 2) == 'd') - { - token_stream[(int) index++].kind = Token_and; - return; - } + *(cursor + 2) == 'd') + { + token_stream[(int) index++].kind = Token_and; + return; + } if (*(cursor + 1) == 's' && - *(cursor + 2) == 'm') - { - token_stream[(int) index++].kind = Token_asm; - return; - } + *(cursor + 2) == 'm') + { + token_stream[(int) index++].kind = Token_asm; + return; + } break; case 'f': if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'r') - { - token_stream[(int) index++].kind = Token_for; - return; - } + *(cursor + 2) == 'r') + { + token_stream[(int) index++].kind = Token_for; + return; + } break; case 'i': if (*(cursor + 1) == 'n' && - *(cursor + 2) == 't') - { - token_stream[(int) index++].kind = Token_int; - return; - } + *(cursor + 2) == 't') + { + token_stream[(int) index++].kind = Token_int; + return; + } break; case 'n': if (*(cursor + 1) == 'e' && - *(cursor + 2) == 'w') - { - token_stream[(int) index++].kind = Token_new; - return; - } + *(cursor + 2) == 'w') + { + token_stream[(int) index++].kind = Token_new; + return; + } if (*(cursor + 1) == 'o' && - *(cursor + 2) == 't') - { - token_stream[(int) index++].kind = Token_not; - return; - } + *(cursor + 2) == 't') + { + token_stream[(int) index++].kind = Token_not; + return; + } break; case 't': if (*(cursor + 1) == 'r' && - *(cursor + 2) == 'y') - { - token_stream[(int) index++].kind = Token_try; - return; - } + *(cursor + 2) == 'y') + { + token_stream[(int) index++].kind = Token_try; + return; + } break; case 'x': if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'r') - { - token_stream[(int) index++].kind = Token_xor; - return; - } + *(cursor + 2) == 'r') + { + token_stream[(int) index++].kind = Token_xor; + return; + } break; } @@ -933,103 +934,103 @@ void Lexer::scanKeyword4() { case 'a': if (*(cursor + 1) == 'u' && - *(cursor + 2) == 't' && - *(cursor + 3) == 'o') - { - token_stream[(int) index++].kind = Token_auto; - return; - } + *(cursor + 2) == 't' && + *(cursor + 3) == 'o') + { + token_stream[(int) index++].kind = Token_auto; + return; + } break; case 'c': if (*(cursor + 1) == 'a' && - *(cursor + 2) == 's' && - *(cursor + 3) == 'e') - { - token_stream[(int) index++].kind = Token_case; - return; - } + *(cursor + 2) == 's' && + *(cursor + 3) == 'e') + { + token_stream[(int) index++].kind = Token_case; + return; + } if (*(cursor + 1) == 'h' && - *(cursor + 2) == 'a' && - *(cursor + 3) == 'r') - { - token_stream[(int) index++].kind = Token_char; - return; - } + *(cursor + 2) == 'a' && + *(cursor + 3) == 'r') + { + token_stream[(int) index++].kind = Token_char; + return; + } break; case 'b': if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'o' && - *(cursor + 3) == 'l') - { - token_stream[(int) index++].kind = Token_bool; - return; - } + *(cursor + 2) == 'o' && + *(cursor + 3) == 'l') + { + token_stream[(int) index++].kind = Token_bool; + return; + } break; case 'e': if (*(cursor + 1) == 'l' && - *(cursor + 2) == 's' && - *(cursor + 3) == 'e') - { - token_stream[(int) index++].kind = Token_else; - return; - } + *(cursor + 2) == 's' && + *(cursor + 3) == 'e') + { + token_stream[(int) index++].kind = Token_else; + return; + } if (*(cursor + 1) == 'm' && - *(cursor + 2) == 'i' && - *(cursor + 3) == 't') - { - token_stream[(int) index++].kind = Token_emit; - return; - } + *(cursor + 2) == 'i' && + *(cursor + 3) == 't') + { + token_stream[(int) index++].kind = Token_emit; + return; + } if (*(cursor + 1) == 'n' && - *(cursor + 2) == 'u' && - *(cursor + 3) == 'm') - { - token_stream[(int) index++].kind = Token_enum; - return; - } + *(cursor + 2) == 'u' && + *(cursor + 3) == 'm') + { + token_stream[(int) index++].kind = Token_enum; + return; + } break; case 'g': if (*(cursor + 1) == 'o' && - *(cursor + 2) == 't' && - *(cursor + 3) == 'o') - { - token_stream[(int) index++].kind = Token_goto; - return; - } + *(cursor + 2) == 't' && + *(cursor + 3) == 'o') + { + token_stream[(int) index++].kind = Token_goto; + return; + } break; case 'l': if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'n' && - *(cursor + 3) == 'g') - { - token_stream[(int) index++].kind = Token_long; - return; - } + *(cursor + 2) == 'n' && + *(cursor + 3) == 'g') + { + token_stream[(int) index++].kind = Token_long; + return; + } break; case 't': if (*(cursor + 1) == 'h' && - *(cursor + 2) == 'i' && - *(cursor + 3) == 's') - { - token_stream[(int) index++].kind = Token_this; - return; - } + *(cursor + 2) == 'i' && + *(cursor + 3) == 's') + { + token_stream[(int) index++].kind = Token_this; + return; + } break; case 'v': if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'i' && - *(cursor + 3) == 'd') - { - token_stream[(int) index++].kind = Token_void; - return; - } + *(cursor + 2) == 'i' && + *(cursor + 3) == 'd') + { + token_stream[(int) index++].kind = Token_void; + return; + } break; } @@ -1042,138 +1043,138 @@ void Lexer::scanKeyword5() { case 'c': if (*(cursor + 1) == 'a' && - *(cursor + 2) == 't' && - *(cursor + 3) == 'c' && - *(cursor + 4) == 'h') - { - token_stream[(int) index++].kind = Token_catch; - return; - } + *(cursor + 2) == 't' && + *(cursor + 3) == 'c' && + *(cursor + 4) == 'h') + { + token_stream[(int) index++].kind = Token_catch; + return; + } if (*(cursor + 1) == 'l' && - *(cursor + 2) == 'a' && - *(cursor + 3) == 's' && - *(cursor + 4) == 's') - { - token_stream[(int) index++].kind = Token_class; - return; - } + *(cursor + 2) == 'a' && + *(cursor + 3) == 's' && + *(cursor + 4) == 's') + { + token_stream[(int) index++].kind = Token_class; + return; + } if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'm' && - *(cursor + 3) == 'p' && - *(cursor + 4) == 'l') - { - token_stream[(int) index++].kind = Token_compl; - return; - } + *(cursor + 2) == 'm' && + *(cursor + 3) == 'p' && + *(cursor + 4) == 'l') + { + token_stream[(int) index++].kind = Token_compl; + return; + } if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'n' && - *(cursor + 3) == 's' && - *(cursor + 4) == 't') - { - token_stream[(int) index++].kind = Token_const; - return; - } + *(cursor + 2) == 'n' && + *(cursor + 3) == 's' && + *(cursor + 4) == 't') + { + token_stream[(int) index++].kind = Token_const; + return; + } break; case 'b': if (*(cursor + 1) == 'i' && - *(cursor + 2) == 't' && - *(cursor + 3) == 'o' && - *(cursor + 4) == 'r') - { - token_stream[(int) index++].kind = Token_bitor; - return; - } + *(cursor + 2) == 't' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'r') + { + token_stream[(int) index++].kind = Token_bitor; + return; + } if (*(cursor + 1) == 'r' && - *(cursor + 2) == 'e' && - *(cursor + 3) == 'a' && - *(cursor + 4) == 'k') - { - token_stream[(int) index++].kind = Token_break; - return; - } + *(cursor + 2) == 'e' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'k') + { + token_stream[(int) index++].kind = Token_break; + return; + } break; case 'f': if (*(cursor + 1) == 'l' && - *(cursor + 2) == 'o' && - *(cursor + 3) == 'a' && - *(cursor + 4) == 't') - { - token_stream[(int) index++].kind = Token_float; - return; - } + *(cursor + 2) == 'o' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 't') + { + token_stream[(int) index++].kind = Token_float; + return; + } break; case 'o': if (*(cursor + 1) == 'r' && - *(cursor + 2) == '_' && - *(cursor + 3) == 'e' && - *(cursor + 4) == 'q') - { - token_stream[(int) index++].kind = Token_or_eq; - return; - } + *(cursor + 2) == '_' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'q') + { + token_stream[(int) index++].kind = Token_or_eq; + return; + } break; case 's': if (*(cursor + 1) == 'h' && - *(cursor + 2) == 'o' && - *(cursor + 3) == 'r' && - *(cursor + 4) == 't') - { - token_stream[(int) index++].kind = Token_short; - return; - } + *(cursor + 2) == 'o' && + *(cursor + 3) == 'r' && + *(cursor + 4) == 't') + { + token_stream[(int) index++].kind = Token_short; + return; + } if (*(cursor + 1) == 'l' && - *(cursor + 2) == 'o' && - *(cursor + 3) == 't' && - *(cursor + 4) == 's') - { - token_stream[(int) index++].kind = Token_slots; - return; - } + *(cursor + 2) == 'o' && + *(cursor + 3) == 't' && + *(cursor + 4) == 's') + { + token_stream[(int) index++].kind = Token_slots; + return; + } break; case 'u': if (*(cursor + 1) == 'n' && - *(cursor + 2) == 'i' && - *(cursor + 3) == 'o' && - *(cursor + 4) == 'n') - { - token_stream[(int) index++].kind = Token_union; - return; - } + *(cursor + 2) == 'i' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'n') + { + token_stream[(int) index++].kind = Token_union; + return; + } if (*(cursor + 1) == 's' && - *(cursor + 2) == 'i' && - *(cursor + 3) == 'n' && - *(cursor + 4) == 'g') - { - token_stream[(int) index++].kind = Token_using; - return; - } + *(cursor + 2) == 'i' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 'g') + { + token_stream[(int) index++].kind = Token_using; + return; + } break; case 't': if (*(cursor + 1) == 'h' && - *(cursor + 2) == 'r' && - *(cursor + 3) == 'o' && - *(cursor + 4) == 'w') - { - token_stream[(int) index++].kind = Token_throw; - return; - } + *(cursor + 2) == 'r' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'w') + { + token_stream[(int) index++].kind = Token_throw; + return; + } break; case 'w': if (*(cursor + 1) == 'h' && - *(cursor + 2) == 'i' && - *(cursor + 3) == 'l' && - *(cursor + 4) == 'e') - { - token_stream[(int) index++].kind = Token_while; - return; - } + *(cursor + 2) == 'i' && + *(cursor + 3) == 'l' && + *(cursor + 4) == 'e') + { + token_stream[(int) index++].kind = Token_while; + return; + } break; } @@ -1186,224 +1187,224 @@ void Lexer::scanKeyword6() { case 'a': if (*(cursor + 1) == 'n' && - *(cursor + 2) == 'd' && - *(cursor + 3) == '_' && - *(cursor + 4) == 'e' && - *(cursor + 5) == 'q') - { - token_stream[(int) index++].kind = Token_and_eq; - return; - } + *(cursor + 2) == 'd' && + *(cursor + 3) == '_' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'q') + { + token_stream[(int) index++].kind = Token_and_eq; + return; + } break; case 'b': if (*(cursor + 1) == 'i' && - *(cursor + 2) == 't' && - *(cursor + 3) == 'a' && - *(cursor + 4) == 'n' && - *(cursor + 5) == 'd') - { - token_stream[(int) index++].kind = Token_bitand; - return; - } + *(cursor + 2) == 't' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'd') + { + token_stream[(int) index++].kind = Token_bitand; + return; + } break; case 'e': if (*(cursor + 1) == 'x' && - *(cursor + 2) == 'p' && - *(cursor + 3) == 'o' && - *(cursor + 4) == 'r' && - *(cursor + 5) == 't') - { - token_stream[(int) index++].kind = Token_export; - return; - } + *(cursor + 2) == 'p' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'r' && + *(cursor + 5) == 't') + { + token_stream[(int) index++].kind = Token_export; + return; + } if (*(cursor + 1) == 'x' && - *(cursor + 2) == 't' && - *(cursor + 3) == 'e' && - *(cursor + 4) == 'r' && - *(cursor + 5) == 'n') - { - token_stream[(int) index++].kind = Token_extern; - return; - } + *(cursor + 2) == 't' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'r' && + *(cursor + 5) == 'n') + { + token_stream[(int) index++].kind = Token_extern; + return; + } break; case 'd': if (*(cursor + 1) == 'e' && - *(cursor + 2) == 'l' && - *(cursor + 3) == 'e' && - *(cursor + 4) == 't' && - *(cursor + 5) == 'e') - { - token_stream[(int) index++].kind = Token_delete; - return; - } + *(cursor + 2) == 'l' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'e') + { + token_stream[(int) index++].kind = Token_delete; + return; + } if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'u' && - *(cursor + 3) == 'b' && - *(cursor + 4) == 'l' && - *(cursor + 5) == 'e') - { - token_stream[(int) index++].kind = Token_double; - return; - } + *(cursor + 2) == 'u' && + *(cursor + 3) == 'b' && + *(cursor + 4) == 'l' && + *(cursor + 5) == 'e') + { + token_stream[(int) index++].kind = Token_double; + return; + } break; case 'f': if (*(cursor + 1) == 'r' && - *(cursor + 2) == 'i' && - *(cursor + 3) == 'e' && - *(cursor + 4) == 'n' && - *(cursor + 5) == 'd') - { - token_stream[(int) index++].kind = Token_friend; - return; - } + *(cursor + 2) == 'i' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'd') + { + token_stream[(int) index++].kind = Token_friend; + return; + } break; case 'i': if (*(cursor + 1) == 'n' && - *(cursor + 2) == 'l' && - *(cursor + 3) == 'i' && - *(cursor + 4) == 'n' && - *(cursor + 5) == 'e') - { - token_stream[(int) index++].kind = Token_inline; - return; - } + *(cursor + 2) == 'l' && + *(cursor + 3) == 'i' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'e') + { + token_stream[(int) index++].kind = Token_inline; + return; + } break; case 'K': if (*(cursor + 1) == '_' && - *(cursor + 2) == 'D' && - *(cursor + 3) == 'C' && - *(cursor + 4) == 'O' && - *(cursor + 5) == 'P') - { - token_stream[(int) index++].kind = Token_K_DCOP; - return; - } + *(cursor + 2) == 'D' && + *(cursor + 3) == 'C' && + *(cursor + 4) == 'O' && + *(cursor + 5) == 'P') + { + token_stream[(int) index++].kind = Token_K_DCOP; + return; + } break; case 'n': if (*(cursor + 1) == 'o' && - *(cursor + 2) == 't' && - *(cursor + 3) == '_' && - *(cursor + 4) == 'e' && - *(cursor + 5) == 'q') - { - token_stream[(int) index++].kind = Token_not_eq; - return; - } + *(cursor + 2) == 't' && + *(cursor + 3) == '_' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'q') + { + token_stream[(int) index++].kind = Token_not_eq; + return; + } break; case 'p': if (*(cursor + 1) == 'u' && - *(cursor + 2) == 'b' && - *(cursor + 3) == 'l' && - *(cursor + 4) == 'i' && - *(cursor + 5) == 'c') - { - token_stream[(int) index++].kind = Token_public; - return; - } + *(cursor + 2) == 'b' && + *(cursor + 3) == 'l' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c') + { + token_stream[(int) index++].kind = Token_public; + return; + } break; case 's': if (*(cursor + 1) == 'i' && - *(cursor + 2) == 'g' && - *(cursor + 3) == 'n' && - *(cursor + 4) == 'e' && - *(cursor + 5) == 'd') - { - token_stream[(int) index++].kind = Token_signed; - return; - } + *(cursor + 2) == 'g' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'd') + { + token_stream[(int) index++].kind = Token_signed; + return; + } if (*(cursor + 1) == 'i' && - *(cursor + 2) == 'z' && - *(cursor + 3) == 'e' && - *(cursor + 4) == 'o' && - *(cursor + 5) == 'f') - { - token_stream[(int) index++].kind = Token_sizeof; - return; - } + *(cursor + 2) == 'z' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'o' && + *(cursor + 5) == 'f') + { + token_stream[(int) index++].kind = Token_sizeof; + return; + } if (*(cursor + 1) == 't' && - *(cursor + 2) == 'a' && - *(cursor + 3) == 't' && - *(cursor + 4) == 'i' && - *(cursor + 5) == 'c') - { - token_stream[(int) index++].kind = Token_static; - return; - } + *(cursor + 2) == 'a' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c') + { + token_stream[(int) index++].kind = Token_static; + return; + } if (*(cursor + 1) == 't' && - *(cursor + 2) == 'r' && - *(cursor + 3) == 'u' && - *(cursor + 4) == 'c' && - *(cursor + 5) == 't') - { - token_stream[(int) index++].kind = Token_struct; - return; - } + *(cursor + 2) == 'r' && + *(cursor + 3) == 'u' && + *(cursor + 4) == 'c' && + *(cursor + 5) == 't') + { + token_stream[(int) index++].kind = Token_struct; + return; + } if (*(cursor + 1) == 'w' && - *(cursor + 2) == 'i' && - *(cursor + 3) == 't' && - *(cursor + 4) == 'c' && - *(cursor + 5) == 'h') - { - token_stream[(int) index++].kind = Token_switch; - return; - } + *(cursor + 2) == 'i' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'c' && + *(cursor + 5) == 'h') + { + token_stream[(int) index++].kind = Token_switch; + return; + } break; case 'r': if (*(cursor + 1) == 'e' && - *(cursor + 2) == 't' && - *(cursor + 3) == 'u' && - *(cursor + 4) == 'r' && - *(cursor + 5) == 'n') - { - token_stream[(int) index++].kind = Token_return; - return; - } + *(cursor + 2) == 't' && + *(cursor + 3) == 'u' && + *(cursor + 4) == 'r' && + *(cursor + 5) == 'n') + { + token_stream[(int) index++].kind = Token_return; + return; + } break; case 't': if (*(cursor + 1) == 'y' && - *(cursor + 2) == 'p' && - *(cursor + 3) == 'e' && - *(cursor + 4) == 'i' && - *(cursor + 5) == 'd') - { - token_stream[(int) index++].kind = Token_typeid; - return; - } + *(cursor + 2) == 'p' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'd') + { + token_stream[(int) index++].kind = Token_typeid; + return; + } break; case 'x': if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'r' && - *(cursor + 3) == '_' && - *(cursor + 4) == 'e' && - *(cursor + 5) == 'q') - { - token_stream[(int) index++].kind = Token_xor_eq; - return; - } + *(cursor + 2) == 'r' && + *(cursor + 3) == '_' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'q') + { + token_stream[(int) index++].kind = Token_xor_eq; + return; + } break; case 'k': if (*(cursor + 1) == '_' && - *(cursor + 2) == 'd' && - *(cursor + 3) == 'c' && - *(cursor + 4) == 'o' && - *(cursor + 5) == 'p') - { - token_stream[(int) index++].kind = Token_k_dcop; - return; - } + *(cursor + 2) == 'd' && + *(cursor + 3) == 'c' && + *(cursor + 4) == 'o' && + *(cursor + 5) == 'p') + { + token_stream[(int) index++].kind = Token_k_dcop; + return; + } break; case 'Q': if (*(cursor + 1) == '_' && @@ -1425,80 +1426,92 @@ void Lexer::scanKeyword7() { switch (*cursor) { + case 'a': + if (*(cursor + 1) == 'l' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'g' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'a' && + *(cursor + 6) == 's') + { + token_stream[(int)index++].kind = Token_alignas; + return; + } + break; case 'd': if (*(cursor + 1) == 'e' && - *(cursor + 2) == 'f' && - *(cursor + 3) == 'a' && - *(cursor + 4) == 'u' && - *(cursor + 5) == 'l' && - *(cursor + 6) == 't') - { - token_stream[(int) index++].kind = Token_default; - return; - } + *(cursor + 2) == 'f' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'u' && + *(cursor + 5) == 'l' && + *(cursor + 6) == 't') + { + token_stream[(int) index++].kind = Token_default; + return; + } break; case 'm': if (*(cursor + 1) == 'u' && - *(cursor + 2) == 't' && - *(cursor + 3) == 'a' && - *(cursor + 4) == 'b' && - *(cursor + 5) == 'l' && - *(cursor + 6) == 'e') - { - token_stream[(int) index++].kind = Token_mutable; - return; - } + *(cursor + 2) == 't' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'b' && + *(cursor + 5) == 'l' && + *(cursor + 6) == 'e') + { + token_stream[(int) index++].kind = Token_mutable; + return; + } break; case 'p': if (*(cursor + 1) == 'r' && - *(cursor + 2) == 'i' && - *(cursor + 3) == 'v' && - *(cursor + 4) == 'a' && - *(cursor + 5) == 't' && - *(cursor + 6) == 'e') - { - token_stream[(int) index++].kind = Token_private; - return; - } + *(cursor + 2) == 'i' && + *(cursor + 3) == 'v' && + *(cursor + 4) == 'a' && + *(cursor + 5) == 't' && + *(cursor + 6) == 'e') + { + token_stream[(int) index++].kind = Token_private; + return; + } break; case 's': if (*(cursor + 1) == 'i' && - *(cursor + 2) == 'g' && - *(cursor + 3) == 'n' && - *(cursor + 4) == 'a' && - *(cursor + 5) == 'l' && - *(cursor + 6) == 's') - { - token_stream[(int) index++].kind = Token_signals; - return; - } + *(cursor + 2) == 'g' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 'a' && + *(cursor + 5) == 'l' && + *(cursor + 6) == 's') + { + token_stream[(int) index++].kind = Token_signals; + return; + } break; case 't': if (*(cursor + 1) == 'y' && - *(cursor + 2) == 'p' && - *(cursor + 3) == 'e' && - *(cursor + 4) == 'd' && - *(cursor + 5) == 'e' && - *(cursor + 6) == 'f') - { - token_stream[(int) index++].kind = Token_typedef; - return; - } + *(cursor + 2) == 'p' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'd' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'f') + { + token_stream[(int) index++].kind = Token_typedef; + return; + } break; case 'v': if (*(cursor + 1) == 'i' && - *(cursor + 2) == 'r' && - *(cursor + 3) == 't' && - *(cursor + 4) == 'u' && - *(cursor + 5) == 'a' && - *(cursor + 6) == 'l') - { - token_stream[(int) index++].kind = Token_virtual; - return; - } + *(cursor + 2) == 'r' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'u' && + *(cursor + 5) == 'a' && + *(cursor + 6) == 'l') + { + token_stream[(int) index++].kind = Token_virtual; + return; + } break; case 'Q': @@ -1524,139 +1537,167 @@ void Lexer::scanKeyword8() { case '_': if (*(cursor + 1) == '_' && - *(cursor + 2) == 't' && - *(cursor + 3) == 'y' && - *(cursor + 4) == 'p' && - *(cursor + 5) == 'e' && - *(cursor + 6) == 'o' && - *(cursor + 7) == 'f') - { - token_stream[(int) index++].kind = Token___typeof; - return; - } + *(cursor + 2) == 't' && + *(cursor + 3) == 'y' && + *(cursor + 4) == 'p' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'o' && + *(cursor + 7) == 'f') + { + token_stream[(int) index++].kind = Token___typeof; + return; + } break; case 'c': if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'n' && - *(cursor + 3) == 't' && - *(cursor + 4) == 'i' && - *(cursor + 5) == 'n' && - *(cursor + 6) == 'u' && - *(cursor + 7) == 'e') - { - token_stream[(int) index++].kind = Token_continue; - return; - } + *(cursor + 2) == 'n' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'n' && + *(cursor + 6) == 'u' && + *(cursor + 7) == 'e') + { + token_stream[(int) index++].kind = Token_continue; + return; + } + break; + + case 'd': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'c' && + *(cursor + 3) == 'l' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'y' && + *(cursor + 6) == 'p' && + *(cursor + 7) == 'e') + { + token_stream[(int) index++].kind = Token_decltype; + return; + } break; case 'e': if (*(cursor + 1) == 'x' && - *(cursor + 2) == 'p' && - *(cursor + 3) == 'l' && - *(cursor + 4) == 'i' && - *(cursor + 5) == 'c' && - *(cursor + 6) == 'i' && - *(cursor + 7) == 't') - { - token_stream[(int) index++].kind = Token_explicit; - return; - } + *(cursor + 2) == 'p' && + *(cursor + 3) == 'l' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c' && + *(cursor + 6) == 'i' && + *(cursor + 7) == 't') + { + token_stream[(int) index++].kind = Token_explicit; + return; + } + break; + + case 'n': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'e' && + *(cursor + 3) == 'x' && + *(cursor + 4) == 'c' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'p' && + *(cursor + 7) == 't') + { + token_stream[(int) index++].kind = Token_noexcept; + return; + } break; case 'o': if (*(cursor + 1) == 'p' && - *(cursor + 2) == 'e' && - *(cursor + 3) == 'r' && - *(cursor + 4) == 'a' && - *(cursor + 5) == 't' && - *(cursor + 6) == 'o' && - *(cursor + 7) == 'r') - { - token_stream[(int) index++].kind = Token_operator; - return; - } + *(cursor + 2) == 'e' && + *(cursor + 3) == 'r' && + *(cursor + 4) == 'a' && + *(cursor + 5) == 't' && + *(cursor + 6) == 'o' && + *(cursor + 7) == 'r') + { + token_stream[(int) index++].kind = Token_operator; + return; + } break; case 'Q': if (*(cursor + 1) == '_' && - *(cursor + 2) == 'O' && - *(cursor + 3) == 'B' && - *(cursor + 4) == 'J' && - *(cursor + 5) == 'E' && - *(cursor + 6) == 'C' && - *(cursor + 7) == 'T') - { - token_stream[(int) index++].kind = Token_Q_OBJECT; - return; - } + *(cursor + 2) == 'O' && + *(cursor + 3) == 'B' && + *(cursor + 4) == 'J' && + *(cursor + 5) == 'E' && + *(cursor + 6) == 'C' && + *(cursor + 7) == 'T') + { + token_stream[(int) index++].kind = Token_Q_OBJECT; + return; + } break; case 'r': if (*(cursor + 1) == 'e' && - *(cursor + 2) == 'g' && - *(cursor + 3) == 'i' && - *(cursor + 4) == 's' && - *(cursor + 5) == 't' && - *(cursor + 6) == 'e' && - *(cursor + 7) == 'r') - { - token_stream[(int) index++].kind = Token_register; - return; - } + *(cursor + 2) == 'g' && + *(cursor + 3) == 'i' && + *(cursor + 4) == 's' && + *(cursor + 5) == 't' && + *(cursor + 6) == 'e' && + *(cursor + 7) == 'r') + { + token_stream[(int) index++].kind = Token_register; + return; + } break; case 'u': if (*(cursor + 1) == 'n' && - *(cursor + 2) == 's' && - *(cursor + 3) == 'i' && - *(cursor + 4) == 'g' && - *(cursor + 5) == 'n' && - *(cursor + 6) == 'e' && - *(cursor + 7) == 'd') - { - token_stream[(int) index++].kind = Token_unsigned; - return; - } + *(cursor + 2) == 's' && + *(cursor + 3) == 'i' && + *(cursor + 4) == 'g' && + *(cursor + 5) == 'n' && + *(cursor + 6) == 'e' && + *(cursor + 7) == 'd') + { + token_stream[(int) index++].kind = Token_unsigned; + return; + } break; case 't': if (*(cursor + 1) == 'e' && - *(cursor + 2) == 'm' && - *(cursor + 3) == 'p' && - *(cursor + 4) == 'l' && - *(cursor + 5) == 'a' && - *(cursor + 6) == 't' && - *(cursor + 7) == 'e') - { - token_stream[(int) index++].kind = Token_template; - return; - } + *(cursor + 2) == 'm' && + *(cursor + 3) == 'p' && + *(cursor + 4) == 'l' && + *(cursor + 5) == 'a' && + *(cursor + 6) == 't' && + *(cursor + 7) == 'e') + { + token_stream[(int) index++].kind = Token_template; + return; + } if (*(cursor + 1) == 'y' && - *(cursor + 2) == 'p' && - *(cursor + 3) == 'e' && - *(cursor + 4) == 'n' && - *(cursor + 5) == 'a' && - *(cursor + 6) == 'm' && - *(cursor + 7) == 'e') - { - token_stream[(int) index++].kind = Token_typename; - return; - } + *(cursor + 2) == 'p' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'a' && + *(cursor + 6) == 'm' && + *(cursor + 7) == 'e') + { + token_stream[(int) index++].kind = Token_typename; + return; + } break; case 'v': if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'l' && - *(cursor + 3) == 'a' && - *(cursor + 4) == 't' && - *(cursor + 5) == 'i' && - *(cursor + 6) == 'l' && - *(cursor + 7) == 'e') - { - token_stream[(int) index++].kind = Token_volatile; - return; - } + *(cursor + 2) == 'l' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'i' && + *(cursor + 6) == 'l' && + *(cursor + 7) == 'e') + { + token_stream[(int) index++].kind = Token_volatile; + return; + } break; } @@ -1667,34 +1708,49 @@ void Lexer::scanKeyword9() { switch (*cursor) { + case 'c': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'n' && + *(cursor + 3) == 's' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'x' && + *(cursor + 7) == 'p' && + *(cursor + 8) == 'r') + { + token_stream[(int) index++].kind = Token_constexpr; + return; + } + break; + case 'p': if (*(cursor + 1) == 'r' && - *(cursor + 2) == 'o' && - *(cursor + 3) == 't' && - *(cursor + 4) == 'e' && - *(cursor + 5) == 'c' && - *(cursor + 6) == 't' && - *(cursor + 7) == 'e' && - *(cursor + 8) == 'd') - { - token_stream[(int) index++].kind = Token_protected; - return; - } + *(cursor + 2) == 'o' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'c' && + *(cursor + 6) == 't' && + *(cursor + 7) == 'e' && + *(cursor + 8) == 'd') + { + token_stream[(int) index++].kind = Token_protected; + return; + } break; case 'n': if (*(cursor + 1) == 'a' && - *(cursor + 2) == 'm' && - *(cursor + 3) == 'e' && - *(cursor + 4) == 's' && - *(cursor + 5) == 'p' && - *(cursor + 6) == 'a' && - *(cursor + 7) == 'c' && - *(cursor + 8) == 'e') - { - token_stream[(int) index++].kind = Token_namespace; - return; - } + *(cursor + 2) == 'm' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 's' && + *(cursor + 5) == 'p' && + *(cursor + 6) == 'a' && + *(cursor + 7) == 'c' && + *(cursor + 8) == 'e') + { + token_stream[(int) index++].kind = Token_namespace; + return; + } break; } @@ -1707,18 +1763,18 @@ void Lexer::scanKeyword10() { case 'c': if (*(cursor + 1) == 'o' && - *(cursor + 2) == 'n' && - *(cursor + 3) == 's' && - *(cursor + 4) == 't' && - *(cursor + 5) == '_' && - *(cursor + 6) == 'c' && - *(cursor + 7) == 'a' && - *(cursor + 8) == 's' && - *(cursor + 9) == 't') - { - token_stream[(int) index++].kind = Token_const_cast; - return; - } + *(cursor + 2) == 'n' && + *(cursor + 3) == 's' && + *(cursor + 4) == 't' && + *(cursor + 5) == '_' && + *(cursor + 6) == 'c' && + *(cursor + 7) == 'a' && + *(cursor + 8) == 's' && + *(cursor + 9) == 't') + { + token_stream[(int) index++].kind = Token_const_cast; + return; + } break; case 'Q': @@ -1748,36 +1804,36 @@ void Lexer::scanKeyword11() { case 'Q': if (*(cursor + 1) == '_' && - *(cursor + 2) == 'I' && - *(cursor + 3) == 'N' && - *(cursor + 4) == 'V' && - *(cursor + 5) == 'O' && - *(cursor + 6) == 'K' && - *(cursor + 7) == 'A' && - *(cursor + 8) == 'B' && - *(cursor + 9) == 'L' && - *(cursor + 10) == 'E') - { - token_stream[(int) index++].kind = Token_Q_INVOKABLE; - return; - } + *(cursor + 2) == 'I' && + *(cursor + 3) == 'N' && + *(cursor + 4) == 'V' && + *(cursor + 5) == 'O' && + *(cursor + 6) == 'K' && + *(cursor + 7) == 'A' && + *(cursor + 8) == 'B' && + *(cursor + 9) == 'L' && + *(cursor + 10) == 'E') + { + token_stream[(int) index++].kind = Token_Q_INVOKABLE; + return; + } break; case 's': if (*(cursor + 1) == 't' && - *(cursor + 2) == 'a' && - *(cursor + 3) == 't' && - *(cursor + 4) == 'i' && - *(cursor + 5) == 'c' && - *(cursor + 6) == '_' && - *(cursor + 7) == 'c' && - *(cursor + 8) == 'a' && - *(cursor + 9) == 's' && - *(cursor + 10) == 't') - { - token_stream[(int) index++].kind = Token_static_cast; - return; - } + *(cursor + 2) == 'a' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c' && + *(cursor + 6) == '_' && + *(cursor + 7) == 'c' && + *(cursor + 8) == 'a' && + *(cursor + 9) == 's' && + *(cursor + 10) == 't') + { + token_stream[(int) index++].kind = Token_static_cast; + return; + } break; } @@ -1790,20 +1846,20 @@ void Lexer::scanKeyword12() { case 'd': if (*(cursor + 1) == 'y' && - *(cursor + 2) == 'n' && - *(cursor + 3) == 'a' && - *(cursor + 4) == 'm' && - *(cursor + 5) == 'i' && - *(cursor + 6) == 'c' && - *(cursor + 7) == '_' && - *(cursor + 8) == 'c' && - *(cursor + 9) == 'a' && - *(cursor + 10) == 's' && - *(cursor + 11) == 't') - { - token_stream[(int) index++].kind = Token_dynamic_cast; - return; - } + *(cursor + 2) == 'n' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'm' && + *(cursor + 5) == 'i' && + *(cursor + 6) == 'c' && + *(cursor + 7) == '_' && + *(cursor + 8) == 'c' && + *(cursor + 9) == 'a' && + *(cursor + 10) == 's' && + *(cursor + 11) == 't') + { + token_stream[(int) index++].kind = Token_dynamic_cast; + return; + } break; } @@ -1816,21 +1872,21 @@ void Lexer::scanKeyword13() { case '_': if (*(cursor + 1) == '_' && - *(cursor + 2) == 'a' && - *(cursor + 3) == 't' && - *(cursor + 4) == 't' && - *(cursor + 5) == 'r' && - *(cursor + 6) == 'i' && - *(cursor + 7) == 'b' && - *(cursor + 8) == 'u' && - *(cursor + 9) == 't' && - *(cursor + 10) == 'e' && - *(cursor + 11) == '_' && - *(cursor + 12) == '_') - { - token_stream[(int) index++].kind = Token___attribute__; - return; - } + *(cursor + 2) == 'a' && + *(cursor + 3) == 't' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'r' && + *(cursor + 6) == 'i' && + *(cursor + 7) == 'b' && + *(cursor + 8) == 'u' && + *(cursor + 9) == 't' && + *(cursor + 10) == 'e' && + *(cursor + 11) == '_' && + *(cursor + 12) == '_') + { + token_stream[(int) index++].kind = Token___attribute__; + return; + } break; } token_stream[(int) index++].kind = Token_identifier; @@ -1842,22 +1898,22 @@ void Lexer::scanKeyword14() { case 'k': if (*(cursor + 1) == '_' && - *(cursor + 2) == 'd' && - *(cursor + 3) == 'c' && - *(cursor + 4) == 'o' && - *(cursor + 5) == 'p' && - *(cursor + 6) == '_' && - *(cursor + 7) == 's' && - *(cursor + 8) == 'i' && - *(cursor + 9) == 'g' && - *(cursor + 10) == 'n' && - *(cursor + 11) == 'a' && - *(cursor + 12) == 'l' && - *(cursor + 13) == 's') - { - token_stream[(int) index++].kind = Token_k_dcop_signals; - return; - } + *(cursor + 2) == 'd' && + *(cursor + 3) == 'c' && + *(cursor + 4) == 'o' && + *(cursor + 5) == 'p' && + *(cursor + 6) == '_' && + *(cursor + 7) == 's' && + *(cursor + 8) == 'i' && + *(cursor + 9) == 'g' && + *(cursor + 10) == 'n' && + *(cursor + 11) == 'a' && + *(cursor + 12) == 'l' && + *(cursor + 13) == 's') + { + token_stream[(int) index++].kind = Token_k_dcop_signals; + return; + } break; } token_stream[(int) index++].kind = Token_identifier; @@ -1869,24 +1925,24 @@ void Lexer::scanKeyword16() { case 'r': if (*(cursor + 1) == 'e' && - *(cursor + 2) == 'i' && - *(cursor + 3) == 'n' && - *(cursor + 4) == 't' && - *(cursor + 5) == 'e' && - *(cursor + 6) == 'r' && - *(cursor + 7) == 'p' && - *(cursor + 8) == 'r' && - *(cursor + 9) == 'e' && - *(cursor + 10) == 't' && - *(cursor + 11) == '_' && - *(cursor + 12) == 'c' && - *(cursor + 13) == 'a' && - *(cursor + 14) == 's' && - *(cursor + 15) == 't') - { - token_stream[(int) index++].kind = Token_reinterpret_cast; - return; - } + *(cursor + 2) == 'i' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'r' && + *(cursor + 7) == 'p' && + *(cursor + 8) == 'r' && + *(cursor + 9) == 'e' && + *(cursor + 10) == 't' && + *(cursor + 11) == '_' && + *(cursor + 12) == 'c' && + *(cursor + 13) == 'a' && + *(cursor + 14) == 's' && + *(cursor + 15) == 't') + { + token_stream[(int) index++].kind = Token_reinterpret_cast; + return; + } break; } diff --git a/generator/parser/lexer.h b/generator/parser/lexer.h index 05158f81..4d440536 100644 --- a/generator/parser/lexer.h +++ b/generator/parser/lexer.h @@ -140,7 +140,7 @@ class TokenStream inline std::size_t cursor() const { return index; } - inline void rewind(int i) + inline void rewind(std::size_t i) { index = i; } void resize(std::size_t size) @@ -168,11 +168,11 @@ class TokenStream inline std::size_t matchingBrace(std::size_t i) const { return tokens[i].extra.right_brace; } - inline Token &operator[](int index) - { return tokens[index]; } + inline Token &operator[](std::size_t i) + { return tokens[i]; } - inline const Token &token(int index) const - { return tokens[index]; } + inline const Token &token(std::size_t i) const + { return tokens[i]; } private: Token *tokens; diff --git a/generator/parser/list.h b/generator/parser/list.h index 71181924..c7ef9e28 100644 --- a/generator/parser/list.h +++ b/generator/parser/list.h @@ -105,7 +105,7 @@ struct ListNode template inline const ListNode *snoc(const ListNode *list, - const Tp &element, pool *p) + const Tp &element, pool *p) { if (!list) return ListNode::create(element, p); diff --git a/generator/parser/name_compiler.cpp b/generator/parser/name_compiler.cpp index 75dc3247..7e136b4d 100644 --- a/generator/parser/name_compiler.cpp +++ b/generator/parser/name_compiler.cpp @@ -80,7 +80,7 @@ void NameCompiler::visitUnqualifiedName(UnqualifiedNameAST *node) if (OperatorFunctionIdAST *op_id = node->operator_id) { #if defined(__GNUC__) -#warning "NameCompiler::visitUnqualifiedName() -- implement me" +#pragma GCC warning "NameCompiler::visitUnqualifiedName() -- implement me" #endif if (op_id->op && op_id->op->op) @@ -93,7 +93,7 @@ void NameCompiler::visitUnqualifiedName(UnqualifiedNameAST *node) else if (op_id->type_specifier) { #if defined(__GNUC__) -#warning "don't use an hardcoded string as cast' name" +#pragma GCC warning "don't use an hardcoded string as cast' name" #endif Token const &tk = _M_token_stream->token ((int) op_id->start_token); Token const &end_tk = _M_token_stream->token ((int) op_id->end_token); diff --git a/generator/parser/parser.cpp b/generator/parser/parser.cpp index a9dc0bd8..b115aeb5 100644 --- a/generator/parser/parser.cpp +++ b/generator/parser/parser.cpp @@ -50,6 +50,7 @@ #include #include +#include #define ADVANCE(tk, descr) \ { \ @@ -57,7 +58,7 @@ tokenRequiredError(tk); \ return false; \ } \ - token_stream.nextToken(); \ + nextToken(); \ } #define ADVANCE_NR(tk, descr) \ @@ -66,7 +67,7 @@ tokenRequiredError(tk); \ } \ else \ - token_stream.nextToken(); \ + nextToken(); \ } while (0) #define CHECK(tk) \ @@ -74,7 +75,7 @@ if (token_stream.lookAhead() != tk) { \ return false; \ } \ - token_stream.nextToken(); \ + nextToken(); \ } while (0) #define UPDATE_POS(_node, start, end) \ @@ -95,9 +96,16 @@ Parser::~Parser() { } -void Parser::advance() +void Parser::nextToken() { token_stream.nextToken(); + keepTrackDebug(); +} + +void Parser::rewind(std::size_t pos) +{ + token_stream.rewind(pos); + keepTrackDebug(); } TranslationUnitAST *Parser::parse(const char *contents, @@ -106,7 +114,7 @@ TranslationUnitAST *Parser::parse(const char *contents, _M_block_errors = false; _M_pool = p; lexer.tokenize(contents, size); - token_stream.nextToken(); // skip the first token + nextToken(); // skip the first token Lexer *oldLexer = control->changeLexer (&lexer); Parser *oldParser = control->changeParser (this); @@ -133,20 +141,20 @@ bool Parser::parseWinDeclSpec(WinDeclSpecAST *&node) return false; std::size_t specifier = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); if (token_stream.lookAhead() != '(') return false; - token_stream.nextToken(); + nextToken(); if (token_stream.lookAhead() != Token_identifier) return false; std::size_t modifier = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); if (token_stream.lookAhead() != ')') return false; - token_stream.nextToken(); + nextToken(); node = CreateNode(_M_pool); node->specifier = specifier; @@ -168,6 +176,7 @@ void Parser::tokenRequiredError(int token) err += token_name(token_stream.lookAhead()); err += "''"; + reportError(err); } @@ -203,6 +212,79 @@ void Parser::reportError(const QString& msg) } } +void Parser::keepTrackDebug() +{ +#ifndef NDEBUG + std::size_t tok = token_stream.cursor(); + location().positionAt(token_stream.position(tok), + &_currentLine, &_currentColumn, &_currentFile); + _currentToken = token_name(token_stream.lookAhead()); + if (token_stream.lookAhead() == Token_identifier) + { + _currentSymbol = token_stream.symbol(tok)->as_string(); + } + else + { + _currentSymbol = ""; + } +#endif +} + +bool Parser::skipAlignas() +{ + // we are currently not interested in alignas, so we just skip it + if (token_stream.lookAhead() == Token_alignas) + { + nextToken(); + if (token_stream.lookAhead() == '(') + { + if (skip('(', ')')) + { + nextToken(); + } + } + return true; + } + return false; +} + +bool Parser::skipAttributes() +{ + bool any = false; + while (true) { + if (token_stream.lookAhead() == Token___attribute__) + { + parse_Attribute__(); + any = true; + } + else if (token_stream.lookAhead() == '[' && token_stream.lookAhead(1) == '[') + { + nextToken(); + while (true) + { + nextToken(); + int tk = token_stream.lookAhead(); + if (tk == Token_EOF) + { + break; + } + else if (tk == ']' && token_stream.lookAhead(1) == ']') // this has no separate token because "]]" can occur in other contexts + { + nextToken(); + nextToken(); + break; + } + } + any = true; + } + else + { + break; + } + } + return any; +} + bool Parser::skipUntil(int token) { while (token_stream.lookAhead()) @@ -210,7 +292,7 @@ bool Parser::skipUntil(int token) if (token_stream.lookAhead() == token) return true; - token_stream.nextToken(); + nextToken(); } return false; @@ -248,7 +330,9 @@ bool Parser::skipUntilDeclaration() case Token_export: case Token_const: // cv + case Token_constexpr: // cv case Token_volatile: // cv + case Token_mutable: // cv case Token_public: case Token_protected: @@ -257,8 +341,13 @@ bool Parser::skipUntilDeclaration() case Token_slots: // Qt return true; + case Token_decltype: + case Token___typeof: + reportError("C++11 decltype/__typeof(id|expression) not handled"); + return true; + default: - token_stream.nextToken(); + nextToken(); } } @@ -275,7 +364,11 @@ bool Parser::skipUntilStatement() case '{': case '}': case Token_const: + case Token_constexpr: + case Token_decltype: + case Token___typeof: case Token_volatile: + case Token_mutable: case Token_identifier: case Token_case: case Token_default: @@ -312,7 +405,7 @@ bool Parser::skipUntilStatement() return true; default: - token_stream.nextToken(); + nextToken(); } } @@ -336,7 +429,7 @@ bool Parser::skip(int l, int r) if (count == 0) return true; - token_stream.nextToken(); + nextToken(); } return false; @@ -347,14 +440,17 @@ bool Parser::parseName(NameAST *&node, bool acceptTemplateId) std::size_t start = token_stream.cursor(); WinDeclSpecAST *winDeclSpec = 0; - parseWinDeclSpec(winDeclSpec); + while (skipAlignas() || (!winDeclSpec && parseWinDeclSpec(winDeclSpec))) + { + ; + } NameAST *ast = CreateNode(_M_pool); if (token_stream.lookAhead() == Token_scope) { ast->global = true; - token_stream.nextToken(); + nextToken(); } std::size_t idx = token_stream.cursor(); @@ -362,12 +458,12 @@ bool Parser::parseName(NameAST *&node, bool acceptTemplateId) while (true) { UnqualifiedNameAST *n = 0; - if (!parseUnqualifiedName(n)) + if (!parseUnqualifiedName(n, acceptTemplateId)) return false; if (token_stream.lookAhead() == Token_scope) { - token_stream.nextToken(); + nextToken(); ast->qualified_names = snoc(ast->qualified_names, n, _M_pool); @@ -375,18 +471,12 @@ bool Parser::parseName(NameAST *&node, bool acceptTemplateId) if (token_stream.lookAhead() == Token_template) { /// skip optional template #### @todo CHECK - token_stream.nextToken(); + nextToken(); } } else { Q_ASSERT(n != 0); - if (!acceptTemplateId) - { - token_stream.rewind((int) n->start_token); - parseUnqualifiedName(n, false); - } - ast->unqualified_name = n; break; } @@ -422,7 +512,7 @@ bool Parser::parseTranslationUnit(TranslationUnitAST *&node) if (startDecl == token_stream.cursor()) { // skip at least one token - token_stream.nextToken(); + nextToken(); } skipUntilDeclaration(); @@ -442,7 +532,10 @@ bool Parser::parseDeclaration(DeclarationAST *&node) switch(token_stream.lookAhead()) { case ';': - token_stream.nextToken(); + // ignore ellipse in constructs like + // using T1 = T2...>; + case Token_ellipsis: + nextToken(); return true; case Token_extern: @@ -470,15 +563,25 @@ bool Parser::parseDeclaration(DeclarationAST *&node) case Token_export: return parseTemplateDeclaration(node); + case Token_inline: + if (token_stream.lookAhead(1) == Token_namespace) + { + nextToken(); + // handle like a normal namespace for now + return parseNamespace(node); + } + // else fallthrough default: { - const ListNode *cv = 0; - parseCvQualify(cv); + skipAttributes(); - const ListNode *storageSpec = 0; - parseStorageClassSpecifier(storageSpec); - - parseCvQualify(cv); + const ListNode *cv = 0; + const ListNode* storageSpec = 0; + // consume all qualifiers/specifiers + while (parseCvQualify(cv) || parseStorageClassSpecifier(storageSpec)) + { + ; + } TypeSpecifierAST *spec = 0; if (parseEnumSpecifier(spec) @@ -507,7 +610,7 @@ bool Parser::parseDeclaration(DeclarationAST *&node) } } // end switch - token_stream.rewind((int) start); + rewind(start); return parseDeclarationInternal(node); } @@ -522,7 +625,7 @@ bool Parser::parseLinkageSpecification(DeclarationAST *&node) if (token_stream.lookAhead() == Token_string_literal) { ast->extern_type = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } if (token_stream.lookAhead() == '{') @@ -568,7 +671,7 @@ bool Parser::parseLinkageBody(LinkageBodyAST *&node) if (startDecl == token_stream.cursor()) { // skip at least one token - token_stream.nextToken(); + nextToken(); } skipUntilDeclaration(); @@ -578,7 +681,7 @@ bool Parser::parseLinkageBody(LinkageBodyAST *&node) if (token_stream.lookAhead() != '}') reportError(("} expected")); else - token_stream.nextToken(); + nextToken(); UPDATE_POS(ast, start, token_stream.cursor()); node = ast; @@ -596,13 +699,13 @@ bool Parser::parseNamespace(DeclarationAST *&node) if (token_stream.lookAhead() == Token_identifier) { namespace_name = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } if (token_stream.lookAhead() == '=') { // namespace alias - token_stream.nextToken(); + nextToken(); NameAST *name = 0; if (parseName(name)) @@ -645,6 +748,11 @@ bool Parser::parseUsing(DeclarationAST *&node) CHECK(Token_using); + if (token_stream.lookAhead(1) == '=') + { + return parseUsingTypedef(node); + } + if (token_stream.lookAhead() == Token_namespace) return parseUsingDirective(node); @@ -653,10 +761,10 @@ bool Parser::parseUsing(DeclarationAST *&node) if (token_stream.lookAhead() == Token_typename) { ast->type_name = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } - if (!parseName(ast->name)) + if (!parseName(ast->name, /*acceptTemplateId=*/true)) return false; ADVANCE(';', ";"); @@ -667,6 +775,41 @@ bool Parser::parseUsing(DeclarationAST *&node) return true; } +bool Parser::parseUsingTypedef(DeclarationAST*& node) +{ + std::size_t start = token_stream.cursor(); + + DeclaratorAST* decl = 0; + if (!parseDeclarator(decl)) + { + return false; + } + + InitDeclaratorAST* init_decl = CreateNode(_M_pool); + init_decl->declarator = decl; + init_decl->initializer = 0; + const ListNode* declarators = 0; + declarators = snoc(declarators, init_decl, _M_pool); + + ADVANCE('=', "="); + + TypeSpecifierAST* spec = 0; + if (!parseTypeSpecifierOrClassSpec(spec)) + { + reportError(("Need a type specifier to declare")); + return false; + } + + TypedefAST* ast = CreateNode(_M_pool); + ast->type_specifier = spec; + ast->init_declarators = declarators; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + bool Parser::parseUsingDirective(DeclarationAST *&node) { std::size_t start = token_stream.cursor(); @@ -737,7 +880,7 @@ bool Parser::parseTemplateArgumentList(const ListNode *&no while (token_stream.lookAhead() == ',') { - token_stream.nextToken(); + nextToken(); if (!parseTemplateArgument(templArg)) { @@ -799,10 +942,10 @@ bool Parser::parseAsmDefinition(DeclarationAST *&node) parseCvQualify(cv); #if defined(__GNUC__) -#warning "implement me" +#pragma GCC warning "implement me" #endif skip('(', ')'); - token_stream.nextToken(); + nextToken(); ADVANCE(';', ";"); AsmDefinitionAST *ast = CreateNode(_M_pool); @@ -821,7 +964,7 @@ bool Parser::parseTemplateDeclaration(DeclarationAST *&node) if (token_stream.lookAhead() == Token_export) { exported = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } CHECK(Token_template); @@ -829,9 +972,10 @@ bool Parser::parseTemplateDeclaration(DeclarationAST *&node) const ListNode *params = 0; if (token_stream.lookAhead() == '<') { - token_stream.nextToken(); + nextToken(); parseTemplateParameterList(params); + resolveRightShift(); ADVANCE('>', ">"); } @@ -864,16 +1008,16 @@ bool Parser::parseOperator(OperatorAST *&node) case Token_delete: { ast->op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); if (token_stream.lookAhead() == '[' && token_stream.lookAhead(1) == ']') { ast->open = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ast->close = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } } break; @@ -893,7 +1037,7 @@ bool Parser::parseOperator(OperatorAST *&node) case '>': case ',': case Token_assign: - case Token_shift: + case Token_shift_left: case Token_eq: case Token_not_eq: case Token_leq: @@ -905,7 +1049,14 @@ bool Parser::parseOperator(OperatorAST *&node) case Token_ptrmem: case Token_arrow: ast->op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); + break; + + case Token_shift_right: + ast->op = token_stream.cursor(); + nextToken(); + // skip placeholder + nextToken(); break; default: @@ -913,17 +1064,26 @@ bool Parser::parseOperator(OperatorAST *&node) && token_stream.lookAhead(1) == ')') { ast->op = ast->open = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ast->close = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } else if (token_stream.lookAhead() == '[' && token_stream.lookAhead(1) == ']') { ast->op = ast->open = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ast->close = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); + } + else if (token_stream.lookAhead() == Token_string_literal + && token_stream.lookAhead(1) == Token_identifier) + { + // string literal operator + ast->op = token_stream.cursor(); + nextToken(); + // skip string literal suffix for now + nextToken(); } else { @@ -943,10 +1103,11 @@ bool Parser::parseCvQualify(const ListNode *&node) int tk; while (0 != (tk = token_stream.lookAhead()) - && (tk == Token_const || tk == Token_volatile)) + && (tk == Token_const || + tk == Token_volatile || tk == Token_mutable)) { node = snoc(node, token_stream.cursor(), _M_pool); - token_stream.nextToken(); + nextToken(); } return start != token_stream.cursor(); @@ -978,7 +1139,7 @@ bool Parser::parseSimpleTypeSpecifier(TypeSpecifierAST *&node, case Token_void: integrals = snoc(integrals, token_stream.cursor(), _M_pool); isIntegral = true; - token_stream.nextToken(); + nextToken(); break; default: @@ -991,22 +1152,28 @@ bool Parser::parseSimpleTypeSpecifier(TypeSpecifierAST *&node, { ast->integrals = integrals; } - else if (token_stream.lookAhead() == Token___typeof) + else if (token_stream.lookAhead() == Token_auto) + { + nextToken(); + ast->is_auto = true; + } + else if (token_stream.lookAhead() == Token___typeof || + token_stream.lookAhead() == Token_decltype) { ast->type_of = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); if (token_stream.lookAhead() == '(') { - token_stream.nextToken(); + nextToken(); std::size_t saved = token_stream.cursor(); parseTypeId(ast->type_id); if (token_stream.lookAhead() != ')') { ast->type_id = 0; - token_stream.rewind((int) saved); - parseUnaryExpression(ast->expression); + rewind(saved); + parseConditionalExpression(ast->expression); } ADVANCE(')', ")"); } @@ -1017,15 +1184,19 @@ bool Parser::parseSimpleTypeSpecifier(TypeSpecifierAST *&node, } else if (onlyIntegral) { - token_stream.rewind((int) start); + rewind(start); return false; } else { + if (token_stream.lookAhead() == Token_typename) + { + nextToken(); // simply skip for now + } if (!parseName(ast->name, true)) { ast->name = 0; - token_stream.rewind((int) start); + rewind(start); return false; } } @@ -1056,7 +1227,7 @@ bool Parser::parsePtrOperator(PtrOperatorAST *&node) case '*': case Token_and: ast->op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); break; case Token_scope: @@ -1064,7 +1235,7 @@ bool Parser::parsePtrOperator(PtrOperatorAST *&node) { if (!parsePtrToMember(ast->mem_ptr)) { - token_stream.rewind((int) start); + rewind(start); return false; } } @@ -1091,9 +1262,11 @@ bool Parser::parseTemplateArgument(TemplateArgumentAST *&node) ExpressionAST *expr = 0; if (!parseTypeId(typeId) || (token_stream.lookAhead() != ',' - && token_stream.lookAhead() != '>')) + && token_stream.lookAhead() != Token_ellipsis + && token_stream.lookAhead() != '>' + && token_stream.lookAhead() != Token_shift_right)) { - token_stream.rewind((int) start); + rewind(start); if (!parseLogicalOrExpression(expr, true)) return false; @@ -1103,6 +1276,11 @@ bool Parser::parseTemplateArgument(TemplateArgumentAST *&node) ast->type_id = typeId; ast->expression = expr; + if (token_stream.lookAhead() == Token_ellipsis) { + nextToken(); + ast->variadic = true; + } + UPDATE_POS(ast, start, token_stream.cursor()); node = ast; @@ -1113,13 +1291,15 @@ bool Parser::parseTypeSpecifier(TypeSpecifierAST *&node) { std::size_t start = token_stream.cursor(); + skipAttributes(); + const ListNode *cv = 0; parseCvQualify(cv); TypeSpecifierAST *ast = 0; if (!parseElaboratedTypeSpecifier(ast) && !parseSimpleTypeSpecifier(ast)) { - token_stream.rewind((int) start); + rewind(start); return false; } @@ -1131,7 +1311,7 @@ bool Parser::parseTypeSpecifier(TypeSpecifierAST *&node) return true; } -bool Parser::parseDeclarator(DeclaratorAST *&node) +bool Parser::parseDeclarator(DeclaratorAST *&node, bool asParameter) { std::size_t start = token_stream.cursor(); @@ -1148,7 +1328,7 @@ bool Parser::parseDeclarator(DeclaratorAST *&node) if (token_stream.lookAhead() == '(') { - token_stream.nextToken(); + nextToken(); if (!parseDeclarator(decl)) return false; @@ -1163,19 +1343,28 @@ bool Parser::parseDeclarator(DeclaratorAST *&node) { // unnamed bitfield } - else if (parseName(declId, true)) - { - ast->id = declId; - } else { - token_stream.rewind((int) start); - return false; + if (asParameter && token_stream.lookAhead() == Token_ellipsis) + { + // parameter pack + nextToken(); + ast->packedParameter = true; + } + if (parseName(declId, true)) + { + ast->id = declId; + } + else + { + rewind(start); + return false; + } } if (token_stream.lookAhead() == ':') { - token_stream.nextToken(); + nextToken(); if (!parseConstantExpression(ast->bit_expression)) { @@ -1190,7 +1379,7 @@ bool Parser::parseDeclarator(DeclaratorAST *&node) while (token_stream.lookAhead() == '[') { - token_stream.nextToken(); + nextToken(); ExpressionAST *expr = 0; parseCommaExpression(expr); @@ -1206,8 +1395,8 @@ bool Parser::parseDeclarator(DeclaratorAST *&node) && token_stream.lookAhead(1) == '(' && token_stream.lookAhead(2) == '(') { - token_stream.nextToken(); - token_stream.nextToken(); + nextToken(); + nextToken(); skipParen = true; } @@ -1216,57 +1405,31 @@ bool Parser::parseDeclarator(DeclaratorAST *&node) && !(isVector || tok == '(' || tok == ',' || tok == ';' || tok == '=')) { - token_stream.rewind((int) start); + rewind(start); return false; } - std::size_t index = token_stream.cursor(); - if (token_stream.lookAhead() == '(') - { - token_stream.nextToken(); - - ParameterDeclarationClauseAST *params = 0; - if (!parseParameterDeclarationClause(params)) - { - token_stream.rewind((int) index); - goto update_pos; - } - - ast->parameter_declaration_clause = params; - - if (token_stream.lookAhead() != ')') - { - token_stream.rewind((int) index); - goto update_pos; - } - - token_stream.nextToken(); // skip ')' + if (parseDeclaratorParametersAndSuffix(ast)) { - parseCvQualify(ast->fun_cv); - parseExceptionSpecification(ast->exception_spec); - if (token_stream.lookAhead() == Token_identifier) { - const NameSymbol *name_symbol = token_stream.symbol(token_stream.cursor()); - QString name = name_symbol->as_string(); - if (name == "override") { - token_stream.nextToken(); - ast->_override = true; - } - } - if (token_stream.lookAhead() == Token___attribute__) - { - parse_Attribute__(); - } + if (token_stream.lookAhead() == Token_identifier && + token_stream.symbol(token_stream.cursor())->as_string() == "override") + { + nextToken(); + ast->_override = true; } + skipAttributes(); - if (skipParen) + if (skipParen) { if (token_stream.lookAhead() != ')') - { - reportError(("')' expected")); - } + { + reportError(("')' expected")); + } else - token_stream.nextToken(); + nextToken(); } + + } } update_pos: @@ -1292,11 +1455,11 @@ bool Parser::parseAbstractDeclarator(DeclaratorAST *&node) int index = (int) token_stream.cursor(); if (token_stream.lookAhead() == '(') { - token_stream.nextToken(); + nextToken(); if (!parseAbstractDeclarator(decl)) { - token_stream.rewind((int) index); + rewind(index); goto label1; } @@ -1304,14 +1467,14 @@ bool Parser::parseAbstractDeclarator(DeclaratorAST *&node) if (token_stream.lookAhead() != ')') { - token_stream.rewind((int) start); + rewind(start); return false; } - token_stream.nextToken(); + nextToken(); } else if (token_stream.lookAhead() == ':') { - token_stream.nextToken(); + nextToken(); if (!parseConstantExpression(ast->bit_expression)) { ast->bit_expression = 0; @@ -1326,7 +1489,7 @@ bool Parser::parseAbstractDeclarator(DeclaratorAST *&node) while (token_stream.lookAhead() == '[') { - token_stream.nextToken(); + nextToken(); ExpressionAST *expr = 0; parseCommaExpression(expr); @@ -1342,35 +1505,11 @@ bool Parser::parseAbstractDeclarator(DeclaratorAST *&node) && !(isVector || tok == '(' || tok == ',' || tok == ';' || tok == '=')) { - token_stream.rewind((int) start); + rewind(start); return false; } - int index = (int) token_stream.cursor(); - if (token_stream.lookAhead() == '(') - { - token_stream.nextToken(); - - ParameterDeclarationClauseAST *params = 0; - if (!parseParameterDeclarationClause(params)) - { - token_stream.rewind((int) index); - goto update_pos; - } - - ast->parameter_declaration_clause = params; - - if (token_stream.lookAhead() != ')') - { - token_stream.rewind((int) index); - goto update_pos; - } - - token_stream.nextToken(); // skip ')' - - parseCvQualify(ast->fun_cv); - parseExceptionSpecification(ast->exception_spec); - } + parseDeclaratorParametersAndSuffix(ast); } update_pos: @@ -1383,24 +1522,84 @@ bool Parser::parseAbstractDeclarator(DeclaratorAST *&node) return true; } +bool Parser::parseDeclaratorParametersAndSuffix(DeclaratorAST* ast) +{ + std::size_t index = token_stream.cursor(); + if (token_stream.lookAhead() == '(') + { + nextToken(); + + ParameterDeclarationClauseAST* params = 0; + if (!parseParameterDeclarationClause(params)) + { + rewind(index); + return false; + } + + ast->parameter_declaration_clause = params; + + if (token_stream.lookAhead() != ')') + { + rewind(index); + return false; + } + + nextToken(); // skip ')' + + parseCvQualify(ast->fun_cv); + if (token_stream.lookAhead() == '&') + { + ast->valueRef = DeclaratorAST::Lvalue; + nextToken(); + } + else if (token_stream.lookAhead() == Token_and) + { + ast->valueRef = DeclaratorAST::Rvalue; + nextToken(); + } + parseExceptionSpecification(ast->exception_spec); + return true; + } + return false; +} + bool Parser::parseEnumSpecifier(TypeSpecifierAST *&node) { std::size_t start = token_stream.cursor(); CHECK(Token_enum); + bool enum_class{}; + if (token_stream.lookAhead() == Token_class) + { + enum_class = true; + nextToken(); + } + NameAST *name = 0; parseName(name); + if(token_stream.lookAhead() == ':') + { + nextToken(); + TypeSpecifierAST *ast = 0; + if (!parseSimpleTypeSpecifier(ast)) + { + rewind(start); + return false; + } + } + if (token_stream.lookAhead() != '{') { - token_stream.rewind((int) start); + rewind(start); return false; } - token_stream.nextToken(); + nextToken(); EnumSpecifierAST *ast = CreateNode(_M_pool); ast->name = name; + ast->is_enum_class = enum_class; EnumeratorAST *enumerator = 0; if (parseEnumerator(enumerator)) @@ -1409,7 +1608,7 @@ bool Parser::parseEnumSpecifier(TypeSpecifierAST *&node) while (token_stream.lookAhead() == ',') { - token_stream.nextToken(); + nextToken(); if (!parseEnumerator(enumerator)) { @@ -1439,7 +1638,7 @@ bool Parser::parseTemplateParameterList(const ListNode *& while (token_stream.lookAhead() == ',') { - token_stream.nextToken(); + nextToken(); if (!parseTemplateParameter(param)) { @@ -1452,6 +1651,17 @@ bool Parser::parseTemplateParameterList(const ListNode *& } } + if (token_stream.lookAhead() == Token_ellipsis) + { + // ignore variadic template parameters as in + // template + token_stream.nextToken(); + if (token_stream.lookAhead() == Token_identifier) + { + token_stream.nextToken(); + } + } + return true; } @@ -1465,7 +1675,13 @@ bool Parser::parseTemplateParameter(TemplateParameterAST *&node) if ((tk == Token_class || tk == Token_typename || tk == Token_template) && parseTypeParameter(ast->type_parameter)) { - // nothing to do + if (token_stream.lookAhead() == '=' || token_stream.lookAhead() == Token_assign) + { + // default template parameter + token_stream.nextToken(); + TypeSpecifierAST* typeNode = 0; + parseTypeSpecifier(typeNode); + } } else if (!parseParameterDeclaration(ast->parameter_declaration)) return false; @@ -1488,26 +1704,32 @@ bool Parser::parseTypeParameter(TypeParameterAST *&node) case Token_class: case Token_typename: { - token_stream.nextToken(); // skip class + nextToken(); // skip class + + if (token_stream.lookAhead() == Token_ellipsis) + { + // skip variadic parameters in template parameter list + nextToken(); + } // parse optional name if(parseName(ast->name, true)) { if (token_stream.lookAhead() == '=') { - token_stream.nextToken(); + nextToken(); if(!parseTypeId(ast->type_id)) { //syntaxError(); - token_stream.rewind((int) start); + rewind(start); return false; } } else if (token_stream.lookAhead() != ',' && token_stream.lookAhead() != '>') { - token_stream.rewind((int) start); + rewind(start); return false; } } @@ -1516,7 +1738,7 @@ bool Parser::parseTypeParameter(TypeParameterAST *&node) case Token_template: { - token_stream.nextToken(); // skip template + nextToken(); // skip template ADVANCE('<', "<"); if (!parseTemplateParameterList(ast->template_parameters)) @@ -1525,14 +1747,14 @@ bool Parser::parseTypeParameter(TypeParameterAST *&node) ADVANCE('>', ">"); if (token_stream.lookAhead() == Token_class) - token_stream.nextToken(); + nextToken(); // parse optional name if (parseName(ast->name, true)) { if (token_stream.lookAhead() == '=') { - token_stream.nextToken(); + nextToken(); if (!parseTypeId(ast->type_id)) { @@ -1544,7 +1766,7 @@ bool Parser::parseTypeParameter(TypeParameterAST *&node) if (token_stream.lookAhead() == '=') { - token_stream.nextToken(); + nextToken(); parseName(ast->template_name, true); } @@ -1568,12 +1790,13 @@ bool Parser::parseStorageClassSpecifier(const ListNode *&node) int tk; while (0 != (tk = token_stream.lookAhead()) - && (tk == Token_friend || tk == Token_auto + && (tk == Token_friend + // || tk == Token_auto // I believe "auto" isn't used as storage class specifier in Qt, and it collides with the type-specifier of the same name || tk == Token_register || tk == Token_static - || tk == Token_extern || tk == Token_mutable)) + || tk == Token_extern)) { node = snoc(node, token_stream.cursor(), _M_pool); - token_stream.nextToken(); + nextToken(); } return start != token_stream.cursor(); @@ -1585,11 +1808,11 @@ bool Parser::parseFunctionSpecifier(const ListNode *&node) int tk; while (0 != (tk = token_stream.lookAhead()) - && (tk == Token_inline || tk == Token_virtual + && (tk == Token_constexpr || tk == Token_inline || tk == Token_virtual || tk == Token_explicit || tk == Token_Q_INVOKABLE)) { node = snoc(node, token_stream.cursor(), _M_pool); - token_stream.nextToken(); + nextToken(); } return start != token_stream.cursor(); @@ -1603,7 +1826,7 @@ bool Parser::parseTypeId(TypeIdAST *&node) TypeSpecifierAST *spec = 0; if (!parseTypeSpecifier(spec)) { - token_stream.rewind((int) start); + rewind(start); return false; } @@ -1630,7 +1853,7 @@ bool Parser::parseInitDeclaratorList(const ListNode *&node) while (token_stream.lookAhead() == ',') { - token_stream.nextToken(); + nextToken(); if (!parseInitDeclarator(decl)) { @@ -1670,7 +1893,7 @@ bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&nod if (token_stream.lookAhead() == Token_ellipsis) { ast->ellipsis = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } /// @todo add ellipsis @@ -1687,7 +1910,7 @@ bool Parser::parseParameterDeclarationList(const ListNodestart_token; - int end_token = ast->end_token; + size_t start_token = ast->start_token; + size_t end_token = ast->end_token; Token const &tk = token_stream.token (start_token); Token const &end_tk = token_stream.token(end_token); @@ -1796,15 +2019,20 @@ bool Parser::parseForwardDeclarationSpecifier(TypeSpecifierAST *&node) std::size_t start = token_stream.cursor(); int kind = token_stream.lookAhead(); - if (kind != Token_class && kind != Token_struct && kind != Token_union) + if (kind != Token_class && kind != Token_struct && kind != Token_union && kind != Token_enum) return false; std::size_t class_key = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); + + if (kind == Token_enum && token_stream.lookAhead() == Token_class) + { + nextToken(); + } NameAST *name = 0; if (!parseName(name, false)) { - token_stream.rewind((int) start); + rewind(start); return false; } @@ -1813,14 +2041,14 @@ bool Parser::parseForwardDeclarationSpecifier(TypeSpecifierAST *&node) { if (!parseBaseClause(bases)) { - token_stream.rewind((int) start); + rewind(start); return false; } } if (token_stream.lookAhead() != ';') { - token_stream.rewind((int) start); + rewind(start); return false; } @@ -1844,24 +2072,23 @@ bool Parser::parseClassSpecifier(TypeSpecifierAST *&node) return false; std::size_t class_key = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); WinDeclSpecAST *winDeclSpec = 0; - parseWinDeclSpec(winDeclSpec); - - if (token_stream.lookAhead() == Token___attribute__) { - parse_Attribute__(); + while (skipAttributes() || skipAlignas() || (!winDeclSpec && parseWinDeclSpec(winDeclSpec))) + { + ; } while (token_stream.lookAhead() == Token_identifier && token_stream.lookAhead(1) == Token_identifier) { - token_stream.nextToken(); + nextToken(); } NameAST *name = 0; parseName(name, true); - + BaseClauseAST *bases = 0; if (token_stream.lookAhead() == ':') @@ -1875,7 +2102,7 @@ bool Parser::parseClassSpecifier(TypeSpecifierAST *&node) if (token_stream.lookAhead() != '{') { - token_stream.rewind((int) start); + rewind(start); return false; } @@ -1898,7 +2125,7 @@ bool Parser::parseClassSpecifier(TypeSpecifierAST *&node) if (!parseMemberSpecification(memSpec)) { if (startDecl == token_stream.cursor()) - token_stream.nextToken(); // skip at least one token + nextToken(); // skip at least one token skipUntilDeclaration(); } else @@ -1932,7 +2159,7 @@ bool Parser::parseAccessSpecifier(DeclarationAST *&node) case Token_protected: case Token_private: specs = snoc(specs, token_stream.cursor(), _M_pool); - token_stream.nextToken(); + nextToken(); break; default: @@ -1960,12 +2187,12 @@ bool Parser::parseMemberSpecification(DeclarationAST *&node) if (token_stream.lookAhead() == ';') { - token_stream.nextToken(); + nextToken(); return true; } else if (token_stream.lookAhead() == Token_Q_OBJECT || token_stream.lookAhead() == Token_K_DCOP) { - token_stream.nextToken(); + nextToken(); return true; } else if (parseTypedef(node)) @@ -1997,15 +2224,15 @@ bool Parser::parseMemberSpecification(DeclarationAST *&node) return true; } - token_stream.rewind((int) start); + rewind(start); const ListNode *cv = 0; - parseCvQualify(cv); - - const ListNode *storageSpec = 0; - parseStorageClassSpecifier(storageSpec); - - parseCvQualify(cv); + const ListNode* storageSpec = 0; + // consume all qualifiers/specifiers + while (parseCvQualify(cv) || parseStorageClassSpecifier(storageSpec)) + { + ; + } TypeSpecifierAST *spec = 0; if (parseEnumSpecifier(spec) || parseClassSpecifier(spec)) @@ -2026,7 +2253,7 @@ bool Parser::parseMemberSpecification(DeclarationAST *&node) return true; } - token_stream.rewind((int) start); + rewind(start); return parseDeclarationInternal(node); } @@ -2062,7 +2289,7 @@ bool Parser::parseElaboratedTypeSpecifier(TypeSpecifierAST *&node) tk == Token_typename) { std::size_t type = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); NameAST *name = 0; if (parseName(name, true)) @@ -2080,7 +2307,7 @@ bool Parser::parseElaboratedTypeSpecifier(TypeSpecifierAST *&node) } } - token_stream.rewind((int) start); + rewind(start); return false; } @@ -2088,6 +2315,20 @@ bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node) { std::size_t start = token_stream.cursor(); + if (token_stream.lookAhead() == Token_noexcept) + { + // ignore noexcept + nextToken(); + if (token_stream.lookAhead() == '(') + { + nextToken(); + ExpressionAST* node; + parseCommaExpression(node); + CHECK(')'); + } + return true; + } + CHECK(Token_throw); ADVANCE('(', "("); @@ -2097,7 +2338,7 @@ bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node) if (token_stream.lookAhead() == Token_ellipsis) { ast->ellipsis = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } else { @@ -2124,7 +2365,7 @@ bool Parser::parseEnumerator(EnumeratorAST *&node) if (token_stream.lookAhead() == '=') { - token_stream.nextToken(); + nextToken(); if (!parseConstantExpression(ast->expression)) { @@ -2142,6 +2383,13 @@ bool Parser::parseInitDeclarator(InitDeclaratorAST *&node) { std::size_t start = token_stream.cursor(); + if (token_stream.lookAhead(0) == Token_ellipsis) + { + // for now just ignore variadic parameters + token_stream.nextToken(); + return true; + } + DeclaratorAST *decl = 0; if (!parseDeclarator(decl)) { @@ -2150,13 +2398,13 @@ bool Parser::parseInitDeclarator(InitDeclaratorAST *&node) if (token_stream.lookAhead(0) == Token_asm) { - token_stream.nextToken(); + nextToken(); skip('(', ')'); - token_stream.nextToken(); + nextToken(); } InitializerAST *init = 0; - parseInitializer(init); + parseInitializer(init, !decl->parameter_declaration_clause); InitDeclaratorAST *ast = CreateNode(_M_pool); ast->declarator = decl; @@ -2183,7 +2431,7 @@ bool Parser::parseBaseClause(BaseClauseAST *&node) while (token_stream.lookAhead() == ',') { - token_stream.nextToken(); + nextToken(); if (!parseBaseSpecifier(baseSpec)) { @@ -2199,31 +2447,51 @@ bool Parser::parseBaseClause(BaseClauseAST *&node) return true; } -bool Parser::parseInitializer(InitializerAST *&node) +bool Parser::parseInitializer(InitializerAST *&node, bool allowNewStyle) { std::size_t start = token_stream.cursor(); int tk = token_stream.lookAhead(); - if (tk != '=' && tk != '(') + if (tk != '=' && tk != '(' && !(allowNewStyle && tk == '{')) return false; InitializerAST *ast = CreateNode(_M_pool); if (tk == '=') { - token_stream.nextToken(); - - if (!parseInitializerClause(ast->initializer_clause)) + nextToken(); + tk = token_stream.lookAhead(); + // this is also used for methods: + if (tk == Token_delete) + { + ast->isDeleted = true; + nextToken(); + } + else if (tk == Token_default) + { + ast->isDefault = true; + nextToken(); + } + else if (!parseInitializerClause(ast->initializer_clause)) { reportError(("Initializer clause expected")); } } else if (tk == '(') { - token_stream.nextToken(); + nextToken(); parseCommaExpression(ast->expression); CHECK(')'); } + else if (tk == '{') + { + nextToken(); + if (token_stream.lookAhead() != '}') { + parseCommaExpression(ast->expression); + } + // new-style initializers may be empty (default value) + CHECK('}'); + } UPDATE_POS(ast, start, token_stream.cursor()); node = ast; @@ -2242,7 +2510,7 @@ bool Parser::parseMemInitializerList(const ListNode *&node) while (token_stream.lookAhead() == ',') { - token_stream.nextToken(); + nextToken(); if (!parseMemInitializer(init)) break; @@ -2264,10 +2532,23 @@ bool Parser::parseMemInitializer(MemInitializerAST *&node) return false; } - ADVANCE('(', "("); - ExpressionAST *expr = 0; - parseCommaExpression(expr); - ADVANCE(')', ")"); + ExpressionAST* expr = 0; + if (token_stream.lookAhead() == '{') + { + // new style initializers + ADVANCE('{', "{"); + if (token_stream.lookAhead() != '}') { + parseCommaExpression(expr); + } + // new-style initializers may be empty (default value) + ADVANCE('}', "}"); + } + else + { + ADVANCE('(', "("); + parseCommaExpression(expr); + ADVANCE(')', ")"); + } MemInitializerAST *ast = CreateNode(_M_pool); ast->initializer_id = initId; @@ -2289,7 +2570,7 @@ bool Parser::parseTypeIdList(const ListNode *&node) while (token_stream.lookAhead() == ',') { - token_stream.nextToken(); + nextToken(); if (parseTypeId(typeId)) { node = snoc(node, typeId, _M_pool); @@ -2313,14 +2594,14 @@ bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node) if (token_stream.lookAhead() == Token_virtual) { ast->virt = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); int tk = token_stream.lookAhead(); if (tk == Token_public || tk == Token_protected || tk == Token_private) { ast->access_specifier = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } } else @@ -2330,13 +2611,13 @@ bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node) || tk == Token_private) { ast->access_specifier = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } if (token_stream.lookAhead() == Token_virtual) { ast->virt = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } } @@ -2358,10 +2639,10 @@ bool Parser::parseInitializerClause(InitializerClauseAST *&node) if (token_stream.lookAhead() == '{') { #if defined(__GNUC__) -#warning "implement me" +#pragma GCC warning "implement me" #endif if (skip('{','}')) - token_stream.nextToken(); + nextToken(); else reportError(("} missing")); } @@ -2382,16 +2663,14 @@ bool Parser::parseInitializerClause(InitializerClauseAST *&node) bool Parser::parsePtrToMember(PtrToMemberAST *&node) { #if defined(__GNUC__) -#warning "implemente me (AST)" +#pragma GCC warning "implemente me (AST)" #endif std::size_t start = token_stream.cursor(); - std::size_t global_scope = 0; if (token_stream.lookAhead() == Token_scope) { - global_scope = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } UnqualifiedNameAST *name = 0; @@ -2403,8 +2682,8 @@ bool Parser::parsePtrToMember(PtrToMemberAST *&node) if (token_stream.lookAhead() == Token_scope && token_stream.lookAhead(1) == '*') { - token_stream.nextToken(); - token_stream.nextToken(); + nextToken(); + nextToken(); PtrToMemberAST *ast = CreateNode(_M_pool); UPDATE_POS(ast, start, token_stream.cursor()); @@ -2414,13 +2693,23 @@ bool Parser::parsePtrToMember(PtrToMemberAST *&node) } if (token_stream.lookAhead() == Token_scope) - token_stream.nextToken(); + nextToken(); } - token_stream.rewind((int) start); + rewind(start); return false; } +void Parser::resolveRightShift() +{ + if (token_stream.lookAhead() == Token_shift_right) + { + std::size_t index = token_stream.cursor(); + token_stream[index].kind = '>'; + token_stream[index + 1].kind = '>'; + } +} + bool Parser::parseUnqualifiedName(UnqualifiedNameAST *&node, bool parseTemplateId) { @@ -2433,16 +2722,16 @@ bool Parser::parseUnqualifiedName(UnqualifiedNameAST *&node, if (token_stream.lookAhead() == Token_identifier) { id = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } else if (token_stream.lookAhead() == '~' && token_stream.lookAhead(1) == Token_identifier) { tilde = token_stream.cursor(); - token_stream.nextToken(); // skip ~ + nextToken(); // skip ~ id = token_stream.cursor(); - token_stream.nextToken(); // skip classname + nextToken(); // skip classname } else if (token_stream.lookAhead() == Token_operator) { @@ -2465,19 +2754,20 @@ bool Parser::parseUnqualifiedName(UnqualifiedNameAST *&node, if (token_stream.lookAhead() == '<') { - token_stream.nextToken(); + nextToken(); // optional template arguments parseTemplateArgumentList(ast->template_arguments); + resolveRightShift(); if (token_stream.lookAhead() == '>') { - token_stream.nextToken(); + nextToken(); } else { ast->template_arguments = 0; - token_stream.rewind((int) index); + rewind(index); } } } @@ -2500,7 +2790,7 @@ bool Parser::parseStringLiteral(StringLiteralAST *&node) while (token_stream.lookAhead() == Token_string_literal) { ast->literals = snoc(ast->literals, token_stream.cursor(), _M_pool); - token_stream.nextToken(); + nextToken(); } UPDATE_POS(ast, start, token_stream.cursor()); @@ -2558,24 +2848,24 @@ bool Parser::parseStatement(StatementAST *&node) case Token_break: case Token_continue: #if defined(__GNUC__) -#warning "implement me" +#pragma GCC warning "implement me" #endif - token_stream.nextToken(); + nextToken(); ADVANCE(';', ";"); return true; case Token_goto: #if defined(__GNUC__) -#warning "implement me" +#pragma GCC warning "implement me" #endif - token_stream.nextToken(); + nextToken(); ADVANCE(Token_identifier, "identifier"); ADVANCE(';', ";"); return true; case Token_return: { - token_stream.nextToken(); + nextToken(); ExpressionAST *expr = 0; parseCommaExpression(expr); @@ -2613,7 +2903,7 @@ bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node) std::size_t end = token_stream.cursor(); - token_stream.rewind((int) start); + rewind(start); StatementAST *expr_ast = 0; maybe_amb &= parseExpressionStatement(expr_ast); maybe_amb &= token_stream.kind(token_stream.cursor() - 1) == ';'; @@ -2631,7 +2921,7 @@ bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node) } else { - token_stream.rewind((int) std::max(end, token_stream.cursor())); + rewind(std::max(end, token_stream.cursor())); node = decl_ast; if (!node) @@ -2662,7 +2952,7 @@ bool Parser::parseCondition(ConditionAST *&node, bool initRequired) DeclaratorAST *decl = 0; if (!parseDeclarator(decl)) { - token_stream.rewind((int) declarator_start); + rewind(declarator_start); if (!initRequired && !parseAbstractDeclarator(decl)) decl = 0; } @@ -2673,7 +2963,7 @@ bool Parser::parseCondition(ConditionAST *&node, bool initRequired) if (token_stream.lookAhead() == '=') { - token_stream.nextToken(); + nextToken(); parseExpression(ast->expression); } @@ -2685,7 +2975,7 @@ bool Parser::parseCondition(ConditionAST *&node, bool initRequired) } } - token_stream.rewind((int) start); + rewind(start); if (!parseCommaExpression(ast->expression)) return false; @@ -2830,7 +3120,7 @@ bool Parser::parseCompoundStatement(StatementAST *&node) if (!parseStatement(stmt)) { if (startStmt == token_stream.cursor()) - token_stream.nextToken(); + nextToken(); skipUntilStatement(); } @@ -2878,7 +3168,7 @@ bool Parser::parseIfStatement(StatementAST *&node) if (token_stream.lookAhead() == Token_else) { - token_stream.nextToken(); + nextToken(); if (!parseStatement(ast->else_statement)) { @@ -2933,8 +3223,8 @@ bool Parser::parseLabeledStatement(StatementAST *&node) case Token_default: if (token_stream.lookAhead(1) == ':') { - token_stream.nextToken(); - token_stream.nextToken(); + nextToken(); + nextToken(); StatementAST *stmt = 0; if (parseStatement(stmt)) @@ -2947,7 +3237,7 @@ bool Parser::parseLabeledStatement(StatementAST *&node) case Token_case: { - token_stream.nextToken(); + nextToken(); ExpressionAST *expr = 0; if (!parseConstantExpression(expr)) { @@ -2955,7 +3245,7 @@ bool Parser::parseLabeledStatement(StatementAST *&node) } else if (token_stream.lookAhead() == Token_ellipsis) { - token_stream.nextToken(); + nextToken(); ExpressionAST *expr2 = 0; if (!parseConstantExpression(expr2)) @@ -2996,17 +3286,17 @@ bool Parser::parseBlockDeclaration(DeclarationAST *&node) std::size_t start = token_stream.cursor(); const ListNode *cv = 0; - parseCvQualify(cv); - const ListNode *storageSpec = 0; - parseStorageClassSpecifier(storageSpec); - - parseCvQualify(cv); + // consume all qualifiers/specifiers + while (parseCvQualify(cv) || parseStorageClassSpecifier(storageSpec)) + { + ; + } TypeSpecifierAST *spec = 0; if (!parseTypeSpecifierOrClassSpec(spec)) { // replace with simpleTypeSpecifier?!?! - token_stream.rewind((int) start); + rewind(start); return false; } @@ -3018,10 +3308,10 @@ bool Parser::parseBlockDeclaration(DeclarationAST *&node) if (token_stream.lookAhead() != ';') { - token_stream.rewind((int) start); + rewind(start); return false; } - token_stream.nextToken(); + nextToken(); SimpleDeclarationAST *ast = CreateNode(_M_pool); ast->type_specifier = spec; @@ -3084,25 +3374,21 @@ bool Parser::parseDeclarationInternal(DeclarationAST *&node) // that is for the case '__declspec(dllexport) int ...' or // '__declspec(dllexport) inline int ...', etc. WinDeclSpecAST *winDeclSpec = 0; - parseWinDeclSpec(winDeclSpec); - - const ListNode *funSpec = 0; - bool hasFunSpec = parseFunctionSpecifier(funSpec); - - const ListNode *cv = 0; - parseCvQualify(cv); - - const ListNode *storageSpec = 0; - bool hasStorageSpec = parseStorageClassSpecifier(storageSpec); - - if (hasStorageSpec && !hasFunSpec) - hasFunSpec = parseFunctionSpecifier(funSpec); - - // that is for the case 'friend __declspec(dllexport) ....' - parseWinDeclSpec(winDeclSpec); - - if (!cv) - parseCvQualify(cv); + const ListNode* cv = 0; + const ListNode* funSpec = 0; + const ListNode* storageSpec = 0; + // since it seems that the various specifiers can come in almost any order, + // so just consume then until no specifiers are left. + // Luckily the parse methods can be called multiple times, they just add to existing nodes. + while (skipAttributes() || + skipAlignas() || + (!winDeclSpec && parseWinDeclSpec(winDeclSpec)) || + parseCvQualify(cv) || + parseFunctionSpecifier(funSpec) || + parseStorageClassSpecifier(storageSpec)) + { + ; + } int index = (int) token_stream.cursor(); NameAST *name = 0; @@ -3110,7 +3396,7 @@ bool Parser::parseDeclarationInternal(DeclarationAST *&node) { // no type specifier, maybe a constructor or a cast operator?? - token_stream.rewind((int) index); + rewind(index); InitDeclaratorAST *declarator = 0; if (parseInitDeclarator(declarator)) @@ -3119,7 +3405,7 @@ bool Parser::parseDeclarationInternal(DeclarationAST *&node) { case ';': { - token_stream.nextToken(); + nextToken(); SimpleDeclarationAST *ast = CreateNode(_M_pool); @@ -3190,14 +3476,14 @@ bool Parser::parseDeclarationInternal(DeclarationAST *&node) } start_decl: - token_stream.rewind((int) index); + rewind(index); if (token_stream.lookAhead() == Token_const && token_stream.lookAhead(1) == Token_identifier && token_stream.lookAhead(2) == '=') { // constant definition - token_stream.nextToken(); // skip const + nextToken(); // skip const const ListNode *declarators = 0; if (!parseInitDeclaratorList(declarators)) @@ -3209,7 +3495,7 @@ bool Parser::parseDeclarationInternal(DeclarationAST *&node) ADVANCE(';', ";"); #if defined(__GNUC__) -#warning "mark the ast as constant" +#pragma GCC warning "mark the ast as constant" #endif SimpleDeclarationAST *ast = CreateNode(_M_pool); ast->init_declarators = declarators; @@ -3225,8 +3511,7 @@ bool Parser::parseDeclarationInternal(DeclarationAST *&node) { Q_ASSERT(spec != 0); - if (!hasFunSpec) - parseFunctionSpecifier(funSpec); // e.g. "void inline" + parseFunctionSpecifier(funSpec); // e.g. "void inline" spec->cv = cv; @@ -3237,14 +3522,14 @@ bool Parser::parseDeclarationInternal(DeclarationAST *&node) if (token_stream.lookAhead() != ';') { - if (parseInitDeclarator(decl) && token_stream.lookAhead() == '{') + if (parseInitDeclarator(decl) && (token_stream.lookAhead() == '{' || token_stream.lookAhead() == Token_arrow)) { // function definition maybeFunctionDefinition = true; } else { - token_stream.rewind((int) startDeclarator); + rewind(startDeclarator); if (!parseInitDeclaratorList(declarators)) { syntaxError(); @@ -3253,11 +3538,23 @@ bool Parser::parseDeclarationInternal(DeclarationAST *&node) } } + if (token_stream.lookAhead() == Token_arrow) { + // trailing return type, used in conjuction with "auto" return type + nextToken(); + TypeSpecifierAST* trailingReturnTypeSpec = 0; + if (!parseTypeSpecifier(trailingReturnTypeSpec)) { + // todo: replace "auto" return type? But I doubt we can handle these return types anyway. + syntaxError(); + return false; + } + maybeFunctionDefinition = true; + } + switch(token_stream.lookAhead()) { case ';': { - token_stream.nextToken(); + nextToken(); SimpleDeclarationAST *ast = CreateNode(_M_pool); @@ -3307,13 +3604,38 @@ bool Parser::parseDeclarationInternal(DeclarationAST *&node) return false; } -bool Parser::skipFunctionBody(StatementAST *&) +bool Parser::skipFunctionBody(StatementAST *& node) { -#if defined(__GNUC__) -#warning "Parser::skipFunctionBody() -- implement me" -#endif - Q_ASSERT(0); // ### not implemented - return 0; + std::size_t start = token_stream.cursor(); + ADVANCE('{', "{"); + int braceCount = 1; + while (braceCount) + { + int tk = token_stream.lookAhead(); + switch (tk) + { + // handle opening braces: + case '{': + braceCount++; + break; + // handle closing braces: + case '}': + braceCount--; + break; + case Token_EOF: + reportError("unexpected EOF while skipping block"); + braceCount = 0; + break; + default: + // skip everything else + ; + } + nextToken(); + } + CompoundStatementAST* ast = CreateNode(_M_pool); + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + return true; } bool Parser::parseFunctionBody(StatementAST *&node) @@ -3339,7 +3661,7 @@ bool Parser::parseTypeSpecifierOrClassSpec(TypeSpecifierAST *&node) bool Parser::parseTryBlockStatement(StatementAST *&node) { #if defined(__GNUC__) -#warning "implement me" +#pragma GCC warning "implement me" #endif CHECK(Token_try); @@ -3358,12 +3680,12 @@ bool Parser::parseTryBlockStatement(StatementAST *&node) while (token_stream.lookAhead() == Token_catch) { - token_stream.nextToken(); + nextToken(); ADVANCE('(', "("); ConditionAST *cond = 0; if (token_stream.lookAhead() == Token_ellipsis) { - token_stream.nextToken(); + nextToken(); } else if (!parseCondition(cond, false)) { @@ -3396,17 +3718,18 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node) parseStringLiteral(ast->literal); break; + case Token_ellipsis: // "..." can occur in constexpr of variadic templates case Token_number_literal: case Token_char_literal: case Token_true: case Token_false: case Token_this: ast->token = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); break; case '(': - token_stream.nextToken(); + nextToken(); if (token_stream.lookAhead() == '{') { @@ -3422,8 +3745,19 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node) CHECK(')'); break; + case '{': + nextToken(); + + // support for new-style initializers + if (token_stream.lookAhead() != '}' && !parseExpression(ast->sub_expression)) { + return false; + } + + CHECK('}'); + break; + default: - if (!parseName(ast->name)) + if (!parseName(ast->name, true)) // this can also be a template return false; break; @@ -3453,7 +3787,7 @@ bool Parser::parsePostfixExpressionInternal(ExpressionAST *&node) { case '[': { - token_stream.nextToken(); + nextToken(); ExpressionAST *expr = 0; parseExpression(expr); CHECK(']'); @@ -3470,7 +3804,7 @@ bool Parser::parsePostfixExpressionInternal(ExpressionAST *&node) case '(': { - token_stream.nextToken(); + nextToken(); ExpressionAST *expr = 0; parseExpression(expr); CHECK(')'); @@ -3487,16 +3821,16 @@ bool Parser::parsePostfixExpressionInternal(ExpressionAST *&node) case Token_arrow: { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); std::size_t templ = 0; if (token_stream.lookAhead() == Token_template) { templ = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } - int saved = int(token_stream.cursor()); + std::size_t saved = token_stream.cursor(); NameAST *name = 0; if (parseName(name, true) && name->unqualified_name @@ -3505,7 +3839,7 @@ bool Parser::parsePostfixExpressionInternal(ExpressionAST *&node) // a template method call // ### reverse the logic } else { - token_stream.rewind(saved); + rewind(saved); name = 0; if (! parseName (name, templ != 0)) @@ -3525,7 +3859,7 @@ bool Parser::parsePostfixExpressionInternal(ExpressionAST *&node) case Token_decr: { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); IncrDecrExpressionAST *ast = CreateNode(_M_pool); ast->op = op; @@ -3557,7 +3891,7 @@ bool Parser::parsePostfixExpression(ExpressionAST *&node) case Token_const_cast: { std::size_t castOp = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); CHECK('<'); TypeIdAST *typeId = 0; @@ -3588,7 +3922,7 @@ bool Parser::parsePostfixExpression(ExpressionAST *&node) case Token_typename: { std::size_t token = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); NameAST* name = 0; if (!parseName(name, true)) @@ -3611,7 +3945,7 @@ bool Parser::parsePostfixExpression(ExpressionAST *&node) case Token_typeid: { - token_stream.nextToken(); + nextToken(); CHECK('('); TypeIdAST *typeId = 0; @@ -3648,22 +3982,30 @@ bool Parser::parsePostfixExpression(ExpressionAST *&node) if (parseCastExpression(cast_expr) && cast_expr->kind == AST::Kind_CastExpression) { - token_stream.rewind((int) saved_pos); + rewind(saved_pos); parsePrimaryExpression(expr); goto L_no_rewind; } } } - token_stream.rewind((int) saved_pos); + rewind(saved_pos); L_no_rewind: if (!expr && parseSimpleTypeSpecifier(typeSpec) - && token_stream.lookAhead() == '(') + && (token_stream.lookAhead() == '(' || token_stream.lookAhead() == '{')) { - token_stream.nextToken(); // skip '(' + int tk = token_stream.lookAhead(); + nextToken(); // skip '(' or '{' parseCommaExpression(expr); - CHECK(')'); + if (tk == '(') + { + CHECK(')'); + } + else + { + CHECK('}'); + } } else if (expr) { @@ -3672,9 +4014,26 @@ bool Parser::parsePostfixExpression(ExpressionAST *&node) else { typeSpec = 0; - token_stream.rewind((int) start); + rewind(start); + + if (token_stream.lookAhead() == Token_noexcept) + { + nextToken(); + CHECK('('); + ExpressionAST* arg_expr = 0; + if (!parseExpression(arg_expr)) + { + return false; + } + CHECK(')'); - if (!parsePrimaryExpression(expr)) + // make noexcept() in expressions an unary expression + UnaryExpressionAST* ast = CreateNode(_M_pool); + ast->op = start; + ast->expression = arg_expr; + expr = ast; + } + else if (!parsePrimaryExpression(expr)) return false; } @@ -3697,6 +4056,12 @@ bool Parser::parsePostfixExpression(ExpressionAST *&node) else node = expr; + if (token_stream.lookAhead() == Token_ellipsis) { + // ignore ellipsis, it might be something like "Pair...", which might appear + // in template arguments of variadic templates + nextToken(); + } + return true; } @@ -3716,7 +4081,7 @@ bool Parser::parseUnaryExpression(ExpressionAST *&node) case '~': { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *expr = 0; if (!parseCastExpression(expr)) @@ -3734,7 +4099,13 @@ bool Parser::parseUnaryExpression(ExpressionAST *&node) case Token_sizeof: { std::size_t sizeof_token = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); + + if (token_stream.lookAhead() == Token_ellipsis) { + // sizeof... is used on parameter packs - currently we ignore this + // todo: handle this + nextToken(); + } SizeofExpressionAST *ast = CreateNode(_M_pool); ast->sizeof_token = sizeof_token; @@ -3742,10 +4113,10 @@ bool Parser::parseUnaryExpression(ExpressionAST *&node) std::size_t index = token_stream.cursor(); if (token_stream.lookAhead() == '(') { - token_stream.nextToken(); + nextToken(); if (parseTypeId(ast->type_id) && token_stream.lookAhead() == ')') { - token_stream.nextToken(); // skip ) + nextToken(); // skip ) UPDATE_POS(ast, start, token_stream.cursor()); node = ast; @@ -3753,7 +4124,7 @@ bool Parser::parseUnaryExpression(ExpressionAST *&node) } ast->type_id = 0; - token_stream.rewind((int) index); + rewind(index); } if (!parseUnaryExpression(ast->expression)) @@ -3791,7 +4162,7 @@ bool Parser::parseNewExpression(ExpressionAST *&node) && token_stream.lookAhead(1) == Token_new) { ast->scope_token = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } CHECK(Token_new); @@ -3799,14 +4170,14 @@ bool Parser::parseNewExpression(ExpressionAST *&node) if (token_stream.lookAhead() == '(') { - token_stream.nextToken(); + nextToken(); parseCommaExpression(ast->expression); CHECK(')'); } if (token_stream.lookAhead() == '(') { - token_stream.nextToken(); + nextToken(); parseTypeId(ast->type_id); CHECK(')'); } @@ -3857,7 +4228,7 @@ bool Parser::parseNewDeclarator(NewDeclaratorAST *&node) while (token_stream.lookAhead() == '[') { - token_stream.nextToken(); + nextToken(); ExpressionAST *expr = 0; parseExpression(expr); ast->expressions = snoc(ast->expressions, expr, _M_pool); @@ -3898,7 +4269,7 @@ bool Parser::parseDeleteExpression(ExpressionAST *&node) && token_stream.lookAhead(1) == Token_delete) { ast->scope_token = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); } CHECK(Token_delete); @@ -3907,7 +4278,7 @@ bool Parser::parseDeleteExpression(ExpressionAST *&node) if (token_stream.lookAhead() == '[') { ast->lbracket_token = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); CHECK(']'); ast->rbracket_token = token_stream.cursor() - 1; } @@ -3927,7 +4298,7 @@ bool Parser::parseCastExpression(ExpressionAST *&node) if (token_stream.lookAhead() == '(') { - token_stream.nextToken(); + nextToken(); CastExpressionAST *ast = CreateNode(_M_pool); @@ -3935,7 +4306,7 @@ bool Parser::parseCastExpression(ExpressionAST *&node) { if (token_stream.lookAhead() == ')') { - token_stream.nextToken(); + nextToken(); if (parseCastExpression(ast->expression)) { @@ -3948,7 +4319,7 @@ bool Parser::parseCastExpression(ExpressionAST *&node) } } - token_stream.rewind((int) start); + rewind(start); return parseUnaryExpression(node); } @@ -3962,7 +4333,7 @@ bool Parser::parsePmExpression(ExpressionAST *&node) while (token_stream.lookAhead() == Token_ptrmem) { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parseCastExpression(rightExpr)) @@ -3992,7 +4363,7 @@ bool Parser::parseMultiplicativeExpression(ExpressionAST *&node) || token_stream.lookAhead() == '%') { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parsePmExpression(rightExpr)) @@ -4021,7 +4392,7 @@ bool Parser::parseAdditiveExpression(ExpressionAST *&node) while (token_stream.lookAhead() == '+' || token_stream.lookAhead() == '-') { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parseMultiplicativeExpression(rightExpr)) @@ -4046,10 +4417,15 @@ bool Parser::parseShiftExpression(ExpressionAST *&node) if (!parseAdditiveExpression(node)) return false; - while (token_stream.lookAhead() == Token_shift) + while (token_stream.lookAhead() == Token_shift_left || token_stream.lookAhead() == Token_shift_right) { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + if (token_stream.lookAhead() == Token_shift_right) + { + // skip placeholder + nextToken(); + } + nextToken(); ExpressionAST *rightExpr = 0; if (!parseAdditiveExpression(rightExpr)) @@ -4080,7 +4456,7 @@ bool Parser::parseRelationalExpression(ExpressionAST *&node, bool templArgs) || token_stream.lookAhead() == Token_geq) { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parseShiftExpression(rightExpr)) @@ -4109,7 +4485,7 @@ bool Parser::parseEqualityExpression(ExpressionAST *&node, bool templArgs) || token_stream.lookAhead() == Token_not_eq) { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parseRelationalExpression(rightExpr, templArgs)) @@ -4137,7 +4513,7 @@ bool Parser::parseAndExpression(ExpressionAST *&node, bool templArgs) while (token_stream.lookAhead() == '&') { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parseEqualityExpression(rightExpr, templArgs)) @@ -4165,7 +4541,7 @@ bool Parser::parseExclusiveOrExpression(ExpressionAST *&node, bool templArgs) while (token_stream.lookAhead() == '^') { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parseAndExpression(rightExpr, templArgs)) @@ -4193,7 +4569,7 @@ bool Parser::parseInclusiveOrExpression(ExpressionAST *&node, bool templArgs) while (token_stream.lookAhead() == '|') { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parseExclusiveOrExpression(rightExpr, templArgs)) @@ -4221,7 +4597,7 @@ bool Parser::parseLogicalAndExpression(ExpressionAST *&node, bool templArgs) while (token_stream.lookAhead() == Token_and) { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parseInclusiveOrExpression(rightExpr, templArgs)) @@ -4249,7 +4625,7 @@ bool Parser::parseLogicalOrExpression(ExpressionAST *&node, bool templArgs) while (token_stream.lookAhead() == Token_or) { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parseLogicalAndExpression(rightExpr, templArgs)) @@ -4276,7 +4652,7 @@ bool Parser::parseConditionalExpression(ExpressionAST *&node) if (token_stream.lookAhead() == '?') { - token_stream.nextToken(); + nextToken(); ExpressionAST *leftExpr = 0; if (!parseExpression(leftExpr)) @@ -4315,7 +4691,7 @@ bool Parser::parseAssignmentExpression(ExpressionAST *&node) || token_stream.lookAhead() == '=') { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parseConditionalExpression(rightExpr)) @@ -4353,7 +4729,7 @@ bool Parser::parseCommaExpression(ExpressionAST *&node) while (token_stream.lookAhead() == ',') { std::size_t op = token_stream.cursor(); - token_stream.nextToken(); + nextToken(); ExpressionAST *rightExpr = 0; if (!parseAssignmentExpression(rightExpr)) @@ -4396,19 +4772,19 @@ bool Parser::parseQ_ENUMS(DeclarationAST *&node) if (token_stream.lookAhead(1) != '(') return false; - token_stream.nextToken(); - token_stream.nextToken(); + nextToken(); + nextToken(); - int firstToken = token_stream.cursor(); + size_t firstToken = token_stream.cursor(); while (token_stream.lookAhead() != ')') { - token_stream.nextToken(); + nextToken(); } QEnumsAST *ast = CreateNode(_M_pool); UPDATE_POS(ast, firstToken, token_stream.cursor()); ast->isQEnum = false; node = ast; - token_stream.nextToken(); + nextToken(); return true; } @@ -4421,37 +4797,33 @@ bool Parser::parseQ_ENUM(DeclarationAST *&node) if (token_stream.lookAhead(1) != '(') return false; - token_stream.nextToken(); - token_stream.nextToken(); + nextToken(); + nextToken(); - int firstToken = token_stream.cursor(); + size_t firstToken = token_stream.cursor(); while (token_stream.lookAhead() != ')') { - token_stream.nextToken(); + nextToken(); } QEnumsAST *ast = CreateNode(_M_pool); UPDATE_POS(ast, firstToken, token_stream.cursor()); node = ast; ast->isQEnum = true; - token_stream.nextToken(); + nextToken(); return true; } bool Parser::parseQ_PROPERTY(DeclarationAST *&node) { - if (token_stream.lookAhead() != Token_Q_PROPERTY) + if (token_stream.lookAhead() != Token_Q_PROPERTY || token_stream.lookAhead(1) != '(') return false; - if (token_stream.lookAhead(1) != '(') - return false; + nextToken(); - token_stream.nextToken(); - token_stream.nextToken(); - - int firstToken = token_stream.cursor(); - while (token_stream.lookAhead() != ')') { - token_stream.nextToken(); + size_t firstToken = token_stream.cursor()+1; + if (!skip('(', ')')) { + return false; } QPropertyAST *ast = CreateNode(_M_pool); UPDATE_POS(ast, firstToken, token_stream.cursor()); @@ -4462,7 +4834,7 @@ bool Parser::parseQ_PROPERTY(DeclarationAST *&node) // printf("property: %s\n", // qPrintable(QString::fromLatin1(t1.text + t1.position, t2.position - t1.position))); - token_stream.nextToken(); + nextToken(); return true; } diff --git a/generator/parser/parser.h b/generator/parser/parser.h index be5e1bf4..fdec18dc 100644 --- a/generator/parser/parser.h +++ b/generator/parser/parser.h @@ -93,17 +93,18 @@ class Parser bool parseDeclaration(DeclarationAST *&node); bool parseDeclarationInternal(DeclarationAST *&node); bool parseDeclarationStatement(StatementAST *&node); - bool parseDeclarator(DeclaratorAST *&node); + bool parseDeclarator(DeclaratorAST *&node, bool asParameter = false); + bool parseDeclaratorParametersAndSuffix(DeclaratorAST* node); bool parseDeleteExpression(ExpressionAST *&node); bool parseDoStatement(StatementAST *&node); bool parseElaboratedTypeSpecifier(TypeSpecifierAST *&node); bool parseEnumSpecifier(TypeSpecifierAST *&node); bool parseEnumerator(EnumeratorAST *&node); bool parseEqualityExpression(ExpressionAST *&node, - bool templArgs = false); + bool templArgs = false); bool parseExceptionSpecification(ExceptionSpecificationAST *&node); bool parseExclusiveOrExpression(ExpressionAST *&node, - bool templArgs = false); + bool templArgs = false); bool parseExpression(ExpressionAST *&node); bool parseExpressionOrDeclarationStatement(StatementAST *&node); bool parseExpressionStatement(StatementAST *&node); @@ -113,18 +114,18 @@ class Parser bool parseFunctionSpecifier(const ListNode *&node); bool parseIfStatement(StatementAST *&node); bool parseInclusiveOrExpression(ExpressionAST *&node, - bool templArgs = false); + bool templArgs = false); bool parseInitDeclarator(InitDeclaratorAST *&node); bool parseInitDeclaratorList(const ListNode *&node); - bool parseInitializer(InitializerAST *&node); + bool parseInitializer(InitializerAST *&node, bool allowNewStyle); bool parseInitializerClause(InitializerClauseAST *&node); bool parseLabeledStatement(StatementAST *&node); bool parseLinkageBody(LinkageBodyAST *&node); bool parseLinkageSpecification(DeclarationAST *&node); bool parseLogicalAndExpression(ExpressionAST *&node, - bool templArgs = false); + bool templArgs = false); bool parseLogicalOrExpression(ExpressionAST *&node, - bool templArgs = false); + bool templArgs = false); bool parseMemInitializer(MemInitializerAST *&node); bool parseMemInitializerList(const ListNode *&node); bool parseMemberSpecification(DeclarationAST *&node); @@ -147,18 +148,19 @@ class Parser bool parsePrimaryExpression(ExpressionAST *&node); bool parsePtrOperator(PtrOperatorAST *&node); bool parsePtrToMember(PtrToMemberAST *&node); + void resolveRightShift(); bool parseRelationalExpression(ExpressionAST *&node, - bool templArgs = false); + bool templArgs = false); bool parseShiftExpression(ExpressionAST *&node); bool parseSimpleTypeSpecifier(TypeSpecifierAST *&node, - bool onlyIntegral = false); + bool onlyIntegral = false); bool parseStatement(StatementAST *&node); bool parseStorageClassSpecifier(const ListNode *&node); bool parseStringLiteral(StringLiteralAST *&node); bool parseSwitchStatement(StatementAST *&node); bool parseTemplateArgument(TemplateArgumentAST *&node); bool parseTemplateArgumentList(const ListNode *&node, - bool reportError = true); + bool reportError = true); bool parseTemplateDeclaration(DeclarationAST *&node); bool parseTemplateParameter(TemplateParameterAST *&node); bool parseTemplateParameterList(const ListNode *&node); @@ -173,8 +175,9 @@ class Parser bool parseTypedef(DeclarationAST *&node); bool parseUnaryExpression(ExpressionAST *&node); bool parseUnqualifiedName(UnqualifiedNameAST *&node, - bool parseTemplateId = true); + bool parseTemplateId = true); bool parseUsing(DeclarationAST *&node); + bool parseUsingTypedef(DeclarationAST*& node); bool parseUsingDirective(DeclarationAST *&node); bool parseWhileStatement(StatementAST *&node); bool parseWinDeclSpec(WinDeclSpecAST *&node); @@ -183,12 +186,15 @@ class Parser bool parseQ_ENUMS(DeclarationAST *&node); bool parseQ_ENUM(DeclarationAST *&node); + bool skipAlignas(); + bool skipAttributes(); bool skipUntil(int token); bool skipUntilDeclaration(); bool skipUntilStatement(); bool skip(int l, int r); - void advance(); + void nextToken(); + void rewind(std::size_t pos); // private: TokenStream token_stream; @@ -199,6 +205,7 @@ class Parser private: QString tokenText(AST *) const; + void keepTrackDebug(); LocationManager _M_location; Control *control; @@ -206,6 +213,12 @@ class Parser pool *_M_pool; bool _M_block_errors; + QString _currentFile; + int _currentLine{}; + int _currentColumn{}; + const char* _currentToken{}; + QString _currentSymbol; + private: Parser(const Parser& source); void operator = (const Parser& source); diff --git a/generator/parser/rpp/pp-engine-bits.h b/generator/parser/rpp/pp-engine-bits.h index 4210eb82..b9013dd9 100644 --- a/generator/parser/rpp/pp-engine-bits.h +++ b/generator/parser/rpp/pp-engine-bits.h @@ -74,14 +74,14 @@ inline bool pp::is_absolute(std::string const &filename) const } template -void pp::file (std::string const &filename, _OutputIterator __result) +void pp::file (std::string const &filename, _OutputIterator _result) { FILE *fp = fopen (filename.c_str(), "rb"); if (fp != 0) { std::string was = env.current_file; env.current_file = filename; - file (fp, __result); + file (fp, _result); env.current_file = was; } //else @@ -89,7 +89,7 @@ void pp::file (std::string const &filename, _OutputIterator __result) } template -void pp::file (FILE *fp, _OutputIterator __result) +void pp::file (FILE *fp, _OutputIterator _result) { assert (fp != 0); @@ -102,7 +102,7 @@ void pp::file (FILE *fp, _OutputIterator __result) fclose (fp); if (!buffer || buffer == (char*) -1) return; - this->operator () (buffer, buffer + size, __result); + this->operator () (buffer, buffer + size, _result); ::munmap(buffer, size); #else std::string buffer; @@ -113,54 +113,54 @@ void pp::file (FILE *fp, _OutputIterator __result) buffer += tmp; } fclose (fp); - this->operator () (buffer.c_str(), buffer.c_str() + buffer.size(), __result); + this->operator () (buffer.c_str(), buffer.c_str() + buffer.size(), _result); #endif } -template -bool pp::find_header_protection (_InputIterator __first, _InputIterator __last, std::string *__prot) +template +bool pp::find_header_protection (InputIterator _first, InputIterator _last, std::string *_prot) { int was = env.current_line; - while (__first != __last) + while (_first != _last) { - if (pp_isspace (*__first)) + if (pp_isspace (*_first)) { - if (*__first == '\n') + if (*_first == '\n') ++env.current_line; - ++__first; + ++_first; } - else if (_PP_internal::comment_p (__first, __last)) + else if (_PP_internal::comment_p (_first, _last)) { - __first = skip_comment_or_divop (__first, __last); + _first = skip_comment_or_divop (_first, _last); env.current_line += skip_comment_or_divop.lines; } - else if (*__first == '#') + else if (*_first == '#') { - __first = skip_blanks (++__first, __last); + _first = skip_blanks (++_first, _last); env.current_line += skip_blanks.lines; - if (__first != __last && *__first == 'i') + if (_first != _last && *_first == 'i') { - _InputIterator __begin = __first; - __first = skip_identifier (__begin, __last); + InputIterator begin = _first; + _first = skip_identifier (begin, _last); env.current_line += skip_identifier.lines; - std::string __directive (__begin, __first); + std::string directive (begin, _first); - if (__directive == "ifndef") + if (directive == "ifndef") { - __first = skip_blanks (__first, __last); + _first = skip_blanks (_first, _last); env.current_line += skip_blanks.lines; - __begin = __first; - __first = skip_identifier (__first, __last); + begin = _first; + _first = skip_identifier (_first, _last); env.current_line += skip_identifier.lines; - if (__begin != __first && __first != __last) + if (begin != _first && _first != _last) { - __prot->assign (__begin, __first); + _prot->assign (begin, _first); return true; } } @@ -175,123 +175,123 @@ bool pp::find_header_protection (_InputIterator __first, _InputIterator __last, return false; } -inline pp::PP_DIRECTIVE_TYPE pp::find_directive (char const *__directive, std::size_t __size) const +inline pp::PP_DIRECTIVE_TYPE pp::find_directive (char const *_directive, std::size_t _size) const { - switch (__size) + switch (_size) { case 2: - if (__directive[0] == 'i' - && __directive[1] == 'f') + if (_directive[0] == 'i' + && _directive[1] == 'f') return PP_IF; break; case 4: - if (__directive[0] == 'e' && !strcmp (__directive, "elif")) + if (_directive[0] == 'e' && !strcmp (_directive, "elif")) return PP_ELIF; - else if (__directive[0] == 'e' && !strcmp (__directive, "else")) + else if (_directive[0] == 'e' && !strcmp (_directive, "else")) return PP_ELSE; break; case 5: - if (__directive[0] == 'i' && !strcmp (__directive, "ifdef")) + if (_directive[0] == 'i' && !strcmp (_directive, "ifdef")) return PP_IFDEF; - else if (__directive[0] == 'u' && !strcmp (__directive, "undef")) + else if (_directive[0] == 'u' && !strcmp (_directive, "undef")) return PP_UNDEF; - else if (__directive[0] == 'e') { - if (!strcmp (__directive, "endif")) + else if (_directive[0] == 'e') { + if (!strcmp (_directive, "endif")) return PP_ENDIF; - else if (!strcmp (__directive, "error")) + else if (!strcmp (_directive, "error")) return PP_ERROR; } break; case 6: - if (__directive[0] == 'i' && !strcmp (__directive, "ifndef")) + if (_directive[0] == 'i' && !strcmp (_directive, "ifndef")) return PP_IFNDEF; - else if (__directive[0] == 'd' && !strcmp (__directive, "define")) + else if (_directive[0] == 'd' && !strcmp (_directive, "define")) return PP_DEFINE; - else if (__directive[0] == 'p' && !strcmp (__directive, "pragma")) + else if (_directive[0] == 'p' && !strcmp (_directive, "pragma")) return PP_PRAGMA; break; case 7: - if (__directive[0] == 'i' && !strcmp (__directive, "include")) + if (_directive[0] == 'i' && !strcmp (_directive, "include")) return PP_INCLUDE; - else if (__directive[0] == 'w' && !strcmp(__directive, "warning")) + else if (_directive[0] == 'w' && !strcmp(_directive, "warning")) return PP_WARNING; break; case 12: - if (__directive[0] == 'i' && !strcmp (__directive, "include_next")) + if (_directive[0] == 'i' && !strcmp (_directive, "include_next")) return PP_INCLUDE_NEXT; break; default: break; } - if (strlen(__directive)) { - std::cerr << "** WARNING unknown directive '#" << __directive << "' at " << env.current_file << ":" << env.current_line << std::endl; + if (strlen(_directive)) { + std::cerr << "** WARNING unknown directive '#" << _directive << "' at " << env.current_file << ":" << env.current_line << std::endl; } return PP_UNKNOWN_DIRECTIVE; } -inline bool pp::file_isdir (std::string const &__filename) const +inline bool pp::file_isdir (std::string const &_filename) const { - struct stat __st; + struct stat st; #if defined(PP_OS_WIN) - if (stat(__filename.c_str (), &__st) == 0) - return (__st.st_mode & _S_IFDIR) == _S_IFDIR; + if (stat(_filename.c_str (), &st) == 0) + return (st.st_mode & _S_IFDIR) == _S_IFDIR; else return false; #else - if (lstat (__filename.c_str (), &__st) == 0) - return (__st.st_mode & S_IFDIR) == S_IFDIR; + if (lstat(_filename.c_str (), &st) == 0) + return (st.st_mode & S_IFDIR) == S_IFDIR; else return false; #endif } -inline bool pp::file_exists (std::string const &__filename) const +inline bool pp::file_exists (std::string const &_filename) const { - struct stat __st; + struct stat st; #if defined(PP_OS_WIN) - return stat(__filename.c_str (), &__st) == 0; + return stat(_filename.c_str (), &st) == 0; #else - return lstat (__filename.c_str (), &__st) == 0; + return lstat (_filename.c_str (), &st) == 0; #endif } -inline FILE *pp::find_include_file(std::string const &__input_filename, std::string *__filepath, - INCLUDE_POLICY __include_policy, bool __skip_current_path) const +inline FILE *pp::find_include_file(std::string const &_input_filename, std::string *_filepath, + INCLUDE_POLICY _include_policy, bool _skip_current_path) const { - assert (__filepath != 0); - assert (! __input_filename.empty()); + assert (_filepath != 0); + assert (! _input_filename.empty()); - __filepath->assign (__input_filename); + _filepath->assign (_input_filename); - if (is_absolute (*__filepath)) - return fopen (__filepath->c_str(), "r"); + if (is_absolute (*_filepath)) + return fopen (_filepath->c_str(), "r"); if (! env.current_file.empty ()) - _PP_internal::extract_file_path (env.current_file, __filepath); + _PP_internal::extract_file_path (env.current_file, _filepath); - if (__include_policy == INCLUDE_LOCAL && ! __skip_current_path) + if (_include_policy == INCLUDE_LOCAL && ! _skip_current_path) { - std::string __tmp (*__filepath); - __tmp += __input_filename; + std::string tmp (*_filepath); + tmp += _input_filename; - if (file_exists (__tmp) && !file_isdir(__tmp)) + if (file_exists (tmp) && !file_isdir(tmp)) { - __filepath->append (__input_filename); - return fopen (__filepath->c_str (), "r"); + _filepath->append (_input_filename); + return fopen (_filepath->c_str (), "r"); } } std::vector::const_iterator it = include_paths.begin (); - if (__skip_current_path) + if (_skip_current_path) { - it = std::find (include_paths.begin (), include_paths.end (), *__filepath); + it = std::find (include_paths.begin (), include_paths.end (), *_filepath); if (it != include_paths.end ()) ++it; @@ -302,28 +302,28 @@ inline FILE *pp::find_include_file(std::string const &__input_filename, std::str for (; it != include_paths.end (); ++it) { - if (__skip_current_path && it == include_paths.begin()) + if (_skip_current_path && it == include_paths.begin()) continue; - __filepath->assign (*it); - __filepath->append (__input_filename); + _filepath->assign (*it); + _filepath->append (_input_filename); - if (file_exists (*__filepath) && !file_isdir(*__filepath)) - return fopen (__filepath->c_str(), "r"); + if (file_exists (*_filepath) && !file_isdir(*_filepath)) + return fopen (_filepath->c_str(), "r"); #ifdef Q_OS_MAC // try in Framework path on Mac, if there is a path in front // ### what about escaped slashes? - size_t slashPos = __input_filename.find('/'); + size_t slashPos = _input_filename.find('/'); if (slashPos != std::string::npos) { - __filepath->assign (*it); - __filepath->append (__input_filename.substr(0, slashPos)); - __filepath->append (".framework/Headers/"); - __filepath->append (__input_filename.substr(slashPos+1, std::string::npos)); - std::cerr << *__filepath << "\n"; - - if (file_exists (*__filepath) && !file_isdir(*__filepath)) - return fopen (__filepath->c_str(), "r"); + _filepath->assign (*it); + _filepath->append (_input_filename.substr(0, slashPos)); + _filepath->append (".framework/Headers/"); + _filepath->append (_input_filename.substr(slashPos+1, std::string::npos)); + std::cerr << *_filepath << "\n"; + + if (file_exists (*_filepath) && !file_isdir(*_filepath)) + return fopen (_filepath->c_str(), "r"); } #endif // Q_OS_MAC } @@ -331,81 +331,81 @@ inline FILE *pp::find_include_file(std::string const &__input_filename, std::str return 0; } -template -_InputIterator pp::handle_directive(char const *__directive, std::size_t __size, - _InputIterator __first, _InputIterator __last, _OutputIterator __result) +template +InputIterator pp::handle_directive(char const *_directive, std::size_t _size, + InputIterator _first, InputIterator _last, OutputIterator _result) { - __first = skip_blanks (__first, __last); + _first = skip_blanks (_first, _last); - PP_DIRECTIVE_TYPE d = find_directive (__directive, __size); + PP_DIRECTIVE_TYPE d = find_directive (_directive, _size); switch (d) { case PP_DEFINE: if (! skipping ()) - return handle_define (__first, __last); + return handle_define (_first, _last); break; case PP_INCLUDE: case PP_INCLUDE_NEXT: if (! skipping ()) - return handle_include (d == PP_INCLUDE_NEXT, __first, __last, __result); + return handle_include (d == PP_INCLUDE_NEXT, _first, _last, _result); break; case PP_UNDEF: if (! skipping ()) - return handle_undef(__first, __last); + return handle_undef(_first, _last); break; case PP_ELIF: - return handle_elif (__first, __last); + return handle_elif (_first, _last); case PP_ELSE: - return handle_else (__first, __last); + return handle_else (_first, _last); case PP_ENDIF: - return handle_endif (__first, __last); + return handle_endif (_first, _last); case PP_IF: - return handle_if (__first, __last); + return handle_if (_first, _last); case PP_IFDEF: - return handle_ifdef (false, __first, __last); + return handle_ifdef (false, _first, _last); case PP_IFNDEF: - return handle_ifdef (true, __first, __last); + return handle_ifdef (true, _first, _last); default: break; } - return __first; + return _first; } -template -_InputIterator pp::handle_include (bool __skip_current_path, _InputIterator __first, _InputIterator __last, - _OutputIterator __result) +template +InputIterator pp::handle_include (bool _skip_current_path, InputIterator _first, InputIterator _last, + OutputIterator _result) { // uncomment to print included files // std::cout << env.current_file << std::endl; - if (pp_isalpha (*__first) || *__first == '_') + if (pp_isalpha (*_first) || *_first == '_') { pp_macro_expander expand_include (env); std::string name; name.reserve (255); - expand_include (__first, __last, std::back_inserter (name)); + expand_include (_first, _last, std::back_inserter (name)); std::string::iterator it = skip_blanks (name.begin (), name.end ()); printf("%s", name.c_str()); assert((it != name.end () && (*it == '<' || *it == '"'))); - handle_include (__skip_current_path, it, name.end (), __result); - return __first; + handle_include (_skip_current_path, it, name.end (), _result); + return _first; } - assert (*__first == '<' || *__first == '"'); - int quote = (*__first == '"') ? '"' : '>'; - ++__first; + assert (*_first == '<' || *_first == '"'); + int quote = (*_first == '"') ? '"' : '>'; + ++_first; - _InputIterator end_name = __first; - for (; end_name != __last; ++end_name) + InputIterator end_name = _first; + for (; end_name != _last; ++end_name) { assert (*end_name != '\n'); @@ -413,14 +413,14 @@ _InputIterator pp::handle_include (bool __skip_current_path, _InputIterator __fi break; } - std::string filename (__first, end_name); + std::string filename (_first, end_name); #ifdef PP_OS_WIN std::replace(filename.begin(), filename.end(), '/', '\\'); #endif std::string filepath; - FILE *fp = find_include_file (filename, &filepath, quote == '>' ? INCLUDE_GLOBAL : INCLUDE_LOCAL, __skip_current_path); + FILE *fp = find_include_file (filename, &filepath, quote == '>' ? INCLUDE_GLOBAL : INCLUDE_LOCAL, _skip_current_path); #if defined (PP_HOOK_ON_FILE_INCLUDED) PP_HOOK_ON_FILE_INCLUDED (env.current_file, fp ? filepath : filename, fp); @@ -430,103 +430,103 @@ _InputIterator pp::handle_include (bool __skip_current_path, _InputIterator __fi { std::string old_file = env.current_file; env.current_file = filepath; - int __saved_lines = env.current_line; + int saved_lines = env.current_line; env.current_line = 1; - //output_line (env.current_file, 1, __result); + //output_line (env.current_file, 1, _result); - file (fp, __result); + file (fp, _result); // restore the file name and the line position env.current_file = old_file; - env.current_line = __saved_lines; + env.current_line = saved_lines; // sync the buffer - _PP_internal::output_line (env.current_file, env.current_line, __result); + _PP_internal::output_line (env.current_file, env.current_line, _result); } #ifndef RPP_JAMBI // else // std::cerr << "*** WARNING " << filename << ": No such file or directory" << std::endl; #endif - return __first; + return _first; } -template -void pp::operator () (_InputIterator __first, _InputIterator __last, _OutputIterator __result) +template +void pp::operator () (InputIterator _first, InputIterator _last, OutputIterator _result) { #ifndef PP_NO_SMART_HEADER_PROTECTION - std::string __prot; - __prot.reserve (255); - pp_fast_string __tmp (__prot.c_str (), __prot.size ()); + std::string prot; + prot.reserve (255); + pp_fast_string tmp (prot.c_str (), prot.size ()); - if (find_header_protection (__first, __last, &__prot) - && env.resolve (&__tmp) != 0) + if (find_header_protection (_first, _last, &prot) + && env.resolve (&tmp) != 0) { - // std::cerr << "** DEBUG found header protection:" << __prot << std::endl; + // std::cerr << "** DEBUG found header protection:" << prot << std::endl; return; } #endif env.current_line = 1; - char __buffer[512]; + char buffer[512]; while (true) { - __first = skip_blanks (__first, __last); + _first = skip_blanks (_first, _last); env.current_line += skip_blanks.lines; - if (__first == __last) + if (_first == _last) break; - else if (*__first == '#') + else if (*_first == '#') { - assert (*__first == '#'); - __first = skip_blanks (++__first, __last); + assert (*_first == '#'); + _first = skip_blanks (++_first, _last); env.current_line += skip_blanks.lines; - _InputIterator end_id = skip_identifier (__first, __last); + InputIterator end_id = skip_identifier (_first, _last); env.current_line += skip_identifier.lines; - std::size_t __size = end_id - __first; + std::size_t size = end_id - _first; - assert (__size < 512); - char *__cp = __buffer; - std::copy (__first, end_id, __cp); - __cp[__size] = '\0'; + assert (size < 512); + char *cp = buffer; + std::copy (_first, end_id, cp); + cp[size] = '\0'; - end_id = skip_blanks (end_id, __last); - __first = skip (end_id, __last); + end_id = skip_blanks (end_id, _last); + _first = skip (end_id, _last); int was = env.current_line; - (void) handle_directive (__buffer, __size, end_id, __first, __result); + (void) handle_directive (buffer, size, end_id, _first, _result); if (env.current_line != was) { env.current_line = was; - _PP_internal::output_line (env.current_file, env.current_line, __result); + _PP_internal::output_line (env.current_file, env.current_line, _result); } } - else if (*__first == '\n') + else if (*_first == '\n') { // ### compress the line - *__result++ = *__first++; + *_result++ = *_first++; ++env.current_line; } else if (skipping ()) - __first = skip (__first, __last); + _first = skip (_first, _last); else { - _PP_internal::output_line (env.current_file, env.current_line, __result); - __first = expand (__first, __last, __result); + _PP_internal::output_line (env.current_file, env.current_line, _result); + _first = expand (_first, _last, _result); env.current_line += expand.lines; if (expand.generated_lines) - _PP_internal::output_line (env.current_file, env.current_line, __result); + _PP_internal::output_line (env.current_file, env.current_line, _result); } } } -inline pp::pp (pp_environment &__env): - env (__env), expand (env), skip_comment(false) +inline pp::pp (pp_environment &_env): + env (_env), expand (env), skip_comment(false) { iflevel = 0; _M_skipping[iflevel] = 0; @@ -548,21 +548,21 @@ inline std::vector::const_iterator pp::include_paths_begin () const inline std::vector::const_iterator pp::include_paths_end () const { return include_paths.end (); } -inline void pp::push_include_path (std::string const &__path) +inline void pp::push_include_path (std::string const &_path) { - if (__path.empty () || __path [__path.size () - 1] != PATH_SEPARATOR) + if (_path.empty () || _path [_path.size () - 1] != PATH_SEPARATOR) { - std::string __tmp (__path); - __tmp += PATH_SEPARATOR; - include_paths.push_back (__tmp); + std::string tmp (_path); + tmp += PATH_SEPARATOR; + include_paths.push_back (tmp); } else - include_paths.push_back (__path); + include_paths.push_back (_path); } -template -_InputIterator pp::handle_define (_InputIterator __first, _InputIterator __last) +template +InputIterator pp::handle_define (InputIterator _first, InputIterator _last) { pp_macro macro; #if defined (PP_WITH_MACRO_POSITION) @@ -570,123 +570,123 @@ _InputIterator pp::handle_define (_InputIterator __first, _InputIterator __last) #endif std::string definition; - __first = skip_blanks (__first, __last); - _InputIterator end_macro_name = skip_identifier (__first, __last); - pp_fast_string const *macro_name = pp_symbol::get (__first, end_macro_name); - __first = end_macro_name; + _first = skip_blanks (_first, _last); + InputIterator end_macro_name = skip_identifier (_first, _last); + pp_fast_string const *macro_name = pp_symbol::get (_first, end_macro_name); + _first = end_macro_name; - if (__first != __last && *__first == '(') + if (_first != _last && *_first == '(') { - macro.function_like = true; + macro.is.function_like = true; macro.formals.reserve (5); - __first = skip_blanks (++__first, __last); // skip '(' - _InputIterator arg_end = skip_identifier (__first, __last); - if (__first != arg_end) - macro.formals.push_back (pp_symbol::get (__first, arg_end)); + _first = skip_blanks (++_first, _last); // skip '(' + InputIterator arg_end = skip_identifier (_first, _last); + if (_first != arg_end) + macro.formals.push_back (pp_symbol::get (_first, arg_end)); - __first = skip_blanks (arg_end, __last); + _first = skip_blanks (arg_end, _last); - if (*__first == '.') + if (*_first == '.') { - macro.variadics = true; - while (*__first == '.') - ++__first; + macro.is.variadics = true; + while (*_first == '.') + ++_first; } - while (__first != __last && *__first == ',') + while (_first != _last && *_first == ',') { - __first = skip_blanks (++__first, __last); + _first = skip_blanks (++_first, _last); - arg_end = skip_identifier (__first, __last); - if (__first != arg_end) - macro.formals.push_back (pp_symbol::get (__first, arg_end)); + arg_end = skip_identifier (_first, _last); + if (_first != arg_end) + macro.formals.push_back (pp_symbol::get (_first, arg_end)); - __first = skip_blanks (arg_end, __last); + _first = skip_blanks (arg_end, _last); - if (*__first == '.') + if (*_first == '.') { - macro.variadics = true; - while (*__first == '.') - ++__first; + macro.is.variadics = true; + while (*_first == '.') + ++_first; } } - assert (*__first == ')'); - ++__first; + assert (*_first == ')'); + ++_first; } - __first = skip_blanks (__first, __last); + _first = skip_blanks (_first, _last); - while (__first != __last && *__first != '\n') + while (_first != _last && *_first != '\n') { - if (*__first == '/') { - __first = skip_comment(__first, __last); + if (*_first == '/') { + _first = skip_comment(_first, _last); env.current_line += skip_comment.lines; } - if (*__first == '\\') + if (*_first == '\\') { - _InputIterator __begin = __first; - __begin = skip_blanks (++__begin, __last); + InputIterator begin = _first; + begin = skip_blanks (++begin, _last); - if (__begin != __last && *__begin == '\n') + if (begin != _last && *begin == '\n') { ++macro.lines; - __first = skip_blanks (++__begin, __last); + _first = skip_blanks (++begin, _last); definition += ' '; continue; } } - definition += *__first++; + definition += *_first++; } macro.definition = pp_symbol::get (definition); env.bind (macro_name, macro); - return __first; + return _first; } -template -_InputIterator pp::skip (_InputIterator __first, _InputIterator __last) +template +InputIterator pp::skip (InputIterator _first, InputIterator _last) { pp_skip_string_literal skip_string_literal; pp_skip_char_literal skip_char_literal; - while (__first != __last && *__first != '\n') + while (_first != _last && *_first != '\n') { - if (*__first == '/') + if (*_first == '/') { - __first = skip_comment_or_divop (__first, __last); + _first = skip_comment_or_divop (_first, _last); env.current_line += skip_comment_or_divop.lines; } - else if (*__first == '"') + else if (*_first == '"') { - __first = skip_string_literal (__first, __last); + _first = skip_string_literal (_first, _last); env.current_line += skip_string_literal.lines; } - else if (*__first == '\'') + else if (*_first == '\'') { - __first = skip_char_literal (__first, __last); + _first = skip_char_literal (_first, _last); env.current_line += skip_char_literal.lines; } - else if (*__first == '\\') + else if (*_first == '\\') { - __first = skip_blanks (++__first, __last); + _first = skip_blanks (++_first, _last); env.current_line += skip_blanks.lines; - if (__first != __last && *__first == '\n') + if (_first != _last && *_first == '\n') { - ++__first; + ++_first; ++env.current_line; } } else - ++__first; + ++_first; } - return __first; + return _first; } inline bool pp::test_if_level() @@ -700,12 +700,12 @@ inline bool pp::test_if_level() inline int pp::skipping() const { return _M_skipping[iflevel]; } -template -_InputIterator pp::eval_primary(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_primary(InputIterator _first, InputIterator _last, Value *result) { bool expect_paren = false; int token; - __first = next_token (__first, __last, &token); + _first = next_token (_first, _last, &token); switch (token) { @@ -718,12 +718,12 @@ _InputIterator pp::eval_primary(_InputIterator __first, _InputIterator __last, V break; case TOKEN_DEFINED: - __first = next_token (__first, __last, &token); + _first = next_token (_first, _last, &token); if (token == '(') { expect_paren = true; - __first = next_token (__first, __last, &token); + _first = next_token (_first, _last, &token); } if (token != TOKEN_IDENTIFIER) @@ -735,15 +735,15 @@ _InputIterator pp::eval_primary(_InputIterator __first, _InputIterator __last, V result->set_long (env.resolve (token_text->c_str (), token_text->size ()) != 0); - next_token (__first, __last, &token); // skip '(' + next_token (_first, _last, &token); // skip '(' if (expect_paren) { - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); if (token != ')') std::cerr << "** WARNING expected ``)'' at " << env.current_file << ":" << env.current_line << std::endl; else - __first = next; + _first = next; } break; @@ -752,48 +752,48 @@ _InputIterator pp::eval_primary(_InputIterator __first, _InputIterator __last, V break; case '-': - __first = eval_primary (__first, __last, result); + _first = eval_primary (_first, _last, result); result->set_long (- result->l); - return __first; + return _first; case '+': - __first = eval_primary (__first, __last, result); - return __first; + _first = eval_primary (_first, _last, result); + return _first; case '!': - __first = eval_primary (__first, __last, result); + _first = eval_primary (_first, _last, result); result->set_long (result->is_zero ()); - return __first; + return _first; case '(': - __first = eval_constant_expression(__first, __last, result); - next_token (__first, __last, &token); + _first = eval_constant_expression(_first, _last, result); + next_token (_first, _last, &token); if (token != ')') std::cerr << "** WARNING expected ``)'' = " << token << " at " << env.current_file << ":" << env.current_line << std::endl; else - __first = next_token(__first, __last, &token); + _first = next_token(_first, _last, &token); break; default: result->set_long (0); } - return __first; + return _first; } -template -_InputIterator pp::eval_multiplicative(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_multiplicative(InputIterator _first, InputIterator _last, Value *result) { - __first = eval_primary(__first, __last, result); + _first = eval_primary(_first, _last, result); int token; - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); while (token == '*' || token == '/' || token == '%') { Value value; - __first = eval_primary(next, __last, &value); + _first = eval_primary(next, _last, &value); if (token == '*') result->op_mult (value); @@ -817,65 +817,65 @@ _InputIterator pp::eval_multiplicative(_InputIterator __first, _InputIterator __ else result->op_mod (value); } - next = next_token (__first, __last, &token); + next = next_token (_first, _last, &token); } - return __first; + return _first; } -template -_InputIterator pp::eval_additive(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_additive(InputIterator _first, InputIterator _last, Value *result) { - __first = eval_multiplicative(__first, __last, result); + _first = eval_multiplicative(_first, _last, result); int token; - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); while (token == '+' || token == '-') { Value value; - __first = eval_multiplicative(next, __last, &value); + _first = eval_multiplicative(next, _last, &value); if (token == '+') result->op_add (value); else result->op_sub (value); - next = next_token (__first, __last, &token); + next = next_token (_first, _last, &token); } - return __first; + return _first; } -template -_InputIterator pp::eval_shift(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_shift(InputIterator _first, InputIterator _last, Value *result) { - __first = eval_additive(__first, __last, result); + _first = eval_additive(_first, _last, result); int token; - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); while (token == TOKEN_LT_LT || token == TOKEN_GT_GT) { Value value; - __first = eval_additive (next, __last, &value); + _first = eval_additive (next, _last, &value); if (token == TOKEN_LT_LT) result->op_lhs (value); else result->op_rhs (value); - next = next_token (__first, __last, &token); + next = next_token (_first, _last, &token); } - return __first; + return _first; } -template -_InputIterator pp::eval_relational(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_relational(InputIterator _first, InputIterator _last, Value *result) { - __first = eval_shift(__first, __last, result); + _first = eval_shift(_first, _last, result); int token; - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); while (token == '<' || token == '>' @@ -883,7 +883,7 @@ _InputIterator pp::eval_relational(_InputIterator __first, _InputIterator __last || token == TOKEN_GT_EQ) { Value value; - __first = eval_shift(next, __last, &value); + _first = eval_shift(next, _last, &value); switch (token) { @@ -907,149 +907,149 @@ _InputIterator pp::eval_relational(_InputIterator __first, _InputIterator __last result->op_ge (value); break; } - next = next_token (__first, __last, &token); + next = next_token (_first, _last, &token); } - return __first; + return _first; } -template -_InputIterator pp::eval_equality(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_equality(InputIterator _first, InputIterator _last, Value *result) { - __first = eval_relational(__first, __last, result); + _first = eval_relational(_first, _last, result); int token; - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); while (token == TOKEN_EQ_EQ || token == TOKEN_NOT_EQ) { Value value; - __first = eval_relational(next, __last, &value); + _first = eval_relational(next, _last, &value); if (token == TOKEN_EQ_EQ) result->op_eq (value); else result->op_ne (value); - next = next_token (__first, __last, &token); + next = next_token (_first, _last, &token); } - return __first; + return _first; } -template -_InputIterator pp::eval_and(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_and(InputIterator _first, InputIterator _last, Value *result) { - __first = eval_equality(__first, __last, result); + _first = eval_equality(_first, _last, result); int token; - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); while (token == '&') { Value value; - __first = eval_equality(next, __last, &value); + _first = eval_equality(next, _last, &value); result->op_bit_and (value); - next = next_token (__first, __last, &token); + next = next_token (_first, _last, &token); } - return __first; + return _first; } -template -_InputIterator pp::eval_xor(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_xor(InputIterator _first, InputIterator _last, Value *result) { - __first = eval_and(__first, __last, result); + _first = eval_and(_first, _last, result); int token; - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); while (token == '^') { Value value; - __first = eval_and(next, __last, &value); + _first = eval_and(next, _last, &value); result->op_bit_xor (value); - next = next_token (__first, __last, &token); + next = next_token (_first, _last, &token); } - return __first; + return _first; } -template -_InputIterator pp::eval_or(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_or(InputIterator _first, InputIterator _last, Value *result) { - __first = eval_xor(__first, __last, result); + _first = eval_xor(_first, _last, result); int token; - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); while (token == '|') { Value value; - __first = eval_xor(next, __last, &value); + _first = eval_xor(next, _last, &value); result->op_bit_or (value); - next = next_token (__first, __last, &token); + next = next_token (_first, _last, &token); } - return __first; + return _first; } -template -_InputIterator pp::eval_logical_and(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_logical_and(InputIterator _first, InputIterator _last, Value *result) { - __first = eval_or(__first, __last, result); + _first = eval_or(_first, _last, result); int token; - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); while (token == TOKEN_AND_AND) { Value value; - __first = eval_or(next, __last, &value); + _first = eval_or(next, _last, &value); result->op_and (value); - next = next_token (__first, __last, &token); + next = next_token (_first, _last, &token); } - return __first; + return _first; } -template -_InputIterator pp::eval_logical_or(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_logical_or(InputIterator _first, InputIterator _last, Value *result) { - __first = eval_logical_and (__first, __last, result); + _first = eval_logical_and (_first, _last, result); int token; - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); while (token == TOKEN_OR_OR) { Value value; - __first = eval_logical_and(next, __last, &value); + _first = eval_logical_and(next, _last, &value); result->op_or (value); - next = next_token (__first, __last, &token); + next = next_token (_first, _last, &token); } - return __first; + return _first; } -template -_InputIterator pp::eval_constant_expression(_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_constant_expression(InputIterator _first, InputIterator _last, Value *result) { - __first = eval_logical_or(__first, __last, result); + _first = eval_logical_or(_first, _last, result); int token; - _InputIterator next = next_token (__first, __last, &token); + InputIterator next = next_token (_first, _last, &token); if (token == '?') { Value left_value; - __first = eval_constant_expression(next, __last, &left_value); - __first = skip_blanks (__first, __last); + _first = eval_constant_expression(next, _last, &left_value); + _first = skip_blanks (_first, _last); - __first = next_token(__first, __last, &token); + _first = next_token(_first, _last, &token); if (token == ':') { Value right_value; - __first = eval_constant_expression(__first, __last, &right_value); + _first = eval_constant_expression(_first, _last, &right_value); *result = !result->is_zero () ? left_value : right_value; } @@ -1060,43 +1060,50 @@ _InputIterator pp::eval_constant_expression(_InputIterator __first, _InputIterat } } - return __first; + return _first; } -template -_InputIterator pp::eval_expression (_InputIterator __first, _InputIterator __last, Value *result) +template +InputIterator pp::eval_expression (InputIterator _first, InputIterator _last, Value *result) { - return __first = eval_constant_expression (skip_blanks (__first, __last), __last, result); + return _first = eval_constant_expression (skip_blanks (_first, _last), _last, result); } -template -_InputIterator pp::handle_if (_InputIterator __first, _InputIterator __last) +template +std::string pp::expand_condition(InputIterator _first, InputIterator _last) +{ + pp_macro_expander expand_condition(env); + std::string condition; + condition.reserve(255); + expand_condition(skip_blanks(_first, _last), _last, std::back_inserter(condition)); + std::string condition2ndpass; + condition2ndpass.reserve(255); + const char* first = condition.c_str(); + const char* last = first + condition.size(); + expand_condition(skip_blanks(first, last), last, std::back_inserter(condition2ndpass)); + return condition2ndpass; +} + +template +InputIterator pp::handle_if (InputIterator _first, InputIterator _last) { if (test_if_level()) { - pp_macro_expander expand_condition (env); - std::string condition; - condition.reserve (255); - expand_condition (skip_blanks (__first, __last), __last, std::back_inserter (condition)); - std::string condition2ndpass; - condition2ndpass.reserve (255); - const char* first = condition.c_str (); - const char* last = first + condition.size (); - expand_condition (skip_blanks (first, last), last, std::back_inserter (condition2ndpass)); + std::string condition = expand_condition(_first, _last); Value result; result.set_long (0); - eval_expression(condition2ndpass.c_str (), condition2ndpass.c_str () + condition2ndpass.size (), &result); + eval_expression(condition.c_str (), condition.c_str () + condition.size (), &result); _M_true_test[iflevel] = !result.is_zero (); _M_skipping[iflevel] = result.is_zero (); } - return __first; + return _first; } -template -_InputIterator pp::handle_else (_InputIterator __first, _InputIterator /*__last*/) +template +InputIterator pp::handle_else (InputIterator __first, InputIterator /*__last*/) { if (iflevel == 0 && !skipping ()) { @@ -1114,8 +1121,8 @@ _InputIterator pp::handle_else (_InputIterator __first, _InputIterator /*__last* return __first; } -template -_InputIterator pp::handle_elif (_InputIterator __first, _InputIterator __last) +template +InputIterator pp::handle_elif (InputIterator _first, InputIterator _last) { assert(iflevel > 0); @@ -1125,8 +1132,11 @@ _InputIterator pp::handle_elif (_InputIterator __first, _InputIterator __last) } else if (!_M_true_test[iflevel] && !_M_skipping[iflevel - 1]) { + std::string condition = expand_condition(_first, _last); + Value result; - __first = eval_expression(__first, __last, &result); + result.set_long(0); + eval_expression(condition.c_str(), condition.c_str() + condition.size(), &result); _M_true_test[iflevel] = !result.is_zero (); _M_skipping[iflevel] = result.is_zero (); } @@ -1135,11 +1145,11 @@ _InputIterator pp::handle_elif (_InputIterator __first, _InputIterator __last) _M_skipping[iflevel] = true; } - return __first; + return _first; } -template -_InputIterator pp::handle_endif (_InputIterator __first, _InputIterator /*__last*/) +template +InputIterator pp::handle_endif (InputIterator _first, InputIterator /*__last*/) { if (iflevel == 0 && !skipping()) { @@ -1153,30 +1163,30 @@ _InputIterator pp::handle_endif (_InputIterator __first, _InputIterator /*__last --iflevel; } - return __first; + return _first; } -template -_InputIterator pp::handle_ifdef (bool check_undefined, _InputIterator __first, _InputIterator __last) +template +InputIterator pp::handle_ifdef (bool check_undefined, InputIterator _first, InputIterator _last) { if (test_if_level()) { - _InputIterator end_macro_name = skip_identifier (__first, __last); + InputIterator end_macro_name = skip_identifier (_first, _last); std::size_t __size; #if defined(__SUNPRO_CC) std::distance (__first, end_macro_name, __size); #else - __size = std::distance (__first, end_macro_name); + __size = std::distance (_first, end_macro_name); #endif assert (__size < 256); char __buffer [256]; - std::copy (__first, end_macro_name, __buffer); + std::copy (_first, end_macro_name, __buffer); bool value = env.resolve (__buffer, __size) != 0; - __first = end_macro_name; + _first = end_macro_name; if (check_undefined) value = !value; @@ -1185,161 +1195,161 @@ _InputIterator pp::handle_ifdef (bool check_undefined, _InputIterator __first, _ _M_skipping[iflevel] = !value; } - return __first; + return _first; } -template -_InputIterator pp::handle_undef(_InputIterator __first, _InputIterator __last) +template +InputIterator pp::handle_undef(InputIterator _first, InputIterator _last) { - __first = skip_blanks (__first, __last); - _InputIterator end_macro_name = skip_identifier (__first, __last); - assert (end_macro_name != __first); + _first = skip_blanks (_first, _last); + InputIterator end_macro_name = skip_identifier (_first, _last); + assert (end_macro_name != _first); std::size_t __size; #if defined(__SUNPRO_CC) std::distance (__first, end_macro_name, __size); #else - __size = std::distance (__first, end_macro_name); + __size = std::distance (_first, end_macro_name); #endif assert (__size < 256); char __buffer [256]; - std::copy (__first, end_macro_name, __buffer); + std::copy (_first, end_macro_name, __buffer); pp_fast_string const __tmp (__buffer, __size); env.unbind (&__tmp); - __first = end_macro_name; + _first = end_macro_name; - return __first; + return _first; } -template -char pp::peek_char (_InputIterator __first, _InputIterator __last) +template +char pp::peek_char (InputIterator _first, InputIterator _last) { - if (__first == __last) + if (_first == _last) return 0; - return *++__first; + return *++_first; } -template -_InputIterator pp::next_token (_InputIterator __first, _InputIterator __last, int *kind) +template +InputIterator pp::next_token (InputIterator _first, InputIterator _last, int *kind) { - __first = skip_blanks (__first, __last); + _first = skip_blanks (_first, _last); - if (__first == __last) + if (_first == _last) { *kind = 0; - return __first; + return _first; } - char ch = *__first; - char ch2 = peek_char (__first, __last); + char ch = *_first; + char ch2 = peek_char (_first, _last); switch (ch) { case '/': if (ch2 == '/' || ch2 == '*') { - __first = skip_comment_or_divop (__first, __last); - return next_token (__first, __last, kind); + _first = skip_comment_or_divop (_first, _last); + return next_token (_first, _last, kind); } - ++__first; + ++_first; *kind = '/'; break; case '<': - ++__first; + ++_first; if (ch2 == '<') { - ++__first; + ++_first; *kind = TOKEN_LT_LT; } else if (ch2 == '=') { - ++__first; + ++_first; *kind = TOKEN_LT_EQ; } else *kind = '<'; - return __first; + return _first; case '>': - ++__first; + ++_first; if (ch2 == '>') { - ++__first; + ++_first; *kind = TOKEN_GT_GT; } else if (ch2 == '=') { - ++__first; + ++_first; *kind = TOKEN_GT_EQ; } else *kind = '>'; - return __first; + return _first; case '!': - ++__first; + ++_first; if (ch2 == '=') { - ++__first; + ++_first; *kind = TOKEN_NOT_EQ; } else *kind = '!'; - return __first; + return _first; case '=': - ++__first; + ++_first; if (ch2 == '=') { - ++__first; + ++_first; *kind = TOKEN_EQ_EQ; } else *kind = '='; - return __first; + return _first; case '|': - ++__first; + ++_first; if (ch2 == '|') { - ++__first; + ++_first; *kind = TOKEN_OR_OR; } else *kind = '|'; - return __first; + return _first; case '&': - ++__first; + ++_first; if (ch2 == '&') { - ++__first; + ++_first; *kind = TOKEN_AND_AND; } else *kind = '&'; - return __first; + return _first; default: if (pp_isalpha (ch) || ch == '_') { - _InputIterator end = skip_identifier (__first, __last); - _M_current_text.assign (__first, end); + InputIterator end = skip_identifier (_first, _last); + _M_current_text.assign (_first, end); token_text = &_M_current_text; - __first = end; + _first = end; if (*token_text == "defined") *kind = TOKEN_DEFINED; @@ -1348,8 +1358,8 @@ _InputIterator pp::next_token (_InputIterator __first, _InputIterator __last, in } else if (pp_isdigit (ch)) { - _InputIterator end = skip_number (__first, __last); - std::string __str (__first, __last); + InputIterator end = skip_number (_first, _last); + std::string __str (_first, _last); char ch = __str [__str.size () - 1]; if (ch == 'u' || ch == 'U') { @@ -1361,13 +1371,13 @@ _InputIterator pp::next_token (_InputIterator __first, _InputIterator __last, in token_value = strtol (__str.c_str (), 0, 0); *kind = TOKEN_NUMBER; } - __first = end; + _first = end; } else - *kind = *__first++; + *kind = *_first++; } - return __first; + return _first; } } // namespace rpp diff --git a/generator/parser/rpp/pp-engine.h b/generator/parser/rpp/pp-engine.h index 7dd22c26..2704fa27 100644 --- a/generator/parser/rpp/pp-engine.h +++ b/generator/parser/rpp/pp-engine.h @@ -171,11 +171,11 @@ class pp }; public: - pp (pp_environment &__env); + pp (pp_environment &env); inline std::back_insert_iterator > include_paths_inserter (); - inline void push_include_path (std::string const &__path); + inline void push_include_path (std::string const &path); inline std::vector::iterator include_paths_begin (); inline std::vector::iterator include_paths_end (); @@ -183,23 +183,26 @@ class pp inline std::vector::const_iterator include_paths_begin () const; inline std::vector::const_iterator include_paths_end () const; - template - inline _InputIterator eval_expression (_InputIterator __first, _InputIterator __last, Value *result); + template + inline InputIterator eval_expression (InputIterator _first, InputIterator _last, Value *result); - template - void file (std::string const &filename, _OutputIterator __result); + template + std::string expand_condition(InputIterator _first, InputIterator _last); - template - void file (FILE *fp, _OutputIterator __result); + template + void file (std::string const &filename, OutputIterator _result); - template - void operator () (_InputIterator __first, _InputIterator __last, _OutputIterator __result); + template + void file (FILE *fp, OutputIterator _result); + + template + void operator () (InputIterator _first, InputIterator _last, OutputIterator _result); private: - inline bool file_isdir (std::string const &__filename) const; - inline bool file_exists (std::string const &__filename) const; - FILE *find_include_file (std::string const &__filename, std::string *__filepath, - INCLUDE_POLICY __include_policy, bool __skip_current_path = false) const; + inline bool file_isdir (std::string const &_filename) const; + inline bool file_exists (std::string const &_filename) const; + FILE *find_include_file (std::string const &_filename, std::string *_filepath, + INCLUDE_POLICY include_policy, bool _skip_current_path = false) const; inline int skipping() const; bool test_if_level(); @@ -207,84 +210,84 @@ class pp inline std::string fix_file_path (std::string const &filename) const; inline bool is_absolute (std::string const &filename) const; - PP_DIRECTIVE_TYPE find_directive (char const *__directive, std::size_t __size) const; + PP_DIRECTIVE_TYPE find_directive (char const *_directive, std::size_t _size) const; - template - bool find_header_protection (_InputIterator __first, _InputIterator __last, std::string *__prot); + template + bool find_header_protection (InputIterator _first, InputIterator _last, std::string *_prot); - template - _InputIterator skip (_InputIterator __first, _InputIterator __last); + template + InputIterator skip (InputIterator _first, InputIterator _last); - template - _InputIterator eval_primary(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_primary(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator eval_multiplicative(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_multiplicative(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator eval_additive(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_additive(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator eval_shift(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_shift(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator eval_relational(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_relational(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator eval_equality(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_equality(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator eval_and(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_and(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator eval_xor(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_xor(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator eval_or(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_or(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator eval_logical_and(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_logical_and(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator eval_logical_or(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_logical_or(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator eval_constant_expression(_InputIterator __first, _InputIterator __last, Value *result); + template + InputIterator eval_constant_expression(InputIterator _first, InputIterator _last, Value *result); - template - _InputIterator handle_directive(char const *__directive, std::size_t __size, - _InputIterator __first, _InputIterator __last, _OutputIterator __result); + template + InputIterator handle_directive(char const *_directive, std::size_t _size, + InputIterator _first, InputIterator _last, OutputIterator _result); - template - _InputIterator handle_include(bool skip_current_path, _InputIterator __first, _InputIterator __last, - _OutputIterator __result); + template + InputIterator handle_include(bool skip_current_path, InputIterator _first, InputIterator _last, + OutputIterator _result); - template - _InputIterator handle_define (_InputIterator __first, _InputIterator __last); + template + InputIterator handle_define (InputIterator _first, InputIterator _last); - template - _InputIterator handle_if (_InputIterator __first, _InputIterator __last); + template + InputIterator handle_if (InputIterator _first, InputIterator _last); - template - _InputIterator handle_else (_InputIterator __first, _InputIterator __last); + template + InputIterator handle_else (InputIterator _first, InputIterator _last); - template - _InputIterator handle_elif (_InputIterator __first, _InputIterator __last); + template + InputIterator handle_elif (InputIterator _first, InputIterator _last); - template - _InputIterator handle_endif (_InputIterator __first, _InputIterator __last); + template + InputIterator handle_endif (InputIterator _first, InputIterator _last); - template - _InputIterator handle_ifdef (bool check_undefined, _InputIterator __first, _InputIterator __last); + template + InputIterator handle_ifdef (bool check_undefined, InputIterator _first, InputIterator _last); - template - _InputIterator handle_undef(_InputIterator __first, _InputIterator __last); + template + InputIterator handle_undef(InputIterator _first, InputIterator _last); - template - inline char peek_char (_InputIterator __first, _InputIterator __last); + template + char peek_char (InputIterator _first, InputIterator _last); - template - _InputIterator next_token (_InputIterator __first, _InputIterator __last, int *kind); + template + InputIterator next_token (InputIterator _first, InputIterator _last, int *kind); }; } // namespace rpp diff --git a/generator/parser/rpp/pp-environment.h b/generator/parser/rpp/pp-environment.h index 12277283..049ff589 100644 --- a/generator/parser/rpp/pp-environment.h +++ b/generator/parser/rpp/pp-environment.h @@ -71,11 +71,11 @@ class pp_environment const_iterator first_macro () const { return _M_macros.begin (); } const_iterator last_macro () const { return _M_macros.end (); } - inline void bind (pp_fast_string const *__name, pp_macro const &__macro) + inline void bind (pp_fast_string const *_name, pp_macro const &_macro) { - std::size_t h = hash_code (*__name) % _M_hash_size; - pp_macro *m = new pp_macro (__macro); - m->name = __name; + std::size_t h = hash_code (*_name) % _M_hash_size; + pp_macro *m = new pp_macro (_macro); + m->name = _name; m->next = _M_base [h]; m->hash_code = h; _M_base [h] = m; @@ -86,33 +86,33 @@ class pp_environment rehash(); } - inline void unbind (pp_fast_string const *__name) + inline void unbind (pp_fast_string const *_name) { - if (pp_macro *m = resolve (__name)) - m->hidden = true; + if (pp_macro *m = resolve (_name)) + m->is.hidden = true; } - inline void unbind (char const *__s, std::size_t __size) + inline void unbind (char const *_s, std::size_t _size) { - pp_fast_string __tmp (__s, __size); - unbind (&__tmp); + pp_fast_string tmp (_s, _size); + unbind (&tmp); } - inline pp_macro *resolve (pp_fast_string const *__name) const + inline pp_macro *resolve (pp_fast_string const *_name) const { - std::size_t h = hash_code (*__name) % _M_hash_size; + std::size_t h = hash_code (*_name) % _M_hash_size; pp_macro *it = _M_base [h]; - while (it && it->name && it->hash_code == h && (*it->name != *__name || it->hidden)) + while (it && it->name && it->hash_code == h && (*it->name != *_name || it->is.hidden)) it = it->next; return it; } - inline pp_macro *resolve (char const *__data, std::size_t __size) const + inline pp_macro *resolve (char const *_data, std::size_t _size) const { - pp_fast_string const __tmp (__data, __size); - return resolve (&__tmp); + pp_fast_string const tmp (_data, _size); + return resolve (&tmp); } std::string current_file; diff --git a/generator/parser/rpp/pp-internal.h b/generator/parser/rpp/pp-internal.h index 045bf097..4821ccb2 100644 --- a/generator/parser/rpp/pp-internal.h +++ b/generator/parser/rpp/pp-internal.h @@ -50,67 +50,67 @@ namespace rpp { namespace _PP_internal { -inline void extract_file_path (const std::string &__filename, std::string *__filepath) +inline void extract_file_path (const std::string &_filename, std::string *_filepath) { - std::size_t __index = __filename.rfind (PATH_SEPARATOR); + std::size_t index = _filename.rfind (PATH_SEPARATOR); - if (__index == std::string::npos) - *__filepath = "/"; + if (index == std::string::npos) + *_filepath = "/"; else - __filepath->assign (__filename, 0, __index + 1); + _filepath->assign (_filename, 0, index + 1); } -template -void output_line(const std::string &__filename, int __line, _OutputIterator __result) +template +void output_line(const std::string &_filename, int _line, OutputIterator _result) { - std::string __msg; + std::string msg; - __msg += "# "; + msg += "# "; - char __line_descr[16]; - pp_snprintf (__line_descr, 16, "%d", __line); - __msg += __line_descr; + char line_descr[16]; + pp_snprintf (line_descr, 16, "%d", _line); + msg += line_descr; - __msg += " \""; + msg += " \""; - if (__filename.empty ()) - __msg += ""; + if (_filename.empty ()) + msg += ""; else - __msg += __filename; + msg += _filename; - __msg += "\"\n"; - std::copy (__msg.begin (), __msg.end (), __result); + msg += "\"\n"; + std::copy (msg.begin (), msg.end (), _result); } -template -inline bool comment_p (_InputIterator __first, _InputIterator __last) /*const*/ +template +inline bool comment_p (InputIterator _first, InputIterator _last) /*const*/ { - if (__first == __last) + if (_first == _last) return false; - if (*__first != '/') + if (*_first != '/') return false; - if (++__first == __last) + if (++_first == _last) return false; - return (*__first == '/' || *__first == '*'); + return (*_first == '/' || *_first == '*'); } -struct _Compare_string: public std::binary_function +struct _Compare_string { inline bool operator () (pp_fast_string const *__lhs, pp_fast_string const *__rhs) const { return *__lhs < *__rhs; } }; -struct _Equal_to_string: public std::binary_function +struct _Equal_to_string { inline bool operator () (pp_fast_string const *__lhs, pp_fast_string const *__rhs) const { return *__lhs == *__rhs; } }; -struct _Hash_string: public std::unary_function +struct _Hash_string { inline std::size_t operator () (pp_fast_string const *__s) const { diff --git a/generator/parser/rpp/pp-iterator.h b/generator/parser/rpp/pp-iterator.h index 90d31b0f..230e3c89 100644 --- a/generator/parser/rpp/pp-iterator.h +++ b/generator/parser/rpp/pp-iterator.h @@ -43,6 +43,7 @@ #define PP_ITERATOR_H #include +#include // Q_CC_MSVC namespace rpp { @@ -71,6 +72,7 @@ class pp_output_iterator explicit pp_output_iterator(std::string &__result): _M_result (__result) {} +#ifdef Q_CC_MSVC // this copy constructor was needed for Visual Studio 2012 release builds: inline pp_output_iterator &operator=(const pp_output_iterator& other) { @@ -78,6 +80,7 @@ class pp_output_iterator _M_result = other._M_result; return *this; } +#endif inline pp_output_iterator &operator=(typename _Container::const_reference __v) { diff --git a/generator/parser/rpp/pp-macro-expander.h b/generator/parser/rpp/pp-macro-expander.h index 8a348f2e..14471592 100644 --- a/generator/parser/rpp/pp-macro-expander.h +++ b/generator/parser/rpp/pp-macro-expander.h @@ -51,8 +51,8 @@ struct pp_frame pp_macro *expanding_macro; std::vector *actuals; - pp_frame (pp_macro *__expanding_macro, std::vector *__actuals): - expanding_macro (__expanding_macro), actuals (__actuals) {} + pp_frame (pp_macro *_expanding_macro, std::vector *_actuals): + expanding_macro (_expanding_macro), actuals (_actuals) {} }; class pp_macro_expander @@ -69,26 +69,36 @@ class pp_macro_expander pp_skip_blanks skip_blanks; pp_skip_whitespaces skip_whitespaces; - std::string const *resolve_formal (pp_fast_string const *__name) + std::string const *resolve_formal (pp_fast_string const *_name) { - assert (__name != 0); + static const pp_fast_string va_args_name("__VA_ARGS__", 11); + static std::string empty(""); + + assert (_name != 0); if (! frame) return 0; assert (frame->expanding_macro != 0); - std::vector const formals = frame->expanding_macro->formals; + std::vector formals = frame->expanding_macro->formals; + if (frame->expanding_macro->is.variadics) + formals.push_back(&va_args_name); + for (std::size_t index = 0; index < formals.size(); ++index) { pp_fast_string const *formal = formals[index]; - if (*formal != *__name) + if (*formal != *_name) continue; else if (frame->actuals && index < frame->actuals->size()) return &(*frame->actuals)[index]; + else if (frame->expanding_macro->is.variadics && index == formals.size()-1) + // variadic argument may also be missing, replace with empty then + return ∅ + else assert (0); // internal error? } @@ -101,127 +111,127 @@ class pp_macro_expander int generated_lines; public: - pp_macro_expander (pp_environment &__env, pp_frame *__frame = 0): - env (__env), frame (__frame), lines (0), generated_lines (0) {} + pp_macro_expander (pp_environment &_env, pp_frame *_frame = 0): + env (_env), frame (_frame), lines (0), generated_lines (0) {} - template - _InputIterator operator () (_InputIterator __first, _InputIterator __last, _OutputIterator __result) + template + InputIterator operator () (InputIterator _first, InputIterator _last, OutputIterator _result) { generated_lines = 0; - __first = skip_blanks (__first, __last); + _first = skip_blanks (_first, _last); lines = skip_blanks.lines; - while (__first != __last) + while (_first != _last) { - if (*__first == '\n') + if (*_first == '\n') { - *__result++ = *__first; + *_result++ = *_first; ++lines; - __first = skip_blanks (++__first, __last); + _first = skip_blanks (++_first, _last); lines += skip_blanks.lines; - if (__first != __last && *__first == '#') + if (_first != _last && *_first == '#') break; } - else if (*__first == '#') + else if (*_first == '#') { - __first = skip_blanks (++__first, __last); + _first = skip_blanks (++_first, _last); lines += skip_blanks.lines; - _InputIterator end_id = skip_identifier (__first, __last); + InputIterator end_id = skip_identifier (_first, _last); // ### rewrite: not safe char name_buffer[512], *cp = name_buffer; - std::copy (__first, end_id, cp); - std::size_t name_size = end_id - __first; + std::copy (_first, end_id, cp); + std::size_t name_size = end_id - _first; name_buffer[name_size] = '\0'; pp_fast_string fast_name (name_buffer, name_size); if (std::string const *actual = resolve_formal (&fast_name)) { - *__result++ = '\"'; + *_result++ = '\"'; for (std::string::const_iterator it = skip_whitespaces (actual->begin (), actual->end ()); it != actual->end (); ++it) { if (*it == '"') { - *__result++ = '\\'; - *__result++ = *it; + *_result++ = '\\'; + *_result++ = *it; } else if (*it == '\n') { - *__result++ = '"'; - *__result++ = '\n'; - *__result++ = '"'; + *_result++ = '"'; + *_result++ = '\n'; + *_result++ = '"'; } else - *__result++ = *it; + *_result++ = *it; } - *__result++ = '\"'; - __first = end_id; + *_result++ = '\"'; + _first = end_id; } else - *__result++ = '#'; // ### warning message? + *_result++ = '#'; // ### warning message? } - else if (*__first == '\"') + else if (*_first == '\"') { - _InputIterator next_pos = skip_string_literal (__first, __last); + InputIterator next_pos = skip_string_literal (_first, _last); lines += skip_string_literal.lines; - std::copy (__first, next_pos, __result); - __first = next_pos; + std::copy (_first, next_pos, _result); + _first = next_pos; } - else if (*__first == '\'') + else if (*_first == '\'') { - _InputIterator next_pos = skip_char_literal (__first, __last); + InputIterator next_pos = skip_char_literal (_first, _last); lines += skip_char_literal.lines; - std::copy (__first, next_pos, __result); - __first = next_pos; + std::copy (_first, next_pos, _result); + _first = next_pos; } - else if (_PP_internal::comment_p (__first, __last)) + else if (_PP_internal::comment_p (_first, _last)) { - __first = skip_comment_or_divop (__first, __last); + _first = skip_comment_or_divop (_first, _last); int n = skip_comment_or_divop.lines; lines += n; while (n-- > 0) - *__result++ = '\n'; + *_result++ = '\n'; } - else if (pp_isspace (*__first)) + else if (pp_isspace (*_first)) { - for (; __first != __last; ++__first) + for (; _first != _last; ++_first) { - if (*__first == '\n' || !pp_isspace (*__first)) + if (*_first == '\n' || !pp_isspace (*_first)) break; } - *__result = ' '; + *_result = ' '; } - else if (pp_isdigit (*__first)) + else if (pp_isdigit (*_first)) { - _InputIterator next_pos = skip_number (__first, __last); + InputIterator next_pos = skip_number (_first, _last); lines += skip_number.lines; - std::copy (__first, next_pos, __result); - __first = next_pos; + std::copy (_first, next_pos, _result); + _first = next_pos; } - else if (pp_isalpha (*__first) || *__first == '_') + else if (pp_isalpha (*_first) || *_first == '_') { - _InputIterator name_begin = __first; - _InputIterator name_end = skip_identifier (__first, __last); - __first = name_end; // advance + InputIterator name_begin = _first; + InputIterator name_end = skip_identifier (_first, _last); + _first = name_end; // advance // search for the paste token - _InputIterator next = skip_blanks (__first, __last); - if (next != __last && *next == '#') + InputIterator next = skip_blanks (_first, _last); + if (next != _last && *next == '#') { ++next; - if (next != __last && *next == '#') - __first = skip_blanks(++next, __last); + if (next != _last && *next == '#') + _first = skip_blanks(++next, _last); } // ### rewrite: not safe @@ -235,88 +245,88 @@ class pp_macro_expander assert (name_size >= 0 && name_size < 512); char name_buffer[512], *cp = name_buffer; - std::size_t __size = name_end - name_begin; + std::size_t _size = name_end - name_begin; std::copy (name_begin, name_end, cp); - name_buffer[__size] = '\0'; + name_buffer[_size] = '\0'; pp_fast_string fast_name (name_buffer, name_size); if (std::string const *actual = resolve_formal (&fast_name)) { - std::copy (actual->begin (), actual->end (), __result); + std::copy (actual->begin (), actual->end (), _result); continue; } static bool hide_next = false; // ### remove me pp_macro *macro = env.resolve (name_buffer, name_size); - if (! macro || macro->hidden || hide_next) + if (! macro || macro->is.hidden || hide_next) { hide_next = ! strcmp (name_buffer, "defined"); - if (__size == 8 && name_buffer [0] == '_' && name_buffer [1] == '_') + if (_size == 8 && name_buffer [0] == '_' && name_buffer [1] == '_') { if (! strcmp (name_buffer, "__LINE__")) { char buf [16]; char *end = buf + pp_snprintf (buf, 16, "%d", env.current_line + lines); - std::copy (&buf [0], end, __result); + std::copy (&buf [0], end, _result); continue; } else if (! strcmp (name_buffer, "__FILE__")) { - __result++ = '"'; - std::copy (env.current_file.begin (), env.current_file.end (), __result); // ### quote - __result++ = '"'; + _result++ = '"'; + std::copy (env.current_file.begin (), env.current_file.end (), _result); // ### quote + _result++ = '"'; continue; } } - std::copy (name_begin, name_end, __result); + std::copy (name_begin, name_end, _result); continue; } - if (! macro->function_like) + if (! macro->is.function_like) { pp_macro *m = 0; if (macro->definition) { - macro->hidden = true; + macro->is.hidden = true; - std::string __tmp; - __tmp.reserve (256); + std::string tmp; + tmp.reserve (256); pp_macro_expander expand_macro (env); - expand_macro (macro->definition->begin (), macro->definition->end (), std::back_inserter (__tmp)); + expand_macro (macro->definition->begin (), macro->definition->end (), std::back_inserter (tmp)); generated_lines += expand_macro.lines; - if (! __tmp.empty ()) + if (! tmp.empty ()) { - std::string::iterator __begin_id = skip_whitespaces (__tmp.begin (), __tmp.end ()); - std::string::iterator __end_id = skip_identifier (__begin_id, __tmp.end ()); + std::string::iterator begin_id = skip_whitespaces (tmp.begin (), tmp.end ()); + std::string::iterator end_id = skip_identifier (begin_id, tmp.end ()); - if (__end_id == __tmp.end ()) + if (end_id == tmp.end ()) { - std::string __id; - __id.assign (__begin_id, __end_id); + std::string id; + id.assign (begin_id, end_id); std::size_t x; #if defined(__SUNPRO_CC) std::distance (__begin_id, __end_id, x); #else - x = std::distance (__begin_id, __end_id); + x = std::distance (begin_id, end_id); #endif - m = env.resolve (__id.c_str (), x); + m = env.resolve (id.c_str (), x); } if (! m) - std::copy (__tmp.begin (), __tmp.end (), __result); + std::copy (tmp.begin (), tmp.end (), _result); } - macro->hidden = false; + macro->is.hidden = false; } if (! m) @@ -326,13 +336,13 @@ class pp_macro_expander } // function like macro - _InputIterator arg_it = skip_whitespaces (__first, __last); + InputIterator arg_it = skip_whitespaces (_first, _last); - if (arg_it == __last || *arg_it != '(') + if (arg_it == _last || *arg_it != '(') { - std::copy (name_begin, name_end, __result); + std::copy (name_begin, name_end, _result); lines += skip_whitespaces.lines; - __first = arg_it; + _first = arg_it; continue; } @@ -342,7 +352,7 @@ class pp_macro_expander pp_macro_expander expand_actual (env, frame); - _InputIterator arg_end = skip_argument_variadics (actuals, macro, arg_it, __last); + InputIterator arg_end = skip_argument_variadics (actuals, macro, arg_it, _last); if (arg_it != arg_end) { std::string actual (arg_it, arg_end); @@ -352,11 +362,11 @@ class pp_macro_expander arg_it = arg_end; } - while (arg_it != __last && *arg_end == ',') + while (arg_it != _last && *arg_end == ',') { ++arg_it; // skip ',' - arg_end = skip_argument_variadics (actuals, macro, arg_it, __last); + arg_end = skip_argument_variadics (actuals, macro, arg_it, _last); std::string actual (arg_it, arg_end); actuals.resize (actuals.size() + 1); actuals.back ().reserve (255); @@ -364,40 +374,40 @@ class pp_macro_expander arg_it = arg_end; } - assert (arg_it != __last && *arg_it == ')'); + assert (arg_it != _last && *arg_it == ')'); ++arg_it; // skip ')' - __first = arg_it; + _first = arg_it; #if 0 // ### enable me - assert ((macro->variadics && macro->formals.size () >= actuals.size ()) + assert ((macro->is.variadics && macro->formals.size () >= actuals.size ()) || macro->formals.size() == actuals.size()); #endif pp_frame frame (macro, &actuals); pp_macro_expander expand_macro (env, &frame); - macro->hidden = true; - expand_macro (macro->definition->begin (), macro->definition->end (), __result); - macro->hidden = false; + macro->is.hidden = true; + expand_macro (macro->definition->begin (), macro->definition->end (), _result); + macro->is.hidden = false; generated_lines += expand_macro.lines; } else - *__result++ = *__first++; + *_result++ = *_first++; } - return __first; + return _first; } - template - _InputIterator skip_argument_variadics (std::vector const &__actuals, pp_macro *__macro, - _InputIterator __first, _InputIterator __last) + template + InputIterator skip_argument_variadics (std::vector const &_actuals, pp_macro *_macro, + InputIterator _first, InputIterator _last) { - _InputIterator arg_end = skip_argument (__first, __last); + InputIterator arg_end = skip_argument (_first, _last); - while (__macro->variadics && __first != arg_end && arg_end != __last && *arg_end == ',' - && (__actuals.size () + 1) == __macro->formals.size ()) + while (_macro->is.variadics && _first != arg_end && arg_end != _last && *arg_end == ',' + && (_actuals.size () + 1) == _macro->formals.size ()) { - arg_end = skip_argument (++arg_end, __last); + arg_end = skip_argument (++arg_end, _last); } return arg_end; diff --git a/generator/parser/rpp/pp-macro.h b/generator/parser/rpp/pp-macro.h index 0b4d7b5e..6342549d 100644 --- a/generator/parser/rpp/pp-macro.h +++ b/generator/parser/rpp/pp-macro.h @@ -62,7 +62,7 @@ struct pp_macro int unsigned hidden: 1; int unsigned function_like: 1; int unsigned variadics: 1; - }; + } is; }; int lines; diff --git a/generator/parser/rpp/pp-main.cpp b/generator/parser/rpp/pp-main.cpp index 0676a2fe..aaf09e14 100644 --- a/generator/parser/rpp/pp-main.cpp +++ b/generator/parser/rpp/pp-main.cpp @@ -142,19 +142,19 @@ int main (int, char *argv []) opt_pch = true; else if (! strcmp (arg, "-msse")) - { - pp_macro __macro; - __macro.name = pp_symbol::get ("__SSE__", 7); - env.bind (__macro.name, __macro); + { + pp_macro __macro; + __macro.name = pp_symbol::get ("__SSE__", 7); + env.bind (__macro.name, __macro); - __macro.name = pp_symbol::get ("__MMX__", 7); - env.bind (__macro.name, __macro); - } + __macro.name = pp_symbol::get ("__MMX__", 7); + env.bind (__macro.name, __macro); + } else if (! strcmp (arg, "-include")) { if (argv [1]) - include_pch_file = *++argv; + include_pch_file = *++argv; } else if (! strncmp (arg, "-o", 2)) diff --git a/generator/parser/rpp/pp-qt-configuration b/generator/parser/rpp/pp-qt-configuration index 590a1426..7ac89908 100644 --- a/generator/parser/rpp/pp-qt-configuration +++ b/generator/parser/rpp/pp-qt-configuration @@ -4,6 +4,7 @@ // Qt #define QOBJECTDEFS_H +#define QTMETAMACROS_H // not yet supported #define Q_SLOTS slots @@ -24,3 +25,9 @@ #define QT_NO_DEBUG #define QT_JAMBI_RUN + +// Qt6 +#define Q_NAMESPACE_EXPORT(...) +#define Q_ENUM_NS(x) +#define Q_FLAG_NS(x) +#define Q_MOC_INCLUDE(...) diff --git a/generator/parser/rpp/preprocessor.cpp b/generator/parser/rpp/preprocessor.cpp index cd58bcd6..55c80480 100644 --- a/generator/parser/rpp/preprocessor.cpp +++ b/generator/parser/rpp/preprocessor.cpp @@ -62,7 +62,7 @@ class PreprocessorPrivate void initPP(pp &proc) { - foreach(QString path, includePaths) + for (QString path : includePaths) proc.push_include_path(path.toStdString()); } }; @@ -143,7 +143,7 @@ QList Preprocessor::macros() const item.parameters += QString::fromLatin1(m->formals[i]->begin(), m->formals[i]->size()); } - item.isFunctionLike = m->function_like; + item.isFunctionLike = m->is.function_like; #ifdef PP_WITH_MACRO_POSITION item.fileName = QString::fromLatin1(m->file->begin(), m->file->size()); diff --git a/generator/parser/rpp/rpp.pri b/generator/parser/rpp/rpp.pri index 8468bcf9..46f6a98a 100644 --- a/generator/parser/rpp/rpp.pri +++ b/generator/parser/rpp/rpp.pri @@ -1,20 +1,20 @@ SOURCES += \ - $$RXXPATH/rpp/preprocessor.cpp + $$RXXPATH/rpp/preprocessor.cpp HEADERS += \ - $$RXXPATH/rpp/pp-cctype.h \ - $$RXXPATH/rpp/pp-engine-bits.h \ - $$RXXPATH/rpp/pp-engine.h \ - $$RXXPATH/rpp/pp-environment.h \ - $$RXXPATH/rpp/pp-fwd.h \ - $$RXXPATH/rpp/pp-internal.h \ - $$RXXPATH/rpp/pp-iterator.h \ - $$RXXPATH/rpp/pp-macro-expander.h \ - $$RXXPATH/rpp/pp-macro.h \ - $$RXXPATH/rpp/pp-scanner.h \ - $$RXXPATH/rpp/pp-string.h \ - $$RXXPATH/rpp/pp-symbol.h \ - $$RXXPATH/rpp/pp.h \ - $$RXXPATH/rpp/preprocessor.h + $$RXXPATH/rpp/pp-cctype.h \ + $$RXXPATH/rpp/pp-engine-bits.h \ + $$RXXPATH/rpp/pp-engine.h \ + $$RXXPATH/rpp/pp-environment.h \ + $$RXXPATH/rpp/pp-fwd.h \ + $$RXXPATH/rpp/pp-internal.h \ + $$RXXPATH/rpp/pp-iterator.h \ + $$RXXPATH/rpp/pp-macro-expander.h \ + $$RXXPATH/rpp/pp-macro.h \ + $$RXXPATH/rpp/pp-scanner.h \ + $$RXXPATH/rpp/pp-string.h \ + $$RXXPATH/rpp/pp-symbol.h \ + $$RXXPATH/rpp/pp.h \ + $$RXXPATH/rpp/preprocessor.h INCLUDEPATH += $$PWD $$RXXPATH/rpp diff --git a/generator/parser/rxx_allocator.h b/generator/parser/rxx_allocator.h index 87ec7e81..88d8f785 100644 --- a/generator/parser/rxx_allocator.h +++ b/generator/parser/rxx_allocator.h @@ -82,31 +82,34 @@ template class rxx_allocator { const size_type bytes = __n * sizeof(_Tp); if (_M_current_block == 0 - || _S_block_size < _M_current_index + bytes) + || _S_block_size < _M_current_index + bytes) { - ++_M_block_index; + ++_M_block_index; - _M_storage = reinterpret_cast - (::realloc(_M_storage, sizeof(char*) * (1 + _M_block_index))); + _M_storage = reinterpret_cast + (::realloc(_M_storage, sizeof(char*) * (1 + _M_block_index))); - _M_current_block = _M_storage[_M_block_index] = reinterpret_cast - (new char[_S_block_size]); + _M_current_block = _M_storage[_M_block_index] = reinterpret_cast + (new char[_S_block_size]); #if defined(RXX_ALLOCATOR_INIT_0) // ### make it a policy - ::memset(_M_current_block, 0, _S_block_size); + ::memset(_M_current_block, 0, _S_block_size); #endif - _M_current_index = 0; + _M_current_index = 0; } pointer p = reinterpret_cast (_M_current_block + _M_current_index); _M_current_index += bytes; + // Hack for modern C++ to get aligned allocations + _M_current_index += 7U; + _M_current_index &= ~(7U); return p; } - void deallocate(pointer __p, size_type __n) {} + void deallocate(pointer /*__p*/, size_type /*__n*/) {} size_type max_size() const { return size_type(-1) / sizeof(_Tp); } @@ -118,7 +121,7 @@ template class rxx_allocator { typedef rxx_allocator<_Tp1> other; }; - template rxx_allocator(const rxx_allocator<_Tp1> &__o) {} + template rxx_allocator(const rxx_allocator<_Tp1> &/*__o*/) {} private: size_type _M_block_index; diff --git a/generator/parser/symbol.h b/generator/parser/symbol.h index f9fe1372..d711e0d3 100644 --- a/generator/parser/symbol.h +++ b/generator/parser/symbol.h @@ -117,8 +117,8 @@ class NameTable NameSymbol *name = _M_storage.value(key); if (!name) { - name = new NameSymbol(str, len); - _M_storage.insert(key, name); + name = new NameSymbol(str, len); + _M_storage.insert(key, name); } return name; diff --git a/generator/parser/tokens.cpp b/generator/parser/tokens.cpp index 07cc10ad..02e02fc7 100644 --- a/generator/parser/tokens.cpp +++ b/generator/parser/tokens.cpp @@ -41,6 +41,7 @@ #include +#include #include "tokens.h" @@ -50,6 +51,7 @@ static char const * const _S_token_names[] = { "Q_PROPERTY", "__attribute__", "__typeof", + "alignas", "and", "and_eq", "arrow", @@ -69,8 +71,10 @@ static char const * const _S_token_names[] = { "compl", "concat", "const", + "constexpr", "const_cast", "continue", + "decltype", "decr", "default", "delete", @@ -103,12 +107,14 @@ static char const * const _S_token_names[] = { "mutable", "namespace", "new", + "noexcept", "not", "not_eq", "number_literal", "operator", "or", "or_eq", + "placeholder", "preproc", "private", "protected", @@ -118,7 +124,8 @@ static char const * const _S_token_names[] = { "reinterpret_cast", "return", "scope", - "shift", + "shift_left", + "shift_right", "short", "signals", "signed", @@ -149,7 +156,8 @@ static char const * const _S_token_names[] = { "xor", "xor_eq", "Q_ENUMS", - "Q_ENUM" + "Q_ENUM", + "Q_INVOKABLE" }; static char _S_printable[][2] = { @@ -251,6 +259,18 @@ static char _S_printable[][2] = { { char(127), '\0' }, }; +int check_tokens_consistency() +{ + if (sizeof(_S_token_names) / sizeof(_S_token_names[0]) != TOKEN_KIND_COUNT - Token_K_DCOP) + { + std::cerr << "** ERROR enum TOKEN_KIND and _S_token_names are not consistent" << std::endl; + abort(); + } + return 0; +} + +static int tokens_consistency = check_tokens_consistency(); + char const *token_name(int token) { if (token == 0) @@ -261,9 +281,9 @@ char const *token_name(int token) { return _S_printable[token - 32]; } - else if (token >= 1000) + else if (token >= Token_K_DCOP) { - return _S_token_names[token - 1000]; + return _S_token_names[token - Token_K_DCOP]; } Q_ASSERT(0); diff --git a/generator/parser/tokens.h b/generator/parser/tokens.h index 6bb944ae..edc6221f 100644 --- a/generator/parser/tokens.h +++ b/generator/parser/tokens.h @@ -52,6 +52,7 @@ enum TOKEN_KIND Token_Q_PROPERTY, Token___attribute__, Token___typeof, + Token_alignas, Token_and, Token_and_eq, Token_arrow, @@ -71,8 +72,10 @@ enum TOKEN_KIND Token_compl, Token_concat, Token_const, + Token_constexpr, Token_const_cast, Token_continue, + Token_decltype, Token_decr, Token_default, Token_delete, @@ -105,12 +108,14 @@ enum TOKEN_KIND Token_mutable, Token_namespace, Token_new, + Token_noexcept, Token_not, Token_not_eq, Token_number_literal, Token_operator, Token_or, Token_or_eq, + Token_placeholder, Token_preproc, Token_private, Token_protected, @@ -120,7 +125,8 @@ enum TOKEN_KIND Token_reinterpret_cast, Token_return, Token_scope, - Token_shift, + Token_shift_left, + Token_shift_right, Token_short, Token_signals, Token_signed, diff --git a/generator/parser/type_compiler.cpp b/generator/parser/type_compiler.cpp index 4a73a744..a03ef979 100644 --- a/generator/parser/type_compiler.cpp +++ b/generator/parser/type_compiler.cpp @@ -127,21 +127,6 @@ void TypeCompiler::visitName(NameAST *node) _M_type = name_cc.qualifiedName(); } -QStringList TypeCompiler::cvString() const -{ - QStringList lst; - - foreach (int q, cv()) - { - if (q == Token_const) - lst.append(QLatin1String("const")); - else if (q == Token_volatile) - lst.append(QLatin1String("volatile")); - } - - return lst; -} - bool TypeCompiler::isConstant() const { return _M_cv.contains(Token_const); @@ -152,4 +137,9 @@ bool TypeCompiler::isVolatile() const return _M_cv.contains(Token_volatile); } +bool TypeCompiler::isMutable() const +{ + return _M_cv.contains(Token_mutable); +} + // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/generator/parser/type_compiler.h b/generator/parser/type_compiler.h index 87e51ca9..b6ea6915 100644 --- a/generator/parser/type_compiler.h +++ b/generator/parser/type_compiler.h @@ -62,8 +62,7 @@ class TypeCompiler: protected DefaultVisitor bool isConstant() const; bool isVolatile() const; - - QStringList cvString() const; + bool isMutable() const; void run(TypeSpecifierAST *node); diff --git a/generator/prigenerator.cpp b/generator/prigenerator.cpp index 6d8bf38f..858651fe 100644 --- a/generator/prigenerator.cpp +++ b/generator/prigenerator.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include // for std::sort + #include "prigenerator.h" #include "shellgenerator.h" #include "reporthandler.h" @@ -72,7 +74,7 @@ static QString combineIncludes(const QString& text) { QStringList lines = text.split('\n'); QSet includes; QString result; - foreach(QString line, lines) { + for (QString line : lines) { if (line.startsWith("#include")) { includes.insert(line); } else if (line.startsWith("#") && line.contains("PYTHONQTWRAPPER_")) { @@ -81,13 +83,17 @@ static QString combineIncludes(const QString& text) { result += line + "\n"; } } - QStringList includeList = includes.toList(); - qSort(includeList); +#if QT_VERSION < QT_VERSION_CHECK(5,14,0) + QStringList includeList = includes.toList(); +#else + QStringList includeList(includes.begin(), includes.end()); +#endif + std::sort(includeList.begin(), includeList.end()); result = includeList.join("\n") + result; return result; } -static QStringList compactFiles(const QStringList& list, const QString& ext, const QString& dir, const QString& prefix) { +QStringList PriGenerator::compactFiles(const QStringList& list, const QString& ext, const QString& dir, const QString& prefix) { QStringList outList; int count = list.count(); int fileNum = 0; @@ -104,7 +110,7 @@ static QStringList compactFiles(const QStringList& list, const QString& ext, con outList << outFileName; QString allText; QTextStream ts(&allText); - for (int i = 0; i0; i++) { + for (int i = 0; i< maxClassesPerFile && count>0; i++) { collectAndRemoveFile(ts, srcDir + "/" + list.at(list.count()-count)); count--; } @@ -129,7 +135,7 @@ void PriGenerator::generate() int idx = folder.indexOf('/'); folder = folder.left(idx); - qSort(list.begin(), list.end()); + std::sort(list.begin(), list.end()); FileOut file(m_out_dir + "/generated_cpp/" + pri.key()); // strange idea to do the file compacting so late, but it is the most effective way without patching the generator a lot @@ -146,7 +152,7 @@ void PriGenerator::generate() file.stream << "\n"; file.stream << "SOURCES += \\\n"; list = pri.value().sources; - qSort(list.begin(), list.end()); + std::sort(list.begin(), list.end()); if (compact) { list = compactFiles(list, ".cpp", m_out_dir + "/generated_cpp/" + folder, folder); } diff --git a/generator/prigenerator.h b/generator/prigenerator.h index ff75682e..853ea6b7 100644 --- a/generator/prigenerator.h +++ b/generator/prigenerator.h @@ -58,13 +58,17 @@ class PriGenerator : public Generator Q_OBJECT public: + PriGenerator(int classesPerFile) : maxClassesPerFile(classesPerFile) {} virtual void generate(); void addHeader(const QString &folder, const QString &header); void addSource(const QString &folder, const QString &source); private: + QStringList compactFiles(const QStringList& list, const QString& ext, const QString& dir, const QString& prefix); + QHash priHash; + int maxClassesPerFile; }; #endif // PRIGENERATOR_H diff --git a/generator/qtscript_masterinclude.h b/generator/qtscript_masterinclude.h index 8f96f084..cc679058 100644 --- a/generator/qtscript_masterinclude.h +++ b/generator/qtscript_masterinclude.h @@ -38,7 +38,6 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - // We need to force the endianess in Qt5 #define Q_BYTE_ORDER Q_LITTLE_ENDIAN @@ -48,11 +47,58 @@ #define QOPENGLFUNCTIONS_H #define QOPENGLEXTRAFUNCTIONS_H -// our compiler can't handle the templates for singleShot (int Qt 5.12), but we can circumvent this with -// Q_CLANG_QDOC for the moment: -#define Q_CLANG_QDOC -#include -#undef Q_CLANG_QDOC +/* This must only be included after 'QT_NO_' definitions have been defined. */ +#include + +/* NOTE: Qt5.12 and later (including Qt6) uses template functions for the + * static implementations of QTimer::singleShot() (the function, not the + * property). The generator does not handle template functions. Defining + * Q_CLANG_QDOC works around this by exposing the non-template forms that + * appear in the documentation at the same time as hiding the templates. + * Without this the QTimer::singleShot functions do not appear in the PythonQt + * interface. + * + * Unfortunately the work around breaks precompilation in Qt5.11 because it + * causes duplicate definitions of some text handling functions (they really + * are duplicated if Q_CLANG_QDOC is turned on) so the change must be version + * specific. + * + * This does not work in Qt6 because Qt6 uses Q_QDOC for the documentation and + * needs other fixes. + */ +#if QT_VERSION_MAJOR == 5 && QT_VERSION_MINOR > 11 +# include // included by QtCore/QTimer +# define Q_CLANG_QDOC +# include +# undef Q_CLANG_QDOC +#endif + +// it seems this can be safely ignored (otherwise generator currently stumbles over use of noexcept): +#define Q_DECLARE_SHARED(TYPE) +#define Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(TYPE) + +// also ignore deprecation macros for now: +#define QT_DEPRECATED_VERSION_X_5(minor, text) +#define QT_DEPRECATED_VERSION_X(major, minor, text) + +#define QT_DEPRECATED_VERSION_5(minor) +#define QT_DEPRECATED_VERSION(major, minor) + +// we also don't use this: +#define Q_CLASSINFO(name, value) +#define Q_PRIVATE_PROPERTY(d, text) + +// treat QDOC_PROPERTY like Q_PROPERTY +#define QDOC_PROPERTY(text) Q_PROPERTY(text) + +// don't need this: +#define Q_REVISION(v) +#define Q_DECLARE_OPERATORS_FOR_FLAGS(x) + +#include + +// parse still stumbles over this declaration +#define QT_DECL_METATYPE_EXTERN_TAGGED(TYPE, TAG, EXPORT) #include #include @@ -61,6 +107,10 @@ #include #include +#if QT_VERSION >= 0x060000 +#include +#endif + #include #if QT_VERSION >= 0x050000 diff --git a/generator/setupgenerator.cpp b/generator/setupgenerator.cpp index f6cd6682..f7eb31d0 100644 --- a/generator/setupgenerator.cpp +++ b/generator/setupgenerator.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include // for std::sort, std::stable_sort + #include "setupgenerator.h" #include "shellgenerator.h" #include "reporthandler.h" @@ -65,7 +67,13 @@ static QStringList getOperatorCodes(const AbstractMetaClass* cls) { } } QSet r; - foreach(QString op, operatorCodes.toList()) { + for (QString op : +# if QT_VERSION < QT_VERSION_CHECK(5,14,0) + operatorCodes.toList() +# else + QStringList(operatorCodes.begin(), operatorCodes.end()) +# endif + ) { if (op == ">" || op == "<" || op == ">=" || op == "<=" || op == "==" || op == "!=") { r.insert("PythonQt::Type_RichCompare"); } else if (op == "+") { @@ -111,10 +119,10 @@ static QStringList getOperatorCodes(const AbstractMetaClass* cls) { { CodeSnipList code_snips = cls->typeEntry()->codeSnips(); - foreach(const CodeSnip &cs, code_snips) { + for (const CodeSnip &cs : code_snips) { if (cs.language == TypeSystem::PyWrapperOperators) { - QStringList values = cs.code().split(" ", QString::SkipEmptyParts); - foreach(QString value, values) { + QStringList values = cs.code().split(" ", Qt::SkipEmptyParts); + for (QString value : values) { r.insert(value); } } @@ -122,16 +130,15 @@ static QStringList getOperatorCodes(const AbstractMetaClass* cls) { } - QStringList result = r.toList(); - qSort(result); +#if QT_VERSION < QT_VERSION_CHECK(5,14,0) + QStringList result = r.toList(); +#else + QStringList result(r.begin(), r.end()); +#endif + std::sort(result.begin(), result.end()); return result; } -static bool class_less_than(const AbstractMetaClass *a, const AbstractMetaClass *b) -{ - return a->name() < b->name(); -} - static QSet _builtinListTypes = QSet() << "QByteArray" << "QDate" << "QTime" @@ -146,7 +153,10 @@ static QSet _builtinListTypes = QSet() << "QByteArray" << "QLineF" << "QPoint" << "QPointF" +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) << "QRegExp" +#endif +<< "QRegularExpression" << "QFont" << "QPixmap" << "QBrush" @@ -163,7 +173,11 @@ static QSet _builtinListTypes = QSet() << "QByteArray" << "QPen" << "QTextLength" << "QTextFormat" +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) << "QMatrix" +#endif +<< "QTransform" +<< "QMatrix4x4" << "QVariant"; static void addListRegistration(AbstractMetaType* type, QSet& output) { @@ -223,7 +237,7 @@ void SetupGenerator::generate() } } } - qSort(classes_with_polymorphic_id.begin(), classes_with_polymorphic_id.end(), class_less_than); + classes_with_polymorphic_id.sort(); QHashIterator > pack(packHash); while (pack.hasNext()) { @@ -231,7 +245,7 @@ void SetupGenerator::generate() QList list = pack.value(); if (list.isEmpty()) continue; - qSort(list.begin(), list.end(), class_less_than); + std::stable_sort(list.begin(), list.end(), AbstractMetaClass::less_than); QString packKey = pack.key(); QString packName = pack.key(); @@ -271,7 +285,7 @@ void SetupGenerator::generate() s << "#include " << endl; s << "#include " << endl; - for (int i=0; i<(list.count()+MAX_CLASSES_PER_FILE-1) / MAX_CLASSES_PER_FILE; i++) { + for (int i=0; i<(list.count()+ maxClassesPerFile -1) / maxClassesPerFile; i++) { s << "#include \"" << packKey << QString::number(i) << ".h\"" << endl; } s << endl; @@ -284,7 +298,7 @@ void SetupGenerator::generate() QSet listRegistration; QSet snips; - foreach(const AbstractMetaClass *cls, list) { + for (const AbstractMetaClass *cls : list) { Q_FOREACH(const AbstractMetaFunction* func, cls->functions()) { if (func->type() && func->type()->isContainer()) { addListRegistration(func->type(), listRegistration); @@ -298,7 +312,7 @@ void SetupGenerator::generate() { while (cls) { CodeSnipList code_snips = cls->typeEntry()->codeSnips(); - foreach(const CodeSnip &cs, code_snips) { + for (const CodeSnip &cs : code_snips) { if (cs.language == TypeSystem::PyInitSource) { snips.insert(cs.code()); } @@ -308,7 +322,7 @@ void SetupGenerator::generate() } } - foreach(QString snip, snips) { + for (QString snip : snips) { s << snip; } s << endl; @@ -335,7 +349,7 @@ void SetupGenerator::generate() const AbstractMetaClass* theclass = cls; while (theclass) { CodeSnipList code_snips = theclass->typeEntry()->codeSnips(); - foreach(const CodeSnip &cs, code_snips) { + for (const CodeSnip &cs : code_snips) { if (cs.language == TypeSystem::PySetWrapperFunc) { setInstanceFunc = cs.code(); break; @@ -346,7 +360,7 @@ void SetupGenerator::generate() } shellCreator = ", " + setInstanceFunc + "<" + ShellGenerator::shellClassName(cls) + ">"; } else { - shellCreator = ", NULL"; + shellCreator = ", nullptr"; } QString operatorCodes = getOperatorCodes(cls).join("|"); if (operatorCodes.isEmpty()) { @@ -358,7 +372,7 @@ void SetupGenerator::generate() QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():""; s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; } - foreach(AbstractMetaClass* interface, cls->interfaces()) { + for (AbstractMetaClass* interface : cls->interfaces()) { // the interface might be our own class... (e.g. QPaintDevice) if (interface->qualifiedCppName() != cls->qualifiedCppName()) { s << "PythonQt::self()->addParentClass(\""<< cls->qualifiedCppName() << "\", \"" << interface->qualifiedCppName() << "\",PythonQtUpcastingOffset<" << cls->qualifiedCppName() <<","<qualifiedCppName()<<">());" << endl; @@ -374,7 +388,11 @@ void SetupGenerator::generate() } s << endl; +#if QT_VERSION < QT_VERSION_CHECK(5,14,0) QStringList list = listRegistration.toList(); +#else + QStringList list(listRegistration.begin(), listRegistration.end()); +#endif list.sort(); Q_FOREACH(QString name, list) { if (name.contains("Ssl")) { @@ -408,7 +426,7 @@ QStringList SetupGenerator::writePolymorphicHandler(QTextStream &s, const QStrin if (isGraphicsItem) { const AbstractMetaClass *currentClazz = clazz; while (!inherits && currentClazz) { - foreach(AbstractMetaClass* interfaze, currentClazz->interfaces()) { + for (AbstractMetaClass* interfaze : currentClazz->interfaces()) { if (interfaze->qualifiedCppName()=="QGraphicsItem") { inherits = true; break; @@ -431,7 +449,7 @@ QStringList SetupGenerator::writePolymorphicHandler(QTextStream &s, const QStrin s << "static void* polymorphichandler_" << handler << "(const void *ptr, const char **class_name)" << endl << "{" << endl - << " Q_ASSERT(ptr != 0);" << endl + << " Q_ASSERT(ptr != nullptr);" << endl << " " << cls->qualifiedCppName() << " *object = (" << cls->qualifiedCppName() << " *)ptr;" << endl; } @@ -456,7 +474,7 @@ QStringList SetupGenerator::writePolymorphicHandler(QTextStream &s, const QStrin // Close the function if it has been opened if (!first) { - s << " return NULL;" << endl + s << " return nullptr;" << endl << "}" << endl; } } diff --git a/generator/setupgenerator.h b/generator/setupgenerator.h index 84dc0ce0..fb5985d2 100644 --- a/generator/setupgenerator.h +++ b/generator/setupgenerator.h @@ -50,19 +50,23 @@ class SetupGenerator : public Generator Q_OBJECT public: - virtual void generate(); + SetupGenerator(int classesPerFile) : maxClassesPerFile(classesPerFile) {} - void addClass(const QString& package, const AbstractMetaClass *cls); + virtual void generate(); - static void writeInclude(QTextStream &stream, const Include &inc); + void addClass(const QString& package, const AbstractMetaClass *cls); + + static void writeInclude(QTextStream &stream, const Include &inc); - static bool isSpecialStreamingOperator(const AbstractMetaFunction *fun); + static bool isSpecialStreamingOperator(const AbstractMetaFunction *fun); private: QStringList writePolymorphicHandler(QTextStream &s, const QString &package, const AbstractMetaClassList &polyBaseClasses, QList& allClasses); QHash > packHash; + + int maxClassesPerFile; }; #endif // SETUPGENERATOR_H diff --git a/generator/shellgenerator.cpp b/generator/shellgenerator.cpp index cad6a483..fa7a0672 100644 --- a/generator/shellgenerator.cpp +++ b/generator/shellgenerator.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include // for std::sort + #include "shellgenerator.h" #include "reporthandler.h" @@ -93,7 +95,7 @@ void ShellGenerator::writeTypeInfo(QTextStream &s, const AbstractMetaType *type, } if (type->instantiations().size() > 0 - && (!type->isContainer() + && (!te->isContainer() || (static_cast(te))->type() != ContainerTypeEntry::StringListContainer)) { s << '<'; QList args = type->instantiations(); @@ -123,13 +125,24 @@ void ShellGenerator::writeTypeInfo(QTextStream &s, const AbstractMetaType *type, s << ' '; } +namespace { + AbstractMetaEnum* findEnumTypeOfClass(const AbstractMetaClass* implementor, const QString& enumName) + { + for (AbstractMetaEnum* enumType : implementor->enums()) { + if (enumType->name() == enumName) { + return enumType; + } + } + return nullptr; + } +} + void ShellGenerator::writeFunctionArguments(QTextStream &s, const AbstractMetaFunction *meta_function, Option option, int numArguments) { - const AbstractMetaClass* owner = meta_function->ownerClass(); const AbstractMetaArgumentList &arguments = meta_function->arguments(); if (numArguments < 0) numArguments = arguments.size(); @@ -159,14 +172,30 @@ void ShellGenerator::writeFunctionArguments(QTextStream &s, s << " = "; QString expr = arg->defaultValueExpression(); + if (expr == "NULL") + { + expr = "nullptr"; + } if (expr != "0") { QString qualifier; if (arg->type()->typeEntry()->isEnum() && expr.indexOf("::") < 0) { qualifier = ((EnumTypeEntry *)arg->type()->typeEntry())->qualifier(); } else if (arg->type()->typeEntry()->isFlags() && expr.indexOf("::") < 0) { qualifier = ((FlagsTypeEntry *)arg->type()->typeEntry())->originator()->qualifier(); + } else if (_currentScope) { + int pos = expr.indexOf("::"); + if (pos > 0) { + QString typeName = expr.left(pos); + AbstractMetaEnum* enumType = findEnumTypeOfClass(_currentScope, typeName); + if (enumType && enumType->typeEntry()->isEnumClass()) { + // prepend original class name, otherwise the new enum type from the wrapper will be used, + // which is not compatible + qualifier = _currentScope->name(); + } + } } - if (!qualifier.isEmpty()) { + + if (!qualifier.isEmpty() && !expr.startsWith("{")) { s << qualifier << "::"; } } @@ -282,7 +311,7 @@ bool function_sorter(AbstractMetaFunction *a, AbstractMetaFunction *b); bool ShellGenerator::functionHasNonConstReferences(const AbstractMetaFunction* function) { - foreach(const AbstractMetaArgument* arg, function->arguments()) + for (const AbstractMetaArgument* arg : function->arguments()) { if (!arg->type()->isConstant() && arg->type()->isReference()) { QString s; @@ -319,8 +348,12 @@ AbstractMetaFunctionList ShellGenerator::getFunctionsToWrap(const AbstractMetaCl AbstractMetaClass::VirtualFunctions | AbstractMetaClass::WasVisible | AbstractMetaClass::NotRemovedFromTargetLang | AbstractMetaClass::ClassImplements ); +#if QT_VERSION < QT_VERSION_CHECK(5,14,0) QSet set1 = QSet::fromList(functions); - foreach(AbstractMetaFunction* func, functions2) { +#else + QSet set1(functions.begin(), functions.end()); +#endif + for (AbstractMetaFunction* func : functions2) { set1.insert(func); } @@ -328,14 +361,20 @@ AbstractMetaFunctionList ShellGenerator::getFunctionsToWrap(const AbstractMetaCl bool hasPromoter = meta_class->typeEntry()->shouldCreatePromoter(); - foreach(AbstractMetaFunction* func, set1.toList()) { + for (AbstractMetaFunction* func : +# if QT_VERSION < QT_VERSION_CHECK(5,14,0) + set1.toList() +# else + QList(set1.begin(), set1.end()) +# endif + ) { if (func->implementingClass()==meta_class) { if (hasPromoter || func->wasPublic()) { resultFunctions << func; } } } - qSort(resultFunctions.begin(), resultFunctions.end(), function_sorter); + std::sort(resultFunctions.begin(), resultFunctions.end(), function_sorter); return resultFunctions; } @@ -345,7 +384,7 @@ AbstractMetaFunctionList ShellGenerator::getVirtualFunctionsForShell(const Abstr AbstractMetaClass::VirtualFunctions | AbstractMetaClass::WasVisible | AbstractMetaClass::NotRemovedFromTargetLang ); - qSort(functions.begin(), functions.end(), function_sorter); + std::sort(functions.begin(), functions.end(), function_sorter); return functions; } @@ -353,12 +392,12 @@ AbstractMetaFunctionList ShellGenerator::getProtectedFunctionsThatNeedPromotion( { AbstractMetaFunctionList functions; AbstractMetaFunctionList functions1 = getFunctionsToWrap(meta_class); - foreach(AbstractMetaFunction* func, functions1) { + for (AbstractMetaFunction* func : functions1) { if (func->wasProtected() || func->isVirtual()) { functions << func; } } - qSort(functions.begin(), functions.end(), function_sorter); + std::sort(functions.begin(), functions.end(), function_sorter); return functions; } @@ -384,6 +423,13 @@ void ShellGenerator::writeInclude(QTextStream &stream, const Include &inc) stream << endl; } +const AbstractMetaClass* ShellGenerator::setCurrentScope(const AbstractMetaClass* scope) +{ + const AbstractMetaClass* previousScope = _currentScope; + _currentScope = scope; + return previousScope; +} + /*! Returns true if the given function \a fun is operator>>() or operator<<() that streams from/to a Q{Data,Text}Stream, false @@ -420,7 +466,11 @@ bool ShellGenerator::isBuiltIn(const QString& name) { builtIn.insert("QKeySequence"); builtIn.insert("QTextLength"); builtIn.insert("QTextFormat"); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) builtIn.insert("QMatrix"); +#endif + builtIn.insert("QTransform"); + builtIn.insert("QMatrix4x4"); builtIn.insert("QDate"); builtIn.insert("QTime"); builtIn.insert("QDateTime"); @@ -434,7 +484,10 @@ bool ShellGenerator::isBuiltIn(const QString& name) { builtIn.insert("QLineF"); builtIn.insert("QPoint"); builtIn.insert("QPointF"); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) builtIn.insert("QRegExp"); +#endif + builtIn.insert("QRegularExpression"); } return builtIn.contains(name); } @@ -452,4 +505,4 @@ TypeSystem::Ownership ShellGenerator::writeOwnershipTemplate(QTextStream & s, co s << "PythonQtNewOwnerOfThis<"; } return ownership; -} \ No newline at end of file +} diff --git a/generator/shellgenerator.h b/generator/shellgenerator.h index 58097e1d..1699b780 100644 --- a/generator/shellgenerator.h +++ b/generator/shellgenerator.h @@ -46,8 +46,6 @@ #include "metaqtscript.h" #include "prigenerator.h" -#define MAX_CLASSES_PER_FILE 30 - class ShellGenerator : public Generator { Q_OBJECT @@ -100,8 +98,14 @@ class ShellGenerator : public Generator static void writeInclude(QTextStream &stream, const Include &inc); + // this scope is used in writeFunctionArguments + const AbstractMetaClass* setCurrentScope(const AbstractMetaClass* scope); + const AbstractMetaClass* currentScope() const { return _currentScope; } + protected: - PriGenerator *priGenerator; + PriGenerator* priGenerator{}; + + const AbstractMetaClass* _currentScope{}; }; diff --git a/generator/shellheadergenerator.cpp b/generator/shellheadergenerator.cpp index 24b6ce14..b0a5c70a 100644 --- a/generator/shellheadergenerator.cpp +++ b/generator/shellheadergenerator.cpp @@ -39,39 +39,40 @@ ** ****************************************************************************/ +#include // for std::sort + #include "shellheadergenerator.h" -#include "fileout.h" #include #include -QString ShellHeaderGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const +QString ShellHeaderGenerator::fileNameForClass(const AbstractMetaClass* meta_class) const { return QString("PythonQtWrapper_%1.h").arg(meta_class->name()); } -void ShellHeaderGenerator::writeFieldAccessors(QTextStream &s, const AbstractMetaField *field) +void ShellHeaderGenerator::writeFieldAccessors(QTextStream& s, const AbstractMetaField* field) { - const AbstractMetaFunction *setter = field->setter(); - const AbstractMetaFunction *getter = field->getter(); + const AbstractMetaFunction* setter = field->setter(); + const AbstractMetaFunction* getter = field->getter(); // static fields are not supported (yet?) if (setter->isStatic()) return; // Uuid data4 did not work (TODO: move to typesystem...( - if (field->enclosingClass()->name()=="QUuid" && setter->name()=="data4") return; - if (field->enclosingClass()->name()=="QIPv6Address") return; + if (field->enclosingClass()->name() == "QUuid" && setter->name() == "data4") return; + if (field->enclosingClass()->name() == "QIPv6Address") return; bool isInventorField = field->type()->name().startsWith("So"); if (!isInventorField && !field->type()->isConstant()) { writeFunctionSignature(s, setter, 0, QString(), - Option(ConvertReferenceToPtr | FirstArgIsWrappedObject| IncludeDefaultExpression | ShowStatic | UnderscoreSpaces)); + Option(ConvertReferenceToPtr | FirstArgIsWrappedObject | IncludeDefaultExpression | ShowStatic | UnderscoreSpaces)); s << "{ theWrappedObject->" << field->name() << " = " << setter->arguments()[0]->argumentName() << "; }\n"; } - + bool addIndirection = false; if (isInventorField && getter->type()->indirections() == 0) { // make it a field ptr: @@ -79,7 +80,7 @@ void ShellHeaderGenerator::writeFieldAccessors(QTextStream &s, const AbstractMet addIndirection = true; } writeFunctionSignature(s, getter, 0, QString(), - Option(ConvertReferenceToPtr | FirstArgIsWrappedObject| IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces)); + Option(ConvertReferenceToPtr | FirstArgIsWrappedObject | IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces)); s << "{ return "; if (addIndirection) { s << "&"; @@ -87,19 +88,20 @@ void ShellHeaderGenerator::writeFieldAccessors(QTextStream &s, const AbstractMet s << "theWrappedObject->" << field->name() << "; }\n"; } -static bool enum_lessThan(const AbstractMetaEnum *a, const AbstractMetaEnum *b) +static bool enum_lessThan(const AbstractMetaEnum* a, const AbstractMetaEnum* b) { return a->name() < b->name(); } -static bool field_lessThan(const AbstractMetaField *a, const AbstractMetaField *b) +static bool field_lessThan(const AbstractMetaField* a, const AbstractMetaField* b) { return a->name() < b->name(); } -void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class) +void ShellHeaderGenerator::write(QTextStream& s, const AbstractMetaClass* meta_class) { - QString builtIn = ShellGenerator::isBuiltIn(meta_class->name())?"_builtin":""; + setCurrentScope(meta_class); + QString builtIn = ShellGenerator::isBuiltIn(meta_class->name()) ? "_builtin" : ""; QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri"; priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class)); setupGenerator->addClass(meta_class->package().replace(".", "_") + builtIn, meta_class); @@ -116,18 +118,19 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c s << "#include " << endl << endl; IncludeList list = meta_class->typeEntry()->extraIncludes(); - qSort(list.begin(), list.end()); - foreach (const Include &inc, list) { + std::sort(list.begin(), list.end()); + for (const Include & inc : list) { ShellGenerator::writeInclude(s, inc); - } + } s << endl; + AbstractMetaFunctionList ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors | AbstractMetaClass::WasVisible | AbstractMetaClass::NotRemovedFromTargetLang); if (meta_class->qualifiedCppName().contains("Ssl")) { - s << "#ifndef QT_NO_SSL" << endl; + s << "#ifndef QT_NO_SSL" << endl; } // Shell------------------------------------------------------------------- @@ -138,9 +141,9 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c s << "class " << shellClassName(meta_class) << " : public " << meta_class->qualifiedCppName() << endl << "{" << endl; s << "public:" << endl; - foreach(AbstractMetaFunction* fun, ctors) { + for (AbstractMetaFunction * fun : ctors) { s << " "; - writeFunctionSignature(s, fun, 0,"PythonQtShell_", + writeFunctionSignature(s, fun, 0, "PythonQtShell_", Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces)); s << ":" << meta_class->qualifiedCppName() << "("; QString scriptFunctionName = fun->originalName(); @@ -150,28 +153,27 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c s << ", "; s << args.at(i)->argumentName(); } - s << "),_wrapper(NULL) {"; + s << "),_wrapper(nullptr) {"; writeInjectedCode(s, meta_class, TypeSystem::PyInheritShellConstructorCode, true); s << "};" << endl; } s << endl; - s << " ~" << shellClassName(meta_class) << "();" << endl; + s << " ~" << shellClassName(meta_class) << "()" << (meta_class->hasVirtualDestructor() ? " override" : "") << ";" << endl; s << endl; - foreach(AbstractMetaFunction* fun, virtualsForShell) { - s << "virtual "; + for (AbstractMetaFunction * fun : virtualsForShell) { writeFunctionSignature(s, fun, 0, QString(), Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces)); - s << ";" << endl; + s << " override;" << endl; } s << endl; if (meta_class->isQObject()) { - s << " const QMetaObject* metaObject() const;" << endl; - s << " int qt_metacall(QMetaObject::Call call, int id, void** args);" << endl; + s << " const QMetaObject* metaObject() const override;" << endl; + s << " int qt_metacall(QMetaObject::Call call, int id, void** args) override;" << endl; } writeInjectedCode(s, meta_class, TypeSystem::PyShellDeclaration); writeInjectedCode(s, meta_class, TypeSystem::PyInheritShellDeclaration, true); - s << " PythonQtInstanceWrapper* _wrapper; " << endl; + s << " PythonQtInstanceWrapper* _wrapper;" << endl; s << "};" << endl << endl; } @@ -186,13 +188,13 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c << " : public " << meta_class->qualifiedCppName() << endl << "{ public:" << endl; AbstractMetaEnumList enums1 = meta_class->enums(); - qSort(enums1.begin(), enums1.end(), enum_lessThan); - foreach(AbstractMetaEnum* enum1, enums1) { + std::sort(enums1.begin(), enums1.end(), enum_lessThan); + for (AbstractMetaEnum * enum1 : enums1) { if (enum1->wasProtected()) { s << "enum " << enum1->name() << "{" << endl; bool first = true; QString scope = meta_class->qualifiedCppName(); - foreach(AbstractMetaEnumValue* value, enum1->values()) { + for (AbstractMetaEnumValue * value : enum1->values()) { if (first) { first = false; } else { s << ", "; } s << " " << value->name() << " = " << scope << "::" << value->name(); @@ -200,8 +202,8 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c s << "};" << endl; } } - - foreach(AbstractMetaFunction* fun, promoteFunctions) { + + for (AbstractMetaFunction * fun : promoteFunctions) { // normal promoter if (fun->wasProtected()) { if (fun->isStatic()) { @@ -220,13 +222,18 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c // always do a direct call, since we want to call the real virtual function here s << "this->"; } + if (fun->originalName() == "operator=") { + // make it clear we don't want to call the (automatically generated) + // assignment operator of the promoter + s << meta_class->qualifiedCppName() << "::"; + } s << fun->originalName() << "("; writePromoterArgs(args, s); s << "); }" << endl; } } - foreach(AbstractMetaFunction* fun, promoteFunctions) { + for (AbstractMetaFunction * fun : promoteFunctions) { // qualified promoter for virtual functions if (fun->isVirtual()) { s << "inline "; @@ -264,14 +271,14 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c s << "public:" << endl; AbstractMetaEnumList enums1 = meta_class->enums(); - qSort(enums1.begin(), enums1.end(), enum_lessThan); + std::sort(enums1.begin(), enums1.end(), enum_lessThan); AbstractMetaEnumList enums; QList flags; - foreach(AbstractMetaEnum* enum1, enums1) { + for (AbstractMetaEnum * enum1 : enums1) { // catch gadgets and enums that are not exported on QObjects... // since we don't parse Q_FLAG(S), we also need to generate for Q_ENUM which might // have a missing Q_FLAG(S) declaration. - if ((enum1->wasProtected() || enum1->wasPublic()) && + if ((enum1->wasProtected() || enum1->wasPublic()) && (!meta_class->isQObject() || !enum1->hasQEnumsDeclaration() || enum1->typeEntry()->flags())) { enums << enum1; @@ -282,45 +289,56 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c } if (enums.count()) { s << "Q_ENUMS("; - foreach(AbstractMetaEnum* enum1, enums) { + for (AbstractMetaEnum * enum1 : enums) { s << enum1->name() << " "; } s << ")" << endl; - + if (flags.count()) { s << "Q_FLAGS("; - foreach(FlagsTypeEntry* flag1, flags) { + for (FlagsTypeEntry * flag1 : flags) { QString origName = flag1->originalName(); int idx = origName.lastIndexOf("::"); - if (idx!= -1) { - origName = origName.mid(idx+2); + if (idx != -1) { + origName = origName.mid(idx + 2); } s << origName << " "; } s << ")" << endl; } - - foreach(AbstractMetaEnum* enum1, enums) { - s << "enum " << enum1->name() << "{" << endl; + + for (AbstractMetaEnum * enum1 : enums) { + bool isEnumClass = enum1->typeEntry()->isEnumClass(); + s << "enum " << (isEnumClass ? "class " : "") << enum1->name() << "{" << endl; bool first = true; QString scope = enum1->wasProtected() ? promoterClassName(meta_class) : meta_class->qualifiedCppName(); + if (isEnumClass) { + scope += "::" + enum1->name(); + } - foreach(AbstractMetaEnumValue* value, enum1->values()) { + for (AbstractMetaEnumValue * value : enum1->values()) { if (first) { first = false; } else { s << ", "; } - s << " " << value->name() << " = " << scope << "::" << value->name(); + QString assignedValue = scope + "::" + value->name(); + if (isEnumClass) { + s << " " << value->name() << " = " << "static_cast(" << scope << "::" << value->name() << ")"; + } + else { + s << " " << value->name() << " = " << scope << "::" << value->name(); + + } } s << "};" << endl; } if (flags.count()) { - foreach(AbstractMetaEnum* enum1, enums) { + for (AbstractMetaEnum * enum1 : enums) { if (enum1->typeEntry()->flags()) { QString origName = enum1->typeEntry()->flags()->originalName(); int idx = origName.lastIndexOf("::"); - if (idx!= -1) { - origName = origName.mid(idx+2); + if (idx != -1) { + origName = origName.mid(idx + 2); } - s << "Q_DECLARE_FLAGS("<< origName << ", " << enum1->name() <<")"<name() << ")" << endl; } } } @@ -330,24 +348,25 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c bool copyConstructorSeen = false; bool defaultConstructorSeen = false; - foreach (const AbstractMetaFunction *fun, ctors) { + for (const AbstractMetaFunction * fun : ctors) { if (fun->isAbstract() || (!meta_class->generateShellClass() && !fun->isPublic())) { continue; } s << meta_class->qualifiedCppName() << "* "; writeFunctionSignature(s, fun, 0, "new_", Option(IncludeDefaultExpression | OriginalName | ShowStatic | AddOwnershipTemplates)); s << ";" << endl; - if (fun->arguments().size()==1 && meta_class->qualifiedCppName() == fun->arguments().at(0)->type()->typeEntry()->qualifiedCppName()) { + if (fun->arguments().size() == 1 && meta_class->qualifiedCppName() == fun->arguments().at(0)->type()->typeEntry()->qualifiedCppName()) { copyConstructorSeen = true; } - if (fun->arguments().size()==0) { + if (fun->arguments().size() == 0) { defaultConstructorSeen = true; } } if (meta_class->typeEntry()->isValue() - && !copyConstructorSeen && defaultConstructorSeen) { - QString className = meta_class->generateShellClass()?shellClassName(meta_class):meta_class->qualifiedCppName(); + && !copyConstructorSeen && defaultConstructorSeen && !meta_class->typeEntry()->hasNoCopy()) + { + QString className = meta_class->generateShellClass() ? shellClassName(meta_class) : meta_class->qualifiedCppName(); s << meta_class->qualifiedCppName() << "* new_" << meta_class->name() << "(const " << meta_class->qualifiedCppName() << "& other) {" << endl; s << className << "* a = new " << className << "();" << endl; s << "*((" << meta_class->qualifiedCppName() << "*)a) = other;" << endl; @@ -355,13 +374,12 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c } } if (meta_class->hasPublicDestructor() && !meta_class->isNamespace()) { - s << "void delete_" << meta_class->name() << "(" << meta_class->qualifiedCppName() << "* obj) { delete obj; } "; - s << endl; + s << "void delete_" << meta_class->name() << "(" << meta_class->qualifiedCppName() << "* obj) { delete obj; }" << endl; } AbstractMetaFunctionList functions = getFunctionsToWrap(meta_class); - foreach (const AbstractMetaFunction *function, functions) { + for (const AbstractMetaFunction * function : functions) { if (functionNeedsNormalWrapperSlot(function, meta_class)) { // for debugging: //functionHasNonConstReferences(function); @@ -399,7 +417,7 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c } } if (meta_class->hasDefaultToStringFunction() || meta_class->hasToStringCapability()) { - s << " QString py_toString(" << meta_class->qualifiedCppName() << "*);" << endl; + s << " QString py_toString(" << meta_class->qualifiedCppName() << "*);" << endl; } QString nonZeroFunc = meta_class->getDefaultNonZeroFunction(); if (!nonZeroFunc.isEmpty()) { @@ -411,11 +429,11 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c } AbstractMetaFieldList fields = meta_class->fields(); - qSort(fields.begin(), fields.end(), field_lessThan); + std::sort(fields.begin(), fields.end(), field_lessThan); // TODO: move "So" check to typesystem, e.g. allow star in rejection... // Field accessors - foreach (const AbstractMetaField *field, fields ) { + for (const AbstractMetaField * field : fields) { if (field->isPublic()) { writeFieldAccessors(s, field); } @@ -423,25 +441,25 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c writeInjectedCode(s, meta_class, TypeSystem::PyWrapperDeclaration); - - s << "};" << endl << endl; + + s << "};" << endl << endl; if (meta_class->qualifiedCppName().contains("Ssl")) { - s << "#endif" << endl << endl; + s << "#endif" << endl << endl; } - s << "#endif // " << include_block << endl; - + s << "#endif // " << include_block << endl; + setCurrentScope(nullptr); } -void ShellHeaderGenerator::writePromoterArgs(AbstractMetaArgumentList &args, QTextStream & s) +void ShellHeaderGenerator::writePromoterArgs(AbstractMetaArgumentList& args, QTextStream& s) { for (int i = 0; i < args.size(); ++i) { if (i > 0) { s << ", "; } if (args.at(i)->type()->isEnum()) { - AbstractMetaEnum* enumType = m_classes.findEnum((EnumTypeEntry *)args.at(i)->type()->typeEntry()); + AbstractMetaEnum* enumType = m_classes.findEnum((EnumTypeEntry*)args.at(i)->type()->typeEntry()); if (enumType && enumType->wasProtected()) { s << "(" << enumType->typeEntry()->qualifiedCppName() << ")"; } @@ -450,12 +468,12 @@ void ShellHeaderGenerator::writePromoterArgs(AbstractMetaArgumentList &args, QTe } } -void ShellHeaderGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class, int type, bool recursive) +void ShellHeaderGenerator::writeInjectedCode(QTextStream& s, const AbstractMetaClass* meta_class, int type, bool recursive) { - const AbstractMetaClass *cls = meta_class; + const AbstractMetaClass* cls = meta_class; do { CodeSnipList code_snips = cls->typeEntry()->codeSnips(); - foreach(const CodeSnip &cs, code_snips) { + for (const CodeSnip & cs : code_snips) { if (cs.language == type) { s << cs.code() << endl; } diff --git a/generator/shellimplgenerator.cpp b/generator/shellimplgenerator.cpp index e543de47..b4ee83f3 100644 --- a/generator/shellimplgenerator.cpp +++ b/generator/shellimplgenerator.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include // for std::sort + #include "shellimplgenerator.h" #include "reporthandler.h" #include "fileout.h" @@ -53,12 +55,14 @@ QString ShellImplGenerator::fileNameForClass(const AbstractMetaClass *meta_class return QString("PythonQtWrapper_%1.cpp").arg(meta_class->name()); } +/* UNUSED static bool include_less_than(const Include &a, const Include &b) { return a.name < b.name; } +*/ -static void writeHelperCode(QTextStream &s, const AbstractMetaClass *) +static void writeHelperCode(QTextStream &, const AbstractMetaClass *) { } @@ -66,6 +70,8 @@ static void writeHelperCode(QTextStream &s, const AbstractMetaClass *) void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class) { + setCurrentScope(meta_class); + QString builtIn = ShellGenerator::isBuiltIn(meta_class->name())?"_builtin":""; QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri"; priGenerator->addSource(pro_file_name, fileNameForClass(meta_class)); @@ -80,7 +86,7 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla // return; IncludeList list = meta_class->typeEntry()->extraIncludes(); - qSort(list.begin(), list.end()); + std::sort(list.begin(), list.end()); foreach (const Include &inc, list) { ShellGenerator::writeInclude(s, inc); } @@ -153,7 +159,7 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla writeTypeInfo(s, fun->type(), typeOptions); s << " returnValue{};" << endl; } - s << " void* args[" << QString::number(args.size() + 1) << "] = {NULL"; + s << " void* args[" << QString::number(args.size() + 1) << "] = {nullptr"; for (int i = 0; i < args.size(); ++i) { s << ", (void*)&" << args.at(i)->indexedName(); } @@ -162,9 +168,9 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla s << " PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true);" << endl; if (hasReturnValue) { s << " if (result) {" << endl; - s << " args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue);" << endl; + s << " args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, nullptr, &returnValue);" << endl; s << " if (args[0]!=&returnValue) {" << endl; - s << " if (args[0]==NULL) {" << endl; + s << " if (args[0]==nullptr) {" << endl; s << " PythonQt::priv()->handleVirtualOverloadReturnError(\"" << fun->name() << "\", methodInfo, result);" << endl; s << " } else {" << endl; s << " returnValue = *(("; @@ -174,7 +180,7 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla s << " }" << endl; s << " }" << endl; } - s << " if (result) { Py_DECREF(result); } " << endl; + s << " if (result) { Py_DECREF(result); }" << endl; s << " Py_DECREF(obj);" << endl; // ugly hack, we don't support QGraphicsScene* nor QGraphicsItem* QVariants in PythonQt... if (fun->name() == "itemChange" && fun->type() && fun->type()->isVariant()) { @@ -200,7 +206,7 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla // return empty default object s << "return "; if (fun->type()->indirections()>0) { - s << "0;"; + s << "nullptr;"; } else { writeTypeInfo(s, fun->type(), typeOptions); s << "();"; @@ -298,13 +304,13 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla } } s << "("; - if (scriptFunctionName.startsWith("operator>>")) { + if (scriptFunctionName.startsWith("operator>>") && !fun->wasProtected()) { s << wrappedObject << " >>" << args.at(0)->argumentName(); - } else if (scriptFunctionName.startsWith("operator<<")) { + } else if (scriptFunctionName.startsWith("operator<<") && !fun->wasProtected()) { s << wrappedObject << " <<" << args.at(0)->argumentName(); - } else if (scriptFunctionName.startsWith("operator[]")) { + } else if (scriptFunctionName.startsWith("operator[]") && !fun->wasProtected()) { s << wrappedObject << "[" << args.at(0)->argumentName() << "]"; - } else if (scriptFunctionName.startsWith("operator") && args.size()==1) { + } else if (scriptFunctionName.startsWith("operator") && args.size()==1 && !fun->wasProtected()) { QString op = scriptFunctionName.mid(8); s << wrappedObject << op << " " << args.at(0)->argumentName(); } else { @@ -322,7 +328,13 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla s << " theWrappedObject->"; } } - s << fun->originalName() << "("; + if (fun->wasProtected()) { + // this is different e.g. for operators + s << fun->name() << "("; + } + else { + s << fun->originalName() << "("; + } for (int i = 0; i < args.size(); ++i) { if (i > 0) s << ", "; @@ -356,6 +368,8 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla if (meta_class->qualifiedCppName().contains("Ssl")) { s << "#endif" << endl; } + + setCurrentScope(nullptr); } void ShellImplGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class) diff --git a/generator/typeparser.cpp b/generator/typeparser.cpp index 87730fa5..90a68e56 100644 --- a/generator/typeparser.cpp +++ b/generator/typeparser.cpp @@ -53,6 +53,7 @@ class Scanner LessThanToken, ColonToken, CommaToken, + EllipsisToken, OpenParenToken, CloseParenToken, SquareBegin, @@ -115,6 +116,12 @@ Scanner::Token Scanner::nextToken() Q_ASSERT(m_pos + 1 < m_length); ++m_pos; break; + case '.': + if (m_pos + 2 < m_length && c == m_chars[m_pos + 1] && c == m_chars[m_pos + 2]) { + tok = EllipsisToken; + m_pos += 2; + break; + } default: if (c.isLetterOrNumber() || c == '_') tok = Identifier; @@ -168,6 +175,7 @@ TypeParser::Info TypeParser::parse(const QString &str) // switch (tok) { // case Scanner::StarToken: printf(" - *\n"); break; // case Scanner::AmpersandToken: printf(" - &\n"); break; +// case Scanner::EllipsisToken: printf(" - ...\n"); break; // case Scanner::LessThanToken: printf(" - <\n"); break; // case Scanner::GreaterThanToken: printf(" - >\n"); break; // case Scanner::ColonToken: printf(" - ::\n"); break; @@ -215,7 +223,8 @@ TypeParser::Info TypeParser::parse(const QString &str) case Scanner::OpenParenToken: // function pointers not supported case Scanner::CloseParenToken: - { + case Scanner::EllipsisToken: // variadic templates not supported + { Info i; i.is_busted = true; return i; diff --git a/generator/typeparser.h b/generator/typeparser.h index b6ca9c57..20edb03f 100644 --- a/generator/typeparser.h +++ b/generator/typeparser.h @@ -54,7 +54,7 @@ class TypeParser Info() : is_reference(false), is_constant(false), is_busted(false), indirections(0) { } QStringList qualified_name; QStringList arrays; - QList template_instantiations; + QList template_instantiations; // I believe template_argument_types would be a better name uint is_reference : 1; uint is_constant : 1; uint is_busted : 1; diff --git a/generator/typesystem.cpp b/generator/typesystem.cpp index 4308a7cc..ae8111c4 100644 --- a/generator/typesystem.cpp +++ b/generator/typesystem.cpp @@ -49,6 +49,23 @@ #include #include +#include // Q_FALLTHROUGH + +/* This file needs to be rewritten as documented here: + * + * See: https://doc.qt.io/qt-6/xml-changes-qt6.html + * + * The rewrite may be backward compatible to Qt4.3 APIs because the base + * facilites (QXmlStreamReader) used to relace the 'SAX' parser were apparently + * available then. Use of Xml5Compat is a work round until such a rewrite has + * been done. + */ +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) +# if defined(__GNUC__) +# pragma GCC warning "Qt6: implement Qt6 compatible XML reading" +# endif +# include +#endif QString strings_Object = QLatin1String("Object"); QString strings_String = QLatin1String("String"); @@ -136,8 +153,10 @@ class StackElement class Handler : public QXmlDefaultHandler { public: - Handler(TypeDatabase *database, bool generate) - : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass) + Handler(TypeDatabase *database, unsigned int qtVersion, bool generate) + : m_database(database) + , m_qtVersion(qtVersion) + , m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass) { m_current_enum = 0; current = 0; @@ -178,6 +197,7 @@ class Handler : public QXmlDefaultHandler tagNames["reference-count"] = StackElement::ReferenceCount; } + bool startDocument() { m_nestingLevel = 0; m_disabledLevel = -1; return true; } bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts); bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName); @@ -195,6 +215,7 @@ class Handler : public QXmlDefaultHandler bool importFileElement(const QXmlAttributes &atts); bool convertBoolean(const QString &, const QString &, bool); + bool qtVersionMatches(const QXmlAttributes& atts, bool& ok); TypeDatabase *m_database; StackElement* current; @@ -210,6 +231,10 @@ class Handler : public QXmlDefaultHandler FieldModificationList m_field_mods; QHash tagNames; + + unsigned int m_qtVersion{}; + int m_nestingLevel{}; // current nesting level, needed to reset m_disabledLevel if leaving element + int m_disabledLevel{}; // if this is != 0, elements should be ignored }; bool Handler::error(const QXmlParseException &e) @@ -244,7 +269,7 @@ void Handler::fetchAttributeValues(const QString &name, const QXmlAttributes &at QString key = atts.localName(i).toLower(); QString val = atts.value(i); - if (!acceptedAttributes->contains(key)) { + if (!acceptedAttributes->contains(key) && key != "since-version" && key != "before-version") { ReportHandler::warning(QString("Unknown attribute for '%1': '%2'").arg(name).arg(key)); } else { (*acceptedAttributes)[key] = val; @@ -255,7 +280,14 @@ void Handler::fetchAttributeValues(const QString &name, const QXmlAttributes &at bool Handler::endElement(const QString &, const QString &localName, const QString &) { QString tagName = localName.toLower(); - if(tagName == "import-file") + int oldNestingLevel = m_nestingLevel--; + if (m_disabledLevel >= 0) { + if (m_disabledLevel == oldNestingLevel) { + m_disabledLevel = -1; + } + return true; + } + if(tagName == "import-file" || tagName == "group") return true; if (!current) @@ -304,7 +336,7 @@ bool Handler::endElement(const QString &, const QString &localName, const QStrin m_code_snips.last().addTemplateInstance(current->value.templateInstance); }else if(current->parent->type == StackElement::Template){ current->parent->value.templateEntry->addTemplateInstance(current->value.templateInstance); - }else if(current->parent->type == StackElement::CustomMetaConstructor || current->parent->type == StackElement::CustomMetaConstructor){ + }else if(current->parent->type == StackElement::CustomMetaConstructor){ current->parent->value.customFunction->addTemplateInstance(current->value.templateInstance); }else if(current->parent->type == StackElement::ConversionRule){ m_function_mods.last().argument_mods.last().conversion_rules.last().addTemplateInstance(current->value.templateInstance); @@ -437,15 +469,61 @@ bool Handler::convertBoolean(const QString &_value, const QString &attributeName } } +bool Handler::qtVersionMatches(const QXmlAttributes& atts, bool& ok) +{ + ok = true; + int beforeIndex = atts.index("before-version"); + if (beforeIndex >= 0) { + uint beforeVersion = TypeSystem::qtVersionFromString(atts.value(beforeIndex), ok); + if (ok) { + if (m_qtVersion >= beforeVersion) { + return false; + } + } + else { + m_error = "Invalid 'before-version' version string: " + atts.value(beforeIndex); + } + } + int sinceIndex = atts.index("since-version"); + if (sinceIndex >= 0) { + uint sinceVersion = TypeSystem::qtVersionFromString(atts.value(sinceIndex), ok); + if (ok) { + if (m_qtVersion < sinceVersion) { + return false; + } + } + else { + m_error = "Invalid 'since-version' version string: " + atts.value(sinceIndex); + } + } + return true; +} + bool Handler::startElement(const QString &, const QString &n, const QString &, const QXmlAttributes &atts) { QString tagName = n.toLower(); - if(tagName == "import-file"){ + m_nestingLevel++; + if (m_disabledLevel >= 0 && m_disabledLevel < m_nestingLevel) { + return true; + } + bool ok; + bool versionMatches = qtVersionMatches(atts, ok); + if (!ok) { + return false; // abort + } else if (!versionMatches) { + m_disabledLevel = m_nestingLevel; + return true; + } + + if (tagName == "import-file") { return importFileElement(atts); } + else if (tagName == "group") { // non-functional element to handle version ranges + return true; + } - std::auto_ptr element(new StackElement(current)); + std::unique_ptr element(new StackElement(current)); if (!tagNames.contains(tagName)) { m_error = QString("Unknown tag name: '%1'").arg(tagName); @@ -482,12 +560,12 @@ bool Handler::startElement(const QString &, const QString &n, case StackElement::ValueTypeEntry: attributes["force-abstract"] = QString("no"); attributes["deprecated"] = QString("no"); - // fall throooough + Q_FALLTHROUGH(); case StackElement::InterfaceTypeEntry: attributes["default-superclass"] = m_defaultSuperclass; attributes["polymorphic-id-expression"] = QString(); attributes["delete-in-main-thread"] = QString("no"); - // fall through + Q_FALLTHROUGH(); case StackElement::NamespaceTypeEntry: attributes["java-name"] = QString(); attributes["package"] = m_defaultPackage; @@ -661,7 +739,7 @@ bool Handler::startElement(const QString &, const QString &n, element->type == StackElement::ValueTypeEntry || element->type == StackElement::ObjectTypeEntry) { if (convertBoolean(attributes["delete-in-main-thread"], "delete-in-main-thread", false)) - ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DeleteInMainThread); + ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DeleteInMainThread); } QString targetType = attributes["target-type"]; @@ -734,7 +812,7 @@ bool Handler::startElement(const QString &, const QString &n, break; case StackElement::ModifyArgument: attributes["index"] = QString(); - attributes["replace-value"] = QString(); + attributes["replace-value"] = QString(); attributes["invalidate-after-use"] = QString("no"); break; case StackElement::ModifyField: @@ -827,7 +905,7 @@ bool Handler::startElement(const QString &, const QString &n, return false; } - if (!m_database->parseFile(name, convertBoolean(attributes["generate"], "generate", true))) { + if (!m_database->parseFile(name, m_qtVersion, convertBoolean(attributes["generate"], "generate", true))) { m_error = QString("Failed to parse: '%1'").arg(name); return false; } @@ -840,9 +918,7 @@ bool Handler::startElement(const QString &, const QString &n, } QString name = attributes["name"]; - bool added = false; if (!name.isEmpty()) { - added = true; m_current_enum->addEnumValueRejection(name); } @@ -910,18 +986,18 @@ bool Handler::startElement(const QString &, const QString &n, return false; } - QString replace_value = attributes["replace-value"]; + QString replace_value = attributes["replace-value"]; - if (!replace_value.isEmpty() && idx != 0) { - m_error = QString("replace-value is only supported for return values (index=0)."); - return false; - } + if (!replace_value.isEmpty() && idx != 0) { + m_error = QString("replace-value is only supported for return values (index=0)."); + return false; + } - ArgumentModification argumentModification = ArgumentModification(idx); - argumentModification.replace_value = replace_value; - argumentModification.reset_after_use = convertBoolean(attributes["invalidate-after-use"], "invalidate-after-use", false); - m_function_mods.last().argument_mods.append(argumentModification); - } + ArgumentModification argumentModification = ArgumentModification(idx); + argumentModification.replace_value = replace_value; + argumentModification.reset_after_use = convertBoolean(attributes["invalidate-after-use"], "invalidate-after-use", false); + m_function_mods.last().argument_mods.append(argumentModification); + } break; case StackElement::NoNullPointers: { @@ -1484,16 +1560,17 @@ TypeDatabase::TypeDatabase() : m_suppressWarnings(true) addRemoveFunctionToTemplates(this); } -bool TypeDatabase::parseFile(const QString &filename, bool generate) +bool TypeDatabase::parseFile(const QString &filename, unsigned int qtVersion, bool generate) { QFile file(filename); + Q_ASSERT(file.exists()); QXmlInputSource source(&file); int count = m_entries.size(); QXmlSimpleReader reader; - Handler handler(this, generate); + Handler handler(this, qtVersion, generate); reader.setContentHandler(&handler); reader.setErrorHandler(&handler); @@ -1665,19 +1742,6 @@ QString FlagsTypeEntry::jniName() const return "jint"; } -void EnumTypeEntry::addEnumValueRedirection(const QString &rejected, const QString &usedValue) -{ - m_enum_redirections << EnumValueRedirection(rejected, usedValue); -} - -QString EnumTypeEntry::enumValueRedirection(const QString &value) const -{ - for (int i=0; ijavaQualifier() + "." + targetLangName(); @@ -1837,7 +1901,7 @@ QString TemplateInstance::expandCode() const{ TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name); if(templateEntry){ QString res = templateEntry->code(); - foreach(QString key, replaceRules.keys()){ + for (QString key : replaceRules.keys()){ res.replace(key, replaceRules[key]); } return "// TEMPLATE - " + m_name + " - START" + res + "// TEMPLATE - " + m_name + " - END"; @@ -1851,7 +1915,7 @@ QString TemplateInstance::expandCode() const{ QString CodeSnipAbstract::code() const{ QString res; - foreach(CodeSnipFragment *codeFrag, codeList){ + for (CodeSnipFragment *codeFrag : codeList){ res.append(codeFrag->code()); } return res; @@ -2031,4 +2095,28 @@ QByteArray TypeSystem::normalizedSignature(const char* signature) result.replace("quint64", "ulonglong"); result.replace("QStringList", "QStringList"); return result; -} \ No newline at end of file +} + +unsigned int TypeSystem::qtVersionFromString(const QString& value, bool& ok) +{ + ok = true; + QList values; + for (QString dotValue : value.split('.')) + { + dotValue = dotValue.trimmed(); + bool ok2; + values.append(dotValue.toUInt(&ok2)); + if (!ok2) { + ok = false; + } + } + uint result = values[0] << 16; + if (values.size() >= 2) { + result += values[1] << 8; + } + if (values.size() >= 3) { + result += values[2]; + } + return result; +} + diff --git a/generator/typesystem.h b/generator/typesystem.h index b332bb96..a68850d8 100644 --- a/generator/typesystem.h +++ b/generator/typesystem.h @@ -48,6 +48,40 @@ #include #include +/* BEGIN: Qt6 compatibility. The following can removed when versions of Qt + * prior to 5.14 are no longer supported. + */ +/* QString::SkipEmptyParts was replicated in Qt::SplitBehavior in 15.4 and the + * QString original deprecated then it was removed in Qt6. This provides + * forward compatibility with Qt6 for versions of Qt prior to 15.4: + */ +#if QT_VERSION < QT_VERSION_CHECK(5,14,0) + namespace Qt { + const QString::SplitBehavior SkipEmptyParts = QString::SkipEmptyParts; + }; +#endif + +/* Global endl (::endl) is used extensively in the generator .cpp files. This + * was supported by Qt until Qt6. In Qt5.14 Qt::endl was added in anticipation + * of the Qt6 change and the use of global endl could be avoided (it does not + * seem to have been explicitly deprecated). This gives backward compatibility + * for global endl in Qt6 (not Qt5, where global endl was still available). + * + * Note that 'constexpr' is available in Qt6 because Qt6 requires C++17; + * constexpr was introduced in C++11. Likewise for decltype. Qt::endl is a + * function so ::endl is a pointer to the function and the implicit conversion + * is used; this is to cause an compiler error in the future if the base type + * of Qt::endl changes. + * + * When versions of Qt older than 5.14 are no longer supported this can be + * removed however all the 'endl' references in the code will need to be + * changed to Qt::endl. + */ +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + static constexpr decltype (Qt::endl) *endl = Qt::endl; +#endif +/* END: Qt compatibility. */ + class Indentor; class AbstractMetaType; @@ -133,7 +167,10 @@ namespace TypeSystem { //! A better normalized signature, which takes care of PODs with the same name QByteArray normalizedSignature(const char* signature); -}; + + //! Determine version ID from version string + unsigned int qtVersionFromString(const QString& value, bool& ok); +} struct ReferenceCount { @@ -644,7 +681,8 @@ class EnumTypeEntry : public TypeEntry : TypeEntry(nspace.isEmpty() ? enumName : nspace + QLatin1String("::") + enumName, EnumType), m_flags(0), - m_extensible(false) + m_extensible(false), + m_force_integer(false) { m_qualifier = nspace; m_java_name = enumName; @@ -689,8 +727,8 @@ class EnumTypeEntry : public TypeEntry void addEnumValueRejection(const QString &name) { m_rejected_enums << name; } QStringList enumValueRejections() const { return m_rejected_enums; } - void addEnumValueRedirection(const QString &rejected, const QString &usedValue); - QString enumValueRedirection(const QString &value) const; + bool isEnumClass() const { return m_enum_class; } + void setEnumClass(bool enum_class) { m_enum_class = enum_class; } bool forceInteger() const { return m_force_integer; } void setForceInteger(bool force) { m_force_integer = force; } @@ -705,11 +743,11 @@ class EnumTypeEntry : public TypeEntry QString m_upper_bound; QStringList m_rejected_enums; - QList m_enum_redirections; FlagsTypeEntry *m_flags; bool m_extensible; + bool m_enum_class; bool m_force_integer; }; @@ -750,7 +788,7 @@ class ComplexTypeEntry : public TypeEntry public: enum TypeFlag { ForceAbstract = 0x1, - DeleteInMainThread = 0x2, + DeleteInMainThread = 0x2, Deprecated = 0x4 }; typedef QFlags TypeFlags; @@ -763,6 +801,7 @@ class ComplexTypeEntry : public TypeEntry m_generic_class(false), m_createShell(false), m_createPromoter(false), + m_noCopy(false), m_type_flags(0) { Include inc; @@ -893,6 +932,9 @@ class ComplexTypeEntry : public TypeEntry bool isGenericClass() const { return m_generic_class; } void setGenericClass(bool isGeneric) { m_generic_class = isGeneric; } + bool hasNoCopy() const { return m_noCopy; } + void setNoCopy(bool noCopy) { m_noCopy = noCopy; } + private: IncludeList m_extra_includes; Include m_include; @@ -910,6 +952,7 @@ class ComplexTypeEntry : public TypeEntry uint m_generic_class : 1; uint m_createShell : 1; uint m_createPromoter : 1; + uint m_noCopy : 1; QString m_polymorphic_id_value; QString m_lookup_name; @@ -1052,7 +1095,7 @@ class InterfaceTypeEntry : public ComplexTypeEntry } private: - ObjectTypeEntry *m_origin; + ObjectTypeEntry *m_origin{}; }; @@ -1120,7 +1163,7 @@ class TypeDatabase SingleTypeEntryHash returned; QList keys = entries.keys(); - foreach(QString key, keys) { + for (QString key : keys) { returned[key] = findType(key); } @@ -1159,7 +1202,8 @@ class TypeDatabase foreach (const QString &_warning, m_suppressedWarnings) { QString warning(QString(_warning).replace("\\*", "&place_holder_for_asterisk;")); - QStringList segs = warning.split("*", QString::SkipEmptyParts); + QStringList segs = warning.split("*", Qt::SkipEmptyParts); + if (segs.size() == 0) continue ; @@ -1181,7 +1225,7 @@ class TypeDatabase static QString globalNamespaceClassName(const TypeEntry *te); QString filename() const { return "typesystem.txt"; } - bool parseFile(const QString &filename, bool generate = true); + bool parseFile(const QString &filename, unsigned int qtVersion, bool generate = true); private: bool m_suppressWarnings; diff --git a/generator/typesystem_core.xml b/generator/typesystem_core.xml index fa283404..32d68413 100644 --- a/generator/typesystem_core.xml +++ b/generator/typesystem_core.xml @@ -201,6 +201,8 @@ + + @@ -467,7 +469,6 @@ - @@ -483,7 +484,6 @@ - @@ -557,7 +557,27 @@ + + + + + + + + + + + + + + + + + + + + @@ -591,14 +611,20 @@ + + + + + + @@ -651,6 +677,7 @@ + @@ -666,9 +693,12 @@ - + + + + @@ -695,9 +725,9 @@ - + - + @@ -761,6 +791,9 @@ + + + @@ -816,6 +849,7 @@ + @@ -833,6 +867,7 @@ + @@ -852,6 +887,7 @@ + @@ -863,10 +899,12 @@ - - - - + + + + + + @@ -1030,8 +1068,11 @@ + + + @@ -1039,6 +1080,7 @@ + @@ -1050,6 +1092,7 @@ + @@ -1149,6 +1192,7 @@ + @@ -1250,12 +1294,14 @@ - + + + @@ -1270,10 +1316,30 @@ - + + + + + PythonQt::Type_EnterExit + + void __enter__(QMutexLocker* /*self*/) {} + void __exit__(QMutexLocker* self, PyObject* /*type*/, PyObject* /*value*/, PyObject* /*traceback*/) { self->unlock(); } + + + + + PythonQt::Type_EnterExit + + void __enter__(QReadLocker* /*self*/) {} + void __exit__(QReadLocker* self, PyObject* /*type*/, PyObject* /*value*/, PyObject* /*traceback*/) { self->unlock(); } + + + + + PythonQt::Type_EnterExit - void __enter__(QMutexLocker* self) {} - void __exit__(QMutexLocker* self) { self->unlock(); } + void __enter__(QWriteLocker* /*self*/) {} + void __exit__(QWriteLocker* self, PyObject* /*type*/, PyObject* /*value*/, PyObject* /*traceback*/) { self->unlock(); } @@ -1739,6 +1805,7 @@ + @@ -1925,6 +1992,7 @@ + @@ -1935,16 +2003,20 @@ + + + - + + @@ -1958,8 +2030,11 @@ + + + diff --git a/generator/typesystem_gui.xml b/generator/typesystem_gui.xml index 9c82b10f..80364fc9 100644 --- a/generator/typesystem_gui.xml +++ b/generator/typesystem_gui.xml @@ -190,6 +190,7 @@ + @@ -206,6 +207,7 @@ + @@ -246,7 +248,8 @@ - + + @@ -256,6 +259,7 @@ + @@ -569,7 +573,8 @@ - + + @@ -600,6 +605,8 @@ + + @@ -775,8 +782,8 @@ - - + + @@ -785,8 +792,6 @@ - - @@ -906,6 +911,11 @@ + + + QFontInfo* new_QFontInfo() { return new QFontInfo(QFont()); } + + @@ -965,7 +975,7 @@ - + @@ -999,7 +1009,11 @@ QImage* new_QImage( const uchar * data, int width, int height, QImage::Format format ) { QImage* image = new QImage(width, height, format); +#if QT_VERSION >= QT_VERSION_CHECK(5,10,0) + memcpy(image->bits(), data, image->sizeInBytes()); +#else memcpy(image->bits(), data, image->byteCount()); +#endif return image; } @@ -1007,7 +1021,11 @@ PyObject* bits(QImage* image) { return PythonQtPrivate::wrapMemoryAsBuffer(image->bits(), image->bytesPerLine()* image->height()); } -#if QT_VERSION >= QT_VERSION_CHECK(4,7,0) +#if QT_VERSION >= QT_VERSION_CHECK(5,10,0) +PyObject* constBits(QImage* image) { + return PythonQtPrivate::wrapMemoryAsBuffer(image->constBits(), image->sizeInBytes()); +} +#elif QT_VERSION >= QT_VERSION_CHECK(4,7,0) PyObject* constBits(QImage* image) { return PythonQtPrivate::wrapMemoryAsBuffer(image->constBits(), image->byteCount()); } @@ -1128,7 +1146,11 @@ PyObject* constScanLine(QImage* image, int line) { - + + QFontMetrics* new_QFontMetrics() { return new QFontMetrics(QFont()); } + + + @@ -1255,6 +1277,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -1642,6 +1665,19 @@ PyObject* constScanLine(QImage* image, int line) { + + + + + + + + + + + + + @@ -2071,18 +2107,20 @@ PyObject* constScanLine(QImage* image, int line) { - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -2476,11 +2514,16 @@ PyObject* constScanLine(QImage* image, int line) { - + - + + + + + + @@ -3046,7 +3089,7 @@ PyObject* constScanLine(QImage* image, int line) { - + diff --git a/generator/typesystem_multimedia.xml b/generator/typesystem_multimedia.xml index c206c518..d4f1a984 100644 --- a/generator/typesystem_multimedia.xml +++ b/generator/typesystem_multimedia.xml @@ -10,6 +10,11 @@ + + + + + @@ -52,6 +57,7 @@ + @@ -75,7 +81,7 @@ - + @@ -108,7 +114,7 @@ - + @@ -116,6 +122,11 @@ + + + + + @@ -176,4 +187,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/generator/typesystem_network.xml b/generator/typesystem_network.xml index 5696d50b..2b0a4b95 100644 --- a/generator/typesystem_network.xml +++ b/generator/typesystem_network.xml @@ -10,7 +10,11 @@ + + + + @@ -42,8 +46,10 @@ + + @@ -51,6 +57,7 @@ + @@ -170,6 +177,7 @@ + @@ -210,6 +218,7 @@ + diff --git a/generator/typesystem_qml.xml b/generator/typesystem_qml.xml index 3a1dec85..ebc664fd 100644 --- a/generator/typesystem_qml.xml +++ b/generator/typesystem_qml.xml @@ -13,6 +13,7 @@ + diff --git a/generator/typesystem_svg.xml b/generator/typesystem_svg.xml index 815cfca5..06d9f565 100644 --- a/generator/typesystem_svg.xml +++ b/generator/typesystem_svg.xml @@ -8,7 +8,7 @@ - + @@ -24,6 +24,7 @@ + diff --git a/generator/typesystem_webenginewidgets.xml b/generator/typesystem_webenginewidgets.xml index 1e545dbf..53fa87d5 100644 --- a/generator/typesystem_webenginewidgets.xml +++ b/generator/typesystem_webenginewidgets.xml @@ -12,6 +12,8 @@ + + @@ -38,6 +40,7 @@ + diff --git a/generator/typesystem_xml.xml b/generator/typesystem_xml.xml index f2fbe1bc..5fbba69e 100644 --- a/generator/typesystem_xml.xml +++ b/generator/typesystem_xml.xml @@ -35,6 +35,7 @@ + diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index efd68a14..8ff82ab6 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -58,10 +58,23 @@ #include +#if PY_VERSION_HEX >= 0x030A0000 +#include +#else #include +#endif + +// .co_varnames was removed in 3.11, but the helper function was added +#if PY_VERSION_HEX < 0x030B0000 +static inline PyObject *PyCode_GetVarnames(PyCodeObject *o) { + Py_XINCREF(o->co_varnames); + return o->co_varnames; +} +#endif + #include -PythonQt* PythonQt::_self = NULL; +PythonQt* PythonQt::_self = nullptr; int PythonQt::_uniqueModuleCount = 0; void PythonQt_init_QtGuiBuiltin(PyObject*); @@ -88,6 +101,16 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) _self->_p->_pySourcelessFileLoader = importlib.getVariable("SourcelessFileLoader"); } +#ifdef PY3K + PythonQtObjectPtr asyncio; + asyncio.setNewRef(PyImport_ImportModule("asyncio")); + if (asyncio) + { + _self->_p->_pyEnsureFuture = asyncio.getVariable("ensure_future"); + _self->_p->_pyFutureClass = asyncio.getVariable("Future"); + } +#endif + PythonQt::priv()->setupSharedLibrarySuffixes(); PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList"); @@ -99,8 +122,10 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) } else { qRegisterMetaType("size_t"); } +#if QT_VERSION < 0x060000 int stringRefId = qRegisterMetaType("QStringRef"); PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConv::convertFromStringRef); +#endif int objectPtrListId = qRegisterMetaType >("QList"); PythonQtConv::registerMetaTypeToPythonConverter(objectPtrListId, PythonQtConv::convertFromQListOfPythonQtObjectPtr); @@ -196,11 +221,11 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) PythonQtRegisterIntegerMapConverter(QHash, QString); PythonQtMethodInfo::addParameterTypeAlias("QHash", "QHash"); - PythonQt_init_QtCoreBuiltin(NULL); - PythonQt_init_QtGuiBuiltin(NULL); + PythonQt_init_QtCoreBuiltin(nullptr); + PythonQt_init_QtGuiBuiltin(nullptr); PythonQt::self()->addDecorators(new PythonQtStdDecorators()); - PythonQt::self()->registerCPPClass("QMetaObject",0, "QtCore", PythonQtCreateObject); + PythonQt::self()->registerCPPClass("QMetaObject",nullptr, "QtCore", PythonQtCreateObject); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QByteArray); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QDate); @@ -216,7 +241,10 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) PythonQtRegisterToolClassesTemplateConverterForKnownClass(QLineF); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QPoint); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QPointF); +#if QT_VERSION < 0x060000 PythonQtRegisterToolClassesTemplateConverterForKnownClass(QRegExp); +#endif + PythonQtRegisterToolClassesTemplateConverterForKnownClass(QRegularExpression); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QFont); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QPixmap); @@ -234,19 +262,24 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) PythonQtRegisterToolClassesTemplateConverterForKnownClass(QPen); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QTextLength); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QTextFormat); - PythonQtRegisterToolClassesTemplateConverterForKnownClass(QMatrix); PyObject* pack = PythonQt::priv()->packageByName("QtCore"); PyObject* pack2 = PythonQt::priv()->packageByName("Qt"); PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper(); const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal" ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"}; - for (unsigned int i = 0;i<16; i++) { + for (unsigned int i = 0; i < sizeof(names) / sizeof(names[0]); i++) { PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]); if (obj) { - PyModule_AddObject(pack, names[i], obj); - Py_INCREF(obj); - PyModule_AddObject(pack2, names[i], obj); + if (PyModule_AddObject(pack, names[i], obj) < 0) { + std::cerr << "failed to add " << names[i] << " to QtCore\n"; + } else { + Py_INCREF(obj); + } + if(PyModule_AddObject(pack2, names[i], obj) < 0) { + Py_DECREF(obj); + std::cerr << "failed to add " << names[i] << " to Qt\n"; + } } else { std::cerr << "method not found " << names[i] << std::endl; } @@ -266,14 +299,18 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) "QtSystemMsg" }; - for (int i = 0; ipriv()->pythonQtModule().addObject("Debug", _self->priv()->_debugAPI); + _self->priv()->pythonQtModule().addObject("Config", _self->priv()->_configAPI); Py_INCREF((PyObject*)&PythonQtSlotDecorator_Type); Py_INCREF((PyObject*)&PythonQtSignalFunction_Type); @@ -293,7 +330,7 @@ void PythonQt::cleanup() _self->removeSignalHandlers(); delete _self; - _self = NULL; + _self = nullptr; } } @@ -382,24 +419,68 @@ PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName) PythonQt::~PythonQt() { delete _p; - _p = NULL; + _p = nullptr; } PythonQtPrivate::~PythonQtPrivate() { delete _defaultImporter; - _defaultImporter = NULL; + _defaultImporter = nullptr; { - QHashIterator i(_knownClassInfos); - while (i.hasNext()) { - delete i.next().value(); - } + qDeleteAll(_knownClassInfos); } PythonQtMethodInfo::cleanupCachedMethodInfos(); PythonQtArgumentFrame::cleanupFreeList(); } +void PythonQtPrivate::setTaskDoneCallback(const PythonQtObjectPtr & callable) +{ + _pyTaskDoneCallback = callable; +} + +PythonQtObjectPtr PythonQtPrivate::checkAndRunCoroutine(const PythonQtObjectPtr& object) +{ + PythonQtObjectPtr result; +#ifdef PY3K + if (!PyCoro_CheckExact(object)) + { + return result; + } + + if (!_pyEnsureFuture) + { + std::cerr << "PythonQt: ensure_future not initialized" << std::endl; + return PythonQtObjectPtr(); + } + PyObject* args = PyTuple_New(1); + PyObject* coro = object.object(); + Py_INCREF(coro); + PyTuple_SetItem(args, 0, coro); + PyObject* r = PyObject_CallObject(_pyEnsureFuture, args); + result.setNewRef(r); + if (_pyTaskDoneCallback) { + PyObject* methodName = PyUnicode_FromString("add_done_callback"); + PyObject_CallMethodObjArgs(r, methodName, _pyTaskDoneCallback.object(), nullptr); + Py_XDECREF(methodName); + } + Py_XDECREF(args); +#else + Q_UNUSED(object) +#endif + return result; +} + +PythonQtObjectPtr PythonQtPrivate::createAsyncioFuture() +{ + if (!_pyFutureClass) + { + std::cerr << "PythonQt: _pyFutureClass not initialized" << std::endl; + return nullptr; + } + return _pyFutureClass.call(); +} + void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData) { if (!callback) { @@ -416,7 +497,7 @@ void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * PyObject_SetAttrString(sys.object(), "pythonqt_original_stdin", PyObject_GetAttrString(sys.object(), "stdin")); } - in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL); + in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, nullptr, nullptr); ((PythonQtStdInRedirect*)in.object())->_cb = callback; ((PythonQtStdInRedirect*)in.object())->_callData = callbackData; // replace the built in file objects with our own objects @@ -433,11 +514,11 @@ void PythonQt::setRedirectStdInCallbackEnabled(bool enabled) sys.setNewRef(PyImport_ImportModule("sys")); if (enabled) { - if( PyObject_HasAttrString(sys.object(), "pythonqt_stdin") ) { + if( !PyObject_HasAttrString(sys.object(), "pythonqt_stdin") ) { PyObject_SetAttrString(sys.object(), "stdin", PyObject_GetAttrString(sys.object(), "pythonqt_stdin")); } } else { - if( PyObject_HasAttrString(sys.object(), "pythonqt_original_stdin") ) { + if( !PyObject_HasAttrString(sys.object(), "pythonqt_original_stdin") ) { PyObject_SetAttrString(sys.object(), "stdin", PyObject_GetAttrString(sys.object(), "pythonqt_original_stdin")); } } @@ -452,7 +533,7 @@ void PythonQt::qObjectNoLongerWrappedCB(QObject* o) { if (_self->_p->_noLongerWrappedCB) { (*_self->_p->_noLongerWrappedCB)(o); - }; + } } void PythonQt::setQObjectMissingAttributeCallback(PythonQtQObjectMissingAttributeCB* cb) @@ -496,7 +577,9 @@ void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* p PyObject* classWrapper = info->pythonQtClassWrapper(); // AddObject steals a reference, so we need to INCREF Py_INCREF(classWrapper); - PyModule_AddObject(module, info->className(), classWrapper); + if (PyModule_AddObject(module, info->className(), classWrapper) < 0) { + Py_DECREF(classWrapper); + } } if (first) { first = false; @@ -529,13 +612,17 @@ void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const PythonQtClassInfo* outerClassInfo = lookupClassInfoAndCreateIfNotPresent(outerClass); outerClassInfo->addNestedClass(info); } else { - PyModule_AddObject(pack, info->className(), pyobj); + if (PyModule_AddObject(pack, info->className(), pyobj) == 0) { + // since PyModule_AddObject steals the reference, we need a incref once more... + Py_INCREF(pyobj); + } } if (!module && package && strncmp(package, "Qt", 2) == 0) { - // since PyModule_AddObject steals the reference, we need a incref once more... - Py_INCREF(pyobj); // put all qt objects into Qt as well - PyModule_AddObject(packageByName("Qt"), info->className(), pyobj); + if (PyModule_AddObject(packageByName("Qt"), info->className(), pyobj) == 0) { + // since PyModule_AddObject steals the reference, we need a incref once more... + Py_INCREF(pyobj); + } } info->setPythonQtClassWrapper(pyobj); } @@ -552,12 +639,12 @@ PyObject* PythonQtPrivate::wrapQObject(QObject* obj) // address, so probably that C++ wrapper has been deleted earlier and // now we see a QObject with the same address. // Do not use the old wrapper anymore. - wrap = NULL; + wrap = nullptr; } if (!wrap) { // smuggling it in... PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className()); - if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) { + if (!classInfo || classInfo->pythonQtClassWrapper()==nullptr) { registerClass(obj->metaObject()); classInfo = _knownClassInfos.value(obj->metaObject()->className()); } @@ -578,7 +665,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name, bool passO } PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr); - PythonQtInstanceWrapper* possibleStillAliveWrapper = NULL; + PythonQtInstanceWrapper* possibleStillAliveWrapper = nullptr; if (wrap && wrap->_wrappedPtr) { // we have a previous C++ wrapper... if the wrapper is for a C++ object, // we are not sure if it may have been deleted earlier and we just see the same C++ @@ -586,7 +673,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name, bool passO // we compare the classInfo() pointer and only reuse the wrapper if it has the same // info. This is only needed for non-QObjects, since we know it when a QObject gets deleted. possibleStillAliveWrapper = wrap; - wrap = NULL; + wrap = nullptr; } if (!wrap) { PythonQtClassInfo* info = getClassInfo(name); @@ -611,7 +698,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name, bool passO // if the object is a derived object, we want to switch the class info to the one of the derived class: if (name!=(qptr->metaObject()->className())) { info = _knownClassInfos.value(qptr->metaObject()->className()); - if (!info || (info->pythonQtClassWrapper() == NULL)) { + if (!info || (info->pythonQtClassWrapper() == nullptr)) { registerClass(qptr->metaObject()); info = _knownClassInfos.value(qptr->metaObject()->className()); } @@ -623,7 +710,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name, bool passO } // not a known QObject, try to wrap via foreign wrapper factories - PyObject* foreignWrapper = NULL; + PyObject* foreignWrapper = nullptr; for (int i=0; i<_foreignWrapperFactories.size(); i++) { foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr); if (foreignWrapper) { @@ -632,7 +719,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name, bool passO } // not a known QObject, so try our wrapper factory: - QObject* wrapper = NULL; + QObject* wrapper = nullptr; for (int i=0; i<_cppWrapperFactories.size(); i++) { wrapper = _cppWrapperFactories.at(i)->create(name, ptr); if (wrapper) { @@ -660,7 +747,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name, bool passO } } - if (!info || info->pythonQtClassWrapper()==NULL) { + if (!info || info->pythonQtClassWrapper()==nullptr) { // still unknown, register as CPP class registerCPPClass(name.constData()); info = _knownClassInfos.value(name); @@ -686,8 +773,8 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name, bool passO } PyObject* PythonQtPrivate::dummyTuple() { - static PyObject* dummyTuple = NULL; - if (dummyTuple==NULL) { + static PyObject* dummyTuple = nullptr; + if (dummyTuple==nullptr) { dummyTuple = PyTuple_New(1); PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy")); } @@ -697,7 +784,7 @@ PyObject* PythonQtPrivate::dummyTuple() { PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) { // call the associated class type to create a new instance... - PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL); + PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), nullptr); result->setQObject(obj); result->_wrappedPtr = wrappedPtr; @@ -716,7 +803,7 @@ PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObje _wrappedObjects.insert(wrappedPtr, result); } else { _wrappedObjects.insert(obj, result); - if (obj->parent()== NULL && _wrappedCB) { + if (obj->parent()== nullptr && _wrappedCB) { // tell someone who is interested that the qobject is wrapped the first time, if it has no parent (*_wrappedCB)(obj); } @@ -743,11 +830,12 @@ PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtCla // set the class info so that PythonQtClassWrapper_new can read it _currentClassInfoForClassWrapperCreation = info; // create the new type object by calling the type - result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL); + result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, nullptr); Py_DECREF(moduleName); Py_DECREF(baseClasses); Py_DECREF(typeDict); + Py_DECREF(moduleName); Py_DECREF(args); Py_DECREF(className); @@ -757,7 +845,7 @@ PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtCla PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue) { PyObject* args = Py_BuildValue("(i)", enumValue); - PyObject* result = PyObject_Call(enumType, args, NULL); + PyObject* result = PyObject_Call(enumType, args, nullptr); Py_DECREF(args); return result; } @@ -778,10 +866,11 @@ PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, Py PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict); // create the new int derived type object by calling the core type - result = PyObject_Call((PyObject *)&PyType_Type, args, NULL); + result = PyObject_Call((PyObject *)&PyType_Type, args, nullptr); Py_DECREF(module); Py_DECREF(baseClasses); + Py_DECREF(module); Py_DECREF(typeDict); Py_DECREF(args); Py_DECREF(className); @@ -859,7 +948,7 @@ PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name } } PyErr_Clear(); - return NULL; + return nullptr; } PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name) @@ -899,8 +988,8 @@ QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) { QVariant result; clearError(); if (pycode) { - PyObject* dict = NULL; - PyObject* globals = NULL; + PyObject* dict = nullptr; + PyObject* globals = nullptr; if (PyModule_Check(object)) { dict = PyModule_GetDict(object); globals = dict; @@ -911,7 +1000,7 @@ QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) { dict = PyObject_GetAttrString(object, "__dict__"); globals = PyObject_GetAttrString(PyImport_ImportModule(PyString_AS_STRING(PyObject_GetAttrString(object, "__module__"))),"__dict__"); } - PyObject* r = NULL; + PyObject* r = nullptr; if (dict) { #ifdef PY3K r = PyEval_EvalCode(pycode, globals, dict); @@ -935,7 +1024,7 @@ QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start { QVariant result; PythonQtObjectPtr p; - PyObject* dict = NULL; + PyObject* dict = nullptr; clearError(); if (PyModule_Check(object)) { dict = PyModule_GetDict(object); @@ -996,7 +1085,7 @@ PythonQtObjectPtr PythonQt::parseFileWithPythonLoaders(const QString& file) { PythonQtObjectPtr result; QString filename = file; - PyObject* loaderClass = NULL; + PyObject* loaderClass = nullptr; if (QFile::exists(filename)) { loaderClass = _p->_pySourceFileLoader; } else { @@ -1055,7 +1144,10 @@ PythonQtObjectPtr PythonQt::createUniqueModule() void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject) { if (PyModule_Check(object)) { - PyModule_AddObject(object, QStringToPythonCharPointer(name), _p->wrapQObject(qObject)); + auto pyobj = _p->wrapQObject(qObject); + if (PyModule_AddObject(object, QStringToPythonCharPointer(name), pyobj) < 0) { + Py_DECREF(pyobj); + } } else if (PyDict_Check(object)) { PyDict_SetItemString(object, QStringToPythonCharPointer(name), _p->wrapQObject(qObject)); } else { @@ -1066,7 +1158,10 @@ void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v) { if (PyModule_Check(object)) { - PyModule_AddObject(object, QStringToPythonCharPointer(name), PythonQtConv::QVariantToPyObject(v)); + auto pyobj = PythonQtConv::QVariantToPyObject(v); + if (PyModule_AddObject(object, QStringToPythonCharPointer(name), pyobj) < 0) { + Py_DECREF(pyobj); + } } else if (PyDict_Check(object)) { PyDict_SetItemString(object, QStringToPythonCharPointer(name), PythonQtConv::QVariantToPyObject(v)); } else { @@ -1165,7 +1260,7 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type) } } } else { - PyObject* keys = NULL; + PyObject* keys = nullptr; bool isDict = false; if (PyDict_Check(object)) { keys = PyDict_Keys(object); @@ -1259,7 +1354,7 @@ PyObject* PythonQt::getObjectByType(const QString& typeName) QString simpleTypeName = tmp.takeLast(); QString moduleName = tmp.join("."); - PyObject* object = NULL; + PyObject* object = nullptr; PyObject* moduleObject = PyDict_GetItemString(modules, QStringToPythonCharPointer(moduleName)); if (moduleObject) { object = PyObject_GetAttrString(moduleObject, QStringToPythonCharPointer(simpleTypeName)); @@ -1330,7 +1425,7 @@ QVariant PythonQt::call(PyObject* callable, const QVariantList& args, const QVar PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs) { - PyObject* result = NULL; + PyObject* result = nullptr; if (callable) { bool err = false; PythonQtObjectPtr pargs; @@ -1430,16 +1525,17 @@ void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory ) //--------------------------------------------------------------------------------------------------- PythonQtPrivate::PythonQtPrivate() { - _importInterface = NULL; + _importInterface = nullptr; _defaultImporter = new PythonQtQFileImporter; - _noLongerWrappedCB = NULL; - _wrappedCB = NULL; - _qObjectMissingAttribCB = NULL; - _currentClassInfoForClassWrapperCreation = NULL; - _profilingCB = NULL; + _noLongerWrappedCB = nullptr; + _wrappedCB = nullptr; + _qObjectMissingAttribCB = nullptr; + _currentClassInfoForClassWrapperCreation = nullptr; + _profilingCB = nullptr; _hadError = false; _systemExitExceptionHandlerEnabled = false; _debugAPI = new PythonQtDebugAPI(this); + _configAPI = new PythonQtConfigAPI(this); } void PythonQtPrivate::setupSharedLibrarySuffixes() @@ -1471,7 +1567,7 @@ void PythonQtPrivate::setupSharedLibrarySuffixes() PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation() { PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation; - _currentClassInfoForClassWrapperCreation = NULL; + _currentClassInfoForClassWrapperCreation = nullptr; return info; } @@ -1490,12 +1586,12 @@ void PythonQtPrivate::addDecorators(QObject* o, int decoTypes) m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) { if (signature.startsWith("new_")) { if ((decoTypes & ConstructorDecorator) == 0) continue; - const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL); + const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, nullptr); if (info->parameters().at(0).pointerCount == 1) { QByteArray nameOfClass = signature.mid(4); nameOfClass.replace("__", "::"); PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass); - PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator); + PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(nullptr, m, i, o, PythonQtSlotInfo::ClassDecorator); classInfo->addConstructor(newSlot); } } else if (signature.startsWith("delete_")) { @@ -1503,23 +1599,23 @@ void PythonQtPrivate::addDecorators(QObject* o, int decoTypes) QByteArray nameOfClass = signature.mid(7); nameOfClass.replace("__", "::"); PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass); - PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator); + PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(nullptr, m, i, o, PythonQtSlotInfo::ClassDecorator); classInfo->setDestructor(newSlot); } else if (signature.startsWith("static_")) { if ((decoTypes & StaticDecorator) == 0) continue; QByteArray nameOfClass = signature.mid(7); nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_')); PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass); - PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator); + PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(nullptr, m, i, o, PythonQtSlotInfo::ClassDecorator); classInfo->addDecoratorSlot(newSlot); } else { if ((decoTypes & InstanceDecorator) == 0) continue; - const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL); + const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, nullptr); if (info->parameters().count()>1) { PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1); if (p.pointerCount==1) { PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name); - PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator); + PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(nullptr, m, i, o, PythonQtSlotInfo::InstanceDecorator); classInfo->addDecoratorSlot(newSlot); } } @@ -1576,7 +1672,7 @@ int custom_system_exit_exception_handler() // TODO: unclear what to do, since Py_FlushLine is gone... #endif fflush(stdout); - if (value == NULL || value == Py_None) + if (value == nullptr || value == Py_None) goto done; if (PyExceptionInstance_Check(value)) { /* The error code should be in the `code' attribute. */ @@ -1594,7 +1690,7 @@ int custom_system_exit_exception_handler() exitcode = (int)PyInt_AsLong(value); else { PyObject *sys_stderr = PySys_GetObject(const_cast("stderr")); - if (sys_stderr != NULL && sys_stderr != Py_None) { + if (sys_stderr != nullptr && sys_stderr != Py_None) { PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW); } else { PyObject_Print(value, stderr, Py_PRINT_RAW); @@ -1635,7 +1731,7 @@ bool PythonQt::handleError(bool printStack) PyErr_Fetch(&ptype, &pvalue, &ptraceback); PyErr_NormalizeException(&ptype, &pvalue, &ptraceback); // we leave out the traceback: - PyErr_Display(ptype, pvalue, NULL); + PyErr_Display(ptype, pvalue, nullptr); PyErr_Restore(ptype, pvalue, ptraceback); PyErr_Clear(); } @@ -1690,6 +1786,20 @@ void PythonQt::overwriteSysPath(const QStringList& paths) void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths) { PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths)); +#if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4) + // Since Python 3.4 a module has a __spec__ member of type ModuleSpec which + // mirrors some module-specific attributes, see + // https://docs.python.org/3/library/importlib.html#importlib.machinery.ModuleSpec . + // + // Python 3.9 prints an import warning "__package__ != __spec__.parent" on relative imports + // if we don't set the submodule_search_locations on __spec__ (this indirectly changes + // the value of parent) + PyObject* spec = PyObject_GetAttrString(module, "__spec__"); + if (spec) { + PythonQt::self()->addVariable(spec, "submodule_search_locations", paths); + Py_DECREF(spec); + } +#endif } void PythonQt::stdOutRedirectCB(const QString& str) @@ -1735,20 +1845,20 @@ void PythonQt::setEnableThreadSupport(bool flag) } static PyMethodDef PythonQtMethods[] = { - {NULL, NULL, 0, NULL} + {nullptr, nullptr, 0, nullptr} }; #ifdef PY3K static PyModuleDef PythonQtModuleDef = { PyModuleDef_HEAD_INIT, "", - NULL, + nullptr, -1, PythonQtMethods, - NULL, - NULL, - NULL, - NULL + nullptr, + nullptr, + nullptr, + nullptr }; #endif @@ -1974,11 +2084,37 @@ void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentT if (shell) { info->setShellSetInstanceWrapperCB(shell); } + if (info->typeSlots() & PythonQt::Type_EnterExit) { + // context handlers must be handled specially, because optimized accesses + // cause that the __enter__ and __exit__ methods will not be found by + // conventional means: + PyObject* classObj = (PyObject*)info->pythonQtClassWrapper(); + PyTypeObject* typeObj = (PyTypeObject*)classObj; + // __enter__ and _exit__ must be inserted directly into the tp_dict, + // otherwise they are not found by "with": + PyObject* tp_dict = typeObj->tp_dict; + PyObject* enterMethod = PyObject_GetAttrString(classObj, "__enter__"); + if (enterMethod) { + PyDict_SetItemString(tp_dict, "__enter__", enterMethod); + Py_DECREF(enterMethod); + } + PyErr_Clear(); + PyObject* exitMethod = PyObject_GetAttrString(classObj, "__exit__"); + if (exitMethod) { + PyDict_SetItemString(tp_dict, "__exit__", exitMethod); + Py_DECREF(exitMethod); + } + PyErr_Clear(); + // invalidate attribute cache for this type: + // (as the search for the class methods otherwise cached methods as "not existing", and + // we don't want to rely on the wrong empty entries being evicted from the cache by chance): + typeObj->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; + } } PyObject* PythonQtPrivate::packageByName(const char* name) { - if (name==NULL || name[0]==0) { + if (name==nullptr || name[0]==0) { name = "private"; } PyObject* v = _packages.value(name); @@ -2039,13 +2175,13 @@ void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrap PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj) { PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj); - if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) { + if (wrap && !wrap->_wrappedPtr && wrap->_obj == nullptr) { // this is a wrapper whose QObject was already removed due to destruction // so the obj pointer has to be a new QObject with the same address... // we remove the old one and set the copy to NULL - wrap->_objPointerCopy = NULL; + wrap->_objPointerCopy = nullptr; removeWrapperPointer(obj); - wrap = NULL; + wrap = nullptr; } return wrap; } @@ -2064,14 +2200,14 @@ PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* p void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj ) { - void* foreignObject = NULL; + void* foreignObject = nullptr; for (int i=0; i<_foreignWrapperFactories.size(); i++) { foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj); if (foreignObject) { return foreignObject; } } - return NULL; + return nullptr; } bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const @@ -2129,9 +2265,9 @@ const QMetaObject* PythonQtPrivate::buildDynamicMetaObject(PythonQtClassWrapper* builder.setClassName(((PyTypeObject*)type)->tp_name); PyObject* dict = ((PyTypeObject*)type)->tp_dict; - Py_ssize_t pos = NULL; - PyObject* value = NULL; - PyObject* key = NULL; + Py_ssize_t pos = 0; + PyObject* value = nullptr; + PyObject* key = nullptr; static PyObject* qtSlots = PyString_FromString("_qtSlots"); bool needsMetaObject = false; @@ -2144,15 +2280,15 @@ const QMetaObject* PythonQtPrivate::buildDynamicMetaObject(PythonQtClassWrapper* if (signal->_dynamicInfo) { signal->_dynamicInfo->name = PyString_AsString(key); foreach(QByteArray sig, signal->_dynamicInfo->signatures) { - QMetaMethodBuilder method = builder.addSignal(signal->_dynamicInfo->name + "(" + sig + ")"); + builder.addSignal(signal->_dynamicInfo->name + "(" + sig + ")"); needsMetaObject = true; } } } } - pos = NULL; - value = NULL; - key = NULL; + pos = 0; + value = nullptr; + key = nullptr; // Now look for slots: (this is a bug in QMetaObjectBuilder, all signals need to be added first) while (PyDict_Next(dict, &pos, &key, &value)) { if (PythonQtProperty_Check(value)) { @@ -2160,8 +2296,8 @@ const QMetaObject* PythonQtPrivate::buildDynamicMetaObject(PythonQtClassWrapper* PythonQtProperty* prop = (PythonQtProperty*)value; QMetaPropertyBuilder newProp = builder.addProperty(PyString_AsString(key), prop->data->cppType); newProp.setReadable(true); - newProp.setWritable(prop->data->fset != NULL); - newProp.setResettable(prop->data->freset != NULL); + newProp.setWritable(prop->data->fset != nullptr); + newProp.setResettable(prop->data->freset != nullptr); newProp.setDesignable(prop->data->designable); newProp.setScriptable(prop->data->scriptable); newProp.setStored(prop->data->stored); @@ -2231,7 +2367,7 @@ int PythonQtPrivate::handleMetaCall(QObject* object, PythonQtInstanceWrapper* wr if (!metaProp.isValid()) { return id - methodCount; } - PythonQtProperty* prop = NULL; + PythonQtProperty* prop = nullptr; // Get directly from the Python class, since we don't want to get the value of the property PyObject* maybeProp = PyBaseObject_Type.tp_getattro((PyObject*)wrapper, PyString_FromString(metaProp.name())); if (maybeProp && PythonQtProperty_Check(maybeProp)) { @@ -2252,9 +2388,9 @@ int PythonQtPrivate::handleMetaCall(QObject* object, PythonQtInstanceWrapper* wr PyObject* value = prop->data->callGetter((PyObject*)wrapper); if (value) { - void* result = PythonQtConv::ConvertPythonToQt(info, value, false, NULL, args[0]); + void* result = PythonQtConv::ConvertPythonToQt(info, value, false, nullptr, args[0]); Py_DECREF(value); - return (result == NULL ? -1 : 0); + return (result == nullptr ? -1 : 0); } else { return -1; } @@ -2268,13 +2404,12 @@ int PythonQtPrivate::handleMetaCall(QObject* object, PythonQtInstanceWrapper* wr void PythonQtPrivate::callMethodInPython(QMetaMethod &method, PythonQtInstanceWrapper* wrapper, void** args) { - QByteArray methodSig = method.methodSignature(); PyObject* func = PyObject_GetAttrString((PyObject*)wrapper, method.name()); if (func) { - const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfo(method, NULL); + const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfo(method, nullptr); PyObject* result = PythonQtSignalTarget::call(func, methodInfo, args, false); if (result) { - PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, args[0]); + PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, nullptr, args[0]); // TODO: handle error? //PythonQt::priv()->handleVirtualOverloadReturnError("devType", methodInfo, result); } @@ -2288,8 +2423,8 @@ QString PythonQtPrivate::getSignature(PyObject* object) QString signature; if (object) { - PyMethodObject* method = NULL; - PyFunctionObject* func = NULL; + PyMethodObject* method = nullptr; + PyFunctionObject* func = nullptr; bool decrefMethod = false; @@ -2354,25 +2489,26 @@ QString PythonQtPrivate::getSignature(PyObject* object) // inspect.getargs() can handle anonymous (tuple) arguments, while this code does not. // It can be implemented, but it may be rarely needed and not necessary. PyCodeObject* code = (PyCodeObject*)func->func_code; - if (code->co_varnames) { + if (auto co_varnames = PyCode_GetVarnames(code)) { int nargs = code->co_argcount; - Q_ASSERT(PyTuple_Check(code->co_varnames)); + Q_ASSERT(PyTuple_Check(co_varnames)); for (int i=0; ico_varnames, i); + PyObject* name = PyTuple_GetItem(co_varnames, i); Q_ASSERT(PyString_Check(name)); arguments << PyString_AsString(name); } if (code->co_flags & CO_VARARGS) { - PyObject* s = PyTuple_GetItem(code->co_varnames, nargs); + PyObject* s = PyTuple_GetItem(co_varnames, nargs); Q_ASSERT(PyString_Check(s)); varargs = PyString_AsString(s); nargs += 1; } if (code->co_flags & CO_VARKEYWORDS) { - PyObject* s = PyTuple_GetItem(code->co_varnames, nargs); + PyObject* s = PyTuple_GetItem(co_varnames, nargs); Q_ASSERT(PyString_Check(s)); varkeywords = PyString_AsString(s); } + Py_DECREF(co_varnames); } PyObject* defaultsTuple = func->func_defaults; @@ -2425,7 +2561,7 @@ void PythonQtPrivate::shellClassDeleted( void* shellClass ) if (wrap->_wrappedPtr) { // this is a pure C++ wrapper and the shell has gone, so we need // to set the _wrappedPtr to NULL on the wrapper - wrap->_wrappedPtr = NULL; + wrap->_wrappedPtr = nullptr; // and then we remove the wrapper, since the wrapped class is gone _wrappedObjects.remove(shellClass); } diff --git a/src/PythonQt.h b/src/PythonQt.h index 1bd6b45f..767f9928 100644 --- a/src/PythonQt.h +++ b/src/PythonQt.h @@ -144,7 +144,7 @@ template int PythonQtUpcastingOffset() { typedef QObject* PythonQtQObjectCreatorFunctionCB(); //! helper template to create a derived QObject class -template QObject* PythonQtCreateObject() { return new T(); }; +template QObject* PythonQtCreateObject() { return new T(); } //! Helper define to convert from QString to Python C-API #ifdef PY3K @@ -208,6 +208,8 @@ class PYTHONQT_EXPORT PythonQt : public QObject { Type_MappingSetItem = 1 << 21, Type_MappingGetItem = 1 << 22, + Type_EnterExit = 1 << 23, + Type_Invert = 1 << 29, Type_RichCompare = 1 << 30, Type_NonZero = 1 << 31, @@ -258,7 +260,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject { //! Overwrite default handling of stdin using a custom callback. It internally backup //! the original 'sys.stdin' into 'sys.pythonqt_original_stdin' - void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = 0); + void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = nullptr); //! Enable or disable stdin custom callback. It resets 'sys.stdin' using either 'sys.pythonqt_stdin' //! or 'sys.pythonqt_original_stdin' @@ -329,7 +331,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject { //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well) /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject, you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */ - void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL); + void registerClass(const QMetaObject* metaobject, const char* package = nullptr, PythonQtQObjectCreatorFunctionCB* wrapperCreator = nullptr, PythonQtShellSetInstanceWrapperCB* shell = nullptr); //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants //! (ownership of wrapper is passed to PythonQt) @@ -339,7 +341,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject { All slots that take a pointer to typeName as the first argument will be callable from Python on a variant object that contains such a type. */ - void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL); + void registerCPPClass(const char* typeName, const char* parentTypeName = nullptr, const char* package = nullptr, PythonQtQObjectCreatorFunctionCB* wrapperCreator = nullptr, PythonQtShellSetInstanceWrapperCB* shell = nullptr); //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes //! and it will register the classes when it first sees a pointer to such a derived class @@ -375,7 +377,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject { //! evaluates the given script code and returns the result value QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input); - + //! evaluates the given script code in context of given globals and locals and returns the result value QVariant evalScript(const QString& script, PyObject* globals, PyObject* locals, int start); @@ -546,7 +548,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject { //! the default importer allows to import files from anywhere QFile can read from, //! including the Qt resource system using ":". Keep in mind that you need to extend //! "sys.path" with ":" to be able to import from the Qt resources. - void installDefaultImporter() { setImporter(NULL); } + void installDefaultImporter() { setImporter(nullptr); } //! set paths that the importer should ignore void setImporterIgnorePaths(const QStringList& paths); @@ -652,7 +654,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject { PythonQtSignalReceiver* getSignalReceiver(QObject* obj); PythonQt(int flags, const QByteArray& pythonQtModuleName); - ~PythonQt(); + ~PythonQt() override; static PythonQt* _self; static int _uniqueModuleCount; @@ -661,6 +663,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject { }; class PythonQtDebugAPI; +class PythonQtConfigAPI; //! internal PythonQt details class PYTHONQT_EXPORT PythonQtPrivate : public QObject { @@ -669,7 +672,7 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject { public: PythonQtPrivate(); - ~PythonQtPrivate(); + ~PythonQtPrivate() override; enum DecoratorTypes { StaticDecorator = 1, @@ -679,6 +682,16 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject { AllDecorators = 0xffff }; + //! Set a callable that is used as the argument for the add_done_callback for the Task + //! created by checkAndRunCoroutine + void setTaskDoneCallback(const PythonQtObjectPtr& callable); + + //! Runs the given coroutine (via asyncio), returns a scheduled task if it object is a coroutine. + PythonQtObjectPtr checkAndRunCoroutine(const PythonQtObjectPtr& object); + + //! Creates a new asyncio.Future object + PythonQtObjectPtr createAsyncioFuture(); + //! get the suffixes that are used for shared libraries const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; } @@ -729,7 +742,7 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject { //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well) /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject, you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */ - void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0); + void registerClass(const QMetaObject* metaobject, const char* package = nullptr, PythonQtQObjectCreatorFunctionCB* wrapperCreator = nullptr, PythonQtShellSetInstanceWrapperCB* shell = nullptr, PyObject* module = nullptr, int typeSlots = 0); //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants //! (ownership of wrapper is passed to PythonQt) @@ -739,7 +752,7 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject { All slots that take a pointer to typeName as the first argument will be callable from Python on a variant object that contains such a type. */ - void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0); + void registerCPPClass(const char* typeName, const char* parentTypeName = nullptr, const char* package = nullptr, PythonQtQObjectCreatorFunctionCB* wrapperCreator = nullptr, PythonQtShellSetInstanceWrapperCB* shell = nullptr, PyObject* module = nullptr, int typeSlots = 0); //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes //! and it will register the classes when it first sees a pointer to such a derived class @@ -758,7 +771,7 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject { static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject); //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map - PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL); + PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = nullptr); //! get the class info for a meta object (if available) PythonQtClassInfo* getClassInfo(const QMetaObject* meta); @@ -797,13 +810,13 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject { //! get the dynamic meta object for the given wrapper. It will contain the signals/slots that have been added in Python const QMetaObject* getDynamicMetaObject(PythonQtInstanceWrapper* wrapper, const QMetaObject* prototypeMetaObject); - //! recursively creates the dynamic meta object chain down to the Qt class wrapper. + //! recursively creates the dynamic meta object chain down to the Qt class wrapper. const QMetaObject* setupDynamicMetaObjectChain(PythonQtClassWrapper* type, const QMetaObject* prototypeMetaObject); //! builds and returns the dynamic meta object for the given type, derived from prototypeMetaObject. const QMetaObject* buildDynamicMetaObject(PythonQtClassWrapper* type, const QMetaObject* prototypeMetaObject); - //! redirected from shell classes, tries to call the given meta call on the Python wrapper. + //! redirected from shell classes, tries to call the given meta call on the Python wrapper. int handleMetaCall(QObject* object, PythonQtInstanceWrapper* wrapper, QMetaObject::Call call, int id, void** args); //! calls the given method on Python function with same name. @@ -814,7 +827,7 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject { void setupSharedLibrarySuffixes(); //! create a new pythonqt class wrapper and place it in the pythonqt module - void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL); + void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = nullptr); //! get/create new package module (the returned object is a borrowed reference) PyObject* packageByName(const char* name); @@ -858,6 +871,10 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject { PythonQtObjectPtr _pySourceFileLoader; PythonQtObjectPtr _pySourcelessFileLoader; + PythonQtObjectPtr _pyEnsureFuture; + PythonQtObjectPtr _pyFutureClass; + + PythonQtObjectPtr _pyTaskDoneCallback; //! the cpp object wrapper factories QList _cppWrapperFactories; @@ -871,6 +888,7 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject { PythonQt::ProfilingCB* _profilingCB; PythonQtDebugAPI* _debugAPI; + PythonQtConfigAPI* _configAPI; int _initFlags; int _PythonQtObjectPtr_metaId; diff --git a/src/PythonQtBoolResult.cpp b/src/PythonQtBoolResult.cpp index 4d4ac185..57c45057 100644 --- a/src/PythonQtBoolResult.cpp +++ b/src/PythonQtBoolResult.cpp @@ -66,54 +66,54 @@ static int PythonQtBoolResult_nonzero(PyObject *obj) // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr static PyNumberMethods PythonQtBoolResult_as_number = { - 0, /* nb_add */ - 0, /* nb_subtract */ - 0, /* nb_multiply */ + nullptr, /* nb_add */ + nullptr, /* nb_subtract */ + nullptr, /* nb_multiply */ #ifndef PY3K - 0, /* nb_divide */ + nullptr, /* nb_divide */ #endif - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ + nullptr, /* nb_remainder */ + nullptr, /* nb_divmod */ + nullptr, /* nb_power */ + nullptr, /* nb_negative */ + nullptr, /* nb_positive */ + nullptr, /* nb_absolute */ PythonQtBoolResult_nonzero, /* nb_nonzero / nb_bool in Py3K */ - 0, /* nb_invert */ - 0, /* nb_lshift */ - 0, /* nb_rshift */ - 0, /* nb_and */ - 0, /* nb_xor */ - 0, /* nb_or */ -#ifndef PY3K - 0, /* nb_coerce */ + nullptr, /* nb_invert */ + nullptr, /* nb_lshift */ + nullptr, /* nb_rshift */ + nullptr, /* nb_and */ + nullptr, /* nb_xor */ + nullptr, /* nb_or */ +#ifndef PY3K + nullptr, /* nb_coerce */ #endif - 0, /* nb_int */ - 0, /* nb_long / nb_reserved in Py3K */ - 0, /* nb_float */ + nullptr, /* nb_int */ + nullptr, /* nb_long / nb_reserved in Py3K */ + nullptr, /* nb_float */ #ifndef PY3K - 0, /* nb_oct */ - 0, /* nb_hex */ + nullptr, /* nb_oct */ + nullptr, /* nb_hex */ #endif - 0, /* nb_inplace_add */ - 0, /* nb_inplace_subtract */ - 0, /* nb_inplace_multiply */ + nullptr, /* nb_inplace_add */ + nullptr, /* nb_inplace_subtract */ + nullptr, /* nb_inplace_multiply */ #ifndef PY3K - 0, /* nb_inplace_divide */ + nullptr, /* nb_inplace_divide */ #endif - 0, /* 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 */ + nullptr, /* nb_inplace_remainder */ + nullptr, /* nb_inplace_power */ + nullptr, /* nb_inplace_lshift */ + nullptr, /* nb_inplace_rshift */ + nullptr, /* nb_inplace_and */ + nullptr, /* nb_inplace_xor */ + nullptr, /* nb_inplace_or */ + nullptr, /* nb_floor_divide */ + nullptr, /* nb_true_divide */ + nullptr, /* nb_inplace_floor_divide */ + nullptr, /* nb_inplace_true_divide */ #ifdef PY3K - 0, /* nb_index in Py3K */ + nullptr, /* nb_index in Py3K */ #endif }; @@ -122,37 +122,37 @@ PyTypeObject PythonQtBoolResult_Type = { "BoolResult", sizeof(PythonQtBoolResultObject), 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, + nullptr, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + nullptr, /* tp_getattr */ + nullptr, /* tp_setattr */ + nullptr, (reprfunc)PythonQtBoolResult_repr, /* tp_repr */ &PythonQtBoolResult_as_number, /* 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 */ + nullptr, /* tp_as_sequence */ + nullptr, /* tp_as_mapping */ + nullptr, /* tp_hash */ + nullptr, /* tp_call */ + nullptr, /* tp_str */ + nullptr, /* tp_getattro */ + nullptr, /* tp_setattro */ + nullptr, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT,/* tp_flags */ - "Result object that is useful for bool* arguments", /* 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 */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ + "Result object that is useful for bool* arguments", /* tp_doc */ + nullptr, /* tp_traverse */ + nullptr, /* tp_clear */ + nullptr, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + nullptr, /* tp_iter */ + nullptr, /* tp_iternext */ + nullptr, /* tp_methods */ + nullptr, /* tp_members */ + nullptr, /* tp_getset */ + nullptr, /* tp_base */ + nullptr, /* tp_dict */ + nullptr, /* tp_descr_get */ + nullptr, /* tp_descr_set */ + 0, /* tp_dictoffset */ (initproc)&PythonQtBoolResult_init, /* tp_init */ }; diff --git a/src/PythonQtBoolResult.h b/src/PythonQtBoolResult.h index 11faad33..d459d6d7 100644 --- a/src/PythonQtBoolResult.h +++ b/src/PythonQtBoolResult.h @@ -51,10 +51,10 @@ extern PYTHONQT_EXPORT PyTypeObject PythonQtBoolResult_Type; #define PythonQtBoolResult_Check(op) (Py_TYPE(op) == &PythonQtBoolResult_Type) //! defines a python object that stores a single bool -typedef struct { +struct PythonQtBoolResultObject { PyObject_HEAD bool _value; -} PythonQtBoolResultObject; +}; #endif diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index aa929c50..b2013b8a 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -50,13 +50,13 @@ QHash PythonQtMethodInfo::_parameterTypeDict; PythonQtClassInfo::PythonQtClassInfo() { - _meta = NULL; - _constructors = NULL; - _destructor = NULL; - _decoratorProvider = NULL; - _decoratorProviderCB = NULL; - _pythonQtClassWrapper = NULL; - _shellSetInstanceWrapperCB = NULL; + _meta = nullptr; + _constructors = nullptr; + _destructor = nullptr; + _decoratorProvider = nullptr; + _decoratorProviderCB = nullptr; + _pythonQtClassWrapper = nullptr; + _shellSetInstanceWrapperCB = nullptr; _metaTypeId = -1; _typeSlots = 0; _isQObject = false; @@ -64,8 +64,8 @@ PythonQtClassInfo::PythonQtClassInfo() { _richCompareDetectionDone = false; _searchPolymorphicHandlerOnParent = true; _searchRefCountCB = true; - _refCallback = NULL; - _unrefCallback = NULL; + _refCallback = nullptr; + _unrefCallback = nullptr; } PythonQtClassInfo::~PythonQtClassInfo() @@ -131,11 +131,11 @@ bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName) if (!_meta) return false; bool found = false; - bool nameMapped = false; const char* attributeName = memberName; // look for properties int i = _meta->indexOfProperty(attributeName); #ifdef PYTHONQT_SUPPORT_NAME_PROPERTY + bool nameMapped = false; if (i==-1) { // try to map name to objectName if (qstrcmp(attributeName, "name")==0) { @@ -154,9 +154,11 @@ bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName) if (i!=-1) { PythonQtMemberInfo newInfo(_meta->property(i)); _cachedMembers.insert(attributeName, newInfo); +#ifdef PYTHONQT_SUPPORT_NAME_PROPERTY if (nameMapped) { _cachedMembers.insert(memberName, newInfo); } +#endif #ifdef PYTHONQT_DEBUG std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl; #endif @@ -256,7 +258,7 @@ PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(con bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName) { bool found = false; - PythonQtSlotInfo* tail = NULL; + PythonQtSlotInfo* tail = nullptr; // look for dynamic decorators in this class and in derived classes // (do this first to allow overloading of existing slots with generated wrappers, @@ -499,7 +501,6 @@ QStringList PythonQtClassInfo::memberList() decorator(); QStringList l; - QString h; // normal slots of QObject (or wrapper QObject) if (_meta) { int numMethods = _meta->methodCount(); @@ -553,7 +554,12 @@ QStringList PythonQtClassInfo::memberList() } } +#if QT_VERSION >= 0x060000 + QSet set(l.begin(), l.end()); + return set.values(); +#else return QSet::fromList(l).toList(); +#endif } const QByteArray& PythonQtClassInfo::className() const @@ -563,8 +569,8 @@ const QByteArray& PythonQtClassInfo::className() const void* PythonQtClassInfo::castTo(void* ptr, const char* classname) { - if (ptr==NULL) { - return NULL; + if (ptr==nullptr) { + return nullptr; } if (_wrappedClassName == classname) { return ptr; @@ -575,7 +581,7 @@ void* PythonQtClassInfo::castTo(void* ptr, const char* classname) return result; } } - return NULL; + return nullptr; } bool PythonQtClassInfo::inherits(const char* name) @@ -768,7 +774,7 @@ void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, const char** res } } } - return NULL; + return nullptr; } void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo) @@ -795,14 +801,14 @@ void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resul if (parent->_parentClasses.count()>0) { parent = parent->_parentClasses[0]._parent; } else { - parent = NULL; + parent = nullptr; } } } } // we only do downcasting on the base object, not on the whole inheritance tree... - void* resultPtr = NULL; + void* resultPtr = nullptr; if (!_polymorphicHandlers.isEmpty()) { Q_FOREACH(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) { resultPtr = (*cb)(ptr, &className); @@ -837,13 +843,13 @@ PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtCla if (info) { return info->findEnumWrapper(enumName); } else{ - return NULL; + return nullptr; } } if (localScope) { return localScope->findEnumWrapper(name); } else { - return NULL; + return nullptr; } } @@ -892,13 +898,13 @@ PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) { PyObject* p = info._parent->findEnumWrapper(name); if (p) return p; } - return NULL; + return nullptr; } void PythonQtClassInfo::setDecoratorProvider( PythonQtQObjectCreatorFunctionCB* cb ) { _decoratorProviderCB = cb; - _decoratorProvider = NULL; + _decoratorProvider = nullptr; _enumsCreated = false; } @@ -959,7 +965,7 @@ PyObject* PythonQtClassInfo::copyObject( void* cppObject ) std::cerr << "PythonQt: Can't create a copy of '" << info->_wrappedClassName.constData() << "', either use qRegisterMetaType() or add a copy constructor to the decorator/wrapper." << std::endl; } } - return NULL; + return nullptr; } PythonQtSlotInfo* PythonQtClassInfo::getCopyConstructor() @@ -973,7 +979,7 @@ PythonQtSlotInfo* PythonQtClassInfo::getCopyConstructor() } construc = construc->nextInfo(); } - return NULL; + return nullptr; } void PythonQtClassInfo::setReferenceCounting( PythonQtVoidPtrCB* refCB, PythonQtVoidPtrCB* unrefCB ) @@ -1019,7 +1025,7 @@ PyObject* PythonQtClassInfo::getPythonTypeForProperty( const QString& name ) if (classInfo) { return classInfo->pythonQtClassWrapper(); } else { - return NULL; + return nullptr; } } @@ -1042,7 +1048,7 @@ PythonQtClassInfo* PythonQtClassInfo::getClassInfoForProperty( const QString& na PythonQtClassInfo* classInfo = PythonQt::priv()->getClassInfo(typeName); return classInfo; } - return NULL; + return nullptr; } bool PythonQtClassInfo::supportsRichCompare() @@ -1074,33 +1080,32 @@ bool PythonQtClassInfo::supportsRichCompare() //------------------------------------------------------------------------- -PythonQtMemberInfo::PythonQtMemberInfo( PythonQtSlotInfo* info ) +PythonQtMemberInfo::PythonQtMemberInfo( PythonQtSlotInfo* info ) : _slot(info) { if (info->metaMethod()->methodType() == QMetaMethod::Signal) { _type = Signal; } else { _type = Slot; } - _slot = info; - _enumValue = NULL; - _pythonType = NULL; + _enumValue = nullptr; + _pythonType = nullptr; } PythonQtMemberInfo::PythonQtMemberInfo( const PythonQtObjectPtr& enumValue ) { _type = EnumValue; - _slot = NULL; + _slot = nullptr; _enumValue = enumValue; - _pythonType = NULL; + _pythonType = nullptr; } PythonQtMemberInfo::PythonQtMemberInfo( const QMetaProperty& prop ) { _type = Property; - _slot = NULL; + _slot = nullptr; _property = prop; - _enumValue = NULL; - _pythonType = NULL; + _enumValue = nullptr; + _pythonType = nullptr; } PythonQtDynamicClassInfo::~PythonQtDynamicClassInfo() diff --git a/src/PythonQtClassInfo.h b/src/PythonQtClassInfo.h index 7e8638bc..5e3faf54 100644 --- a/src/PythonQtClassInfo.h +++ b/src/PythonQtClassInfo.h @@ -46,7 +46,7 @@ class PythonQtClassInfo; struct PythonQtDynamicClassInfo { - PythonQtDynamicClassInfo() { _dynamicMetaObject = NULL; _classInfo = NULL; } + PythonQtDynamicClassInfo() { _dynamicMetaObject = nullptr; _classInfo = nullptr; } ~PythonQtDynamicClassInfo(); const QMetaObject* _dynamicMetaObject; @@ -55,11 +55,11 @@ struct PythonQtDynamicClassInfo struct PythonQtMemberInfo { enum Type { - Invalid, Slot, Signal, EnumValue, EnumWrapper, Property, NestedClass, NotFound + Invalid, Slot, Signal, EnumValue, EnumWrapper, Property, NestedClass, NotFound }; - PythonQtMemberInfo():_type(Invalid),_slot(NULL),_pythonType(NULL),_enumValue(0) { } - + PythonQtMemberInfo():_type(Invalid),_slot(nullptr),_pythonType(nullptr),_enumValue(nullptr) { } + PythonQtMemberInfo(PythonQtSlotInfo* info); PythonQtMemberInfo(const PythonQtObjectPtr& enumValue); @@ -110,7 +110,7 @@ class PYTHONQT_EXPORT PythonQtClassInfo { //! get access to the constructor slot (which may be overloaded if there are multiple constructors) PythonQtSlotInfo* constructors(); - + //! get access to the destructor slot PythonQtSlotInfo* destructor(); @@ -146,7 +146,7 @@ class PYTHONQT_EXPORT PythonQtClassInfo { //! returns if this class inherits from the given classname bool inherits(const char* classname); - + //! returns if this class inherits from the given classinfo bool inherits(PythonQtClassInfo* info); @@ -167,12 +167,12 @@ class PYTHONQT_EXPORT PythonQtClassInfo { //! get the meta type id of this class (only valid for isCPPWrapper() == true) int metaTypeId() { return _metaTypeId; } - //! set an additional decorator provider that offers additional decorator slots for this class + //! set an additional decorator provider that offers additional decorator slots for this class void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb); //! get the decorator qobject instance QObject* decorator(); - + //! add the parent class info of a CPP object void addParentClass(const ParentClassInfo& info) { _parentClasses.append(info); } @@ -186,7 +186,7 @@ class PYTHONQT_EXPORT PythonQtClassInfo { void setShellSetInstanceWrapperCB(PythonQtShellSetInstanceWrapperCB* cb) { _shellSetInstanceWrapperCB = cb; } - + //! get the shell set instance wrapper cb PythonQtShellSetInstanceWrapperCB* shellSetInstanceWrapperCB() { return _shellSetInstanceWrapperCB; @@ -199,7 +199,7 @@ class PYTHONQT_EXPORT PythonQtClassInfo { void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo); //! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum - static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = NULL); + static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = nullptr); //! clear all members that where cached as "NotFound" void clearNotFoundCachedMembers(); @@ -262,7 +262,7 @@ class PYTHONQT_EXPORT PythonQtClassInfo { PythonQtSlotInfo* findDecoratorSlots(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash& memberCache, int upcastingOffset); int findCharOffset(const char* sigStart, char someChar); - + QHash _cachedMembers; PythonQtSlotInfo* _constructors; @@ -286,11 +286,11 @@ class PYTHONQT_EXPORT PythonQtClassInfo { QObject* _decoratorProvider; PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB; - + PyObject* _pythonQtClassWrapper; - + PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB; - + int _metaTypeId; int _typeSlots; @@ -299,7 +299,7 @@ class PYTHONQT_EXPORT PythonQtClassInfo { bool _richCompareDetectionDone; bool _searchPolymorphicHandlerOnParent; bool _searchRefCountCB; - + }; //--------------------------------------------------------------- diff --git a/src/PythonQtClassWrapper.cpp b/src/PythonQtClassWrapper.cpp index 6a5ddccc..ad8f5064 100644 --- a/src/PythonQtClassWrapper.cpp +++ b/src/PythonQtClassWrapper.cpp @@ -51,34 +51,34 @@ static PyObject* PythonQtInstanceWrapper_invert(PythonQtInstanceWrapper* wrapper) { - PyObject* result = NULL; + PyObject* result = nullptr; static QByteArray memberName = "__invert__"; PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName); if (opSlot._type == PythonQtMemberInfo::Slot) { - result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr); + result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, nullptr, nullptr, wrapper->_wrappedPtr); } return result; } static PyObject* PythonQtInstanceWrapper_negative(PythonQtInstanceWrapper* wrapper) { - PyObject* result = NULL; + PyObject* result = nullptr; static QByteArray memberName = "__sub__"; PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName); if (opSlot._type == PythonQtMemberInfo::Slot) { - result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr); + result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, nullptr, nullptr, wrapper->_wrappedPtr); } return result; } static int PythonQtInstanceWrapper_nonzero(PythonQtInstanceWrapper* wrapper) { - int result = (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1; + int result = (wrapper->_wrappedPtr == nullptr && wrapper->_obj == nullptr)?0:1; if (result) { static QByteArray memberName = "__nonzero__"; PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName); if (opSlot._type == PythonQtMemberInfo::Slot) { - PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr); + PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, nullptr, nullptr, wrapper->_wrappedPtr); if (resultObj == Py_False) { result = 0; } @@ -91,11 +91,11 @@ static int PythonQtInstanceWrapper_nonzero(PythonQtInstanceWrapper* wrapper) static Py_ssize_t PythonQtInstanceWrapper_length(PythonQtInstanceWrapper* wrapper) { qint64 result = -1; - if (wrapper->_wrappedPtr != NULL || wrapper->_obj != NULL) { + if (wrapper->_wrappedPtr != nullptr || wrapper->_obj != nullptr) { static QByteArray memberName = "__len__"; PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName); if (opSlot._type == PythonQtMemberInfo::Slot) { - PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr); + PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, nullptr, nullptr, wrapper->_wrappedPtr); bool ok; result = PythonQtConv::PyObjGetLongLong(resultObj, false, ok); if (!ok) { @@ -110,14 +110,11 @@ static Py_ssize_t PythonQtInstanceWrapper_length(PythonQtInstanceWrapper* wrappe static int PythonQtInstanceWrapper_setitem(PyObject* self, PyObject* index, PyObject* value) { PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self; - PythonQtMemberInfo opSlot; - bool isSetItem = false; - if (value) { - isSetItem = true; - opSlot = wrapper->classInfo()->member("__setitem__"); - } else { - opSlot = wrapper->classInfo()->member("__delitem__"); - } + bool isSetItem = value; + PythonQtMemberInfo opSlot = isSetItem ? + wrapper->classInfo()->member("__setitem__") + : wrapper->classInfo()->member("__delitem__"); + if (opSlot._type == PythonQtMemberInfo::Slot) { PyObject* args = PyTuple_New(isSetItem?2:1); Py_INCREF(index); @@ -126,7 +123,7 @@ static int PythonQtInstanceWrapper_setitem(PyObject* self, PyObject* index, PyOb Py_INCREF(value); PyTuple_SET_ITEM(args, 1, value); } - PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr); + PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, nullptr, wrapper->_wrappedPtr); if (result) { Py_DECREF(result); } @@ -144,16 +141,16 @@ static PyObject* PythonQtInstanceWrapper_binaryfunc(PyObject* self, PyObject* ot if (!PyObject_TypeCheck(self, &PythonQtInstanceWrapper_Type)) { QString error = "Unsupported operation " + opName + "(" + self->ob_type->tp_name + ", " + other->ob_type->tp_name + ")"; PyErr_SetString(PyExc_ArithmeticError, QStringToPythonCharPointer(error)); - return NULL; + return nullptr; } PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self; - PyObject* result = NULL; + PyObject* result = nullptr; PythonQtMemberInfo opSlot = wrapper->classInfo()->member(opName); if (opSlot._type == PythonQtMemberInfo::Slot) { PyObject* args = PyTuple_New(1); Py_INCREF(other); PyTuple_SET_ITEM(args, 0, other); - result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr); + result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, nullptr, wrapper->_wrappedPtr); Py_DECREF(args); if (!result && !fallbackOpName.isEmpty()) { // try fallback if we did not get a result @@ -174,13 +171,13 @@ static PyObject* PythonQtInstanceWrapper_mul(PyObject* self, PyObject* other) other = tmp; } PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self; - PyObject* result = NULL; + PyObject* result = nullptr; PythonQtMemberInfo opSlot = wrapper->classInfo()->member("__mul__"); if (opSlot._type == PythonQtMemberInfo::Slot) { PyObject* args = PyTuple_New(1); Py_INCREF(other); PyTuple_SET_ITEM(args, 0, other); - result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr); + result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, nullptr, wrapper->_wrappedPtr); Py_DECREF(args); } return result; @@ -343,7 +340,7 @@ static int PythonQtClassWrapper_init(PythonQtClassWrapper* self, PyObject* args, if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) { return -1; } - self->_dynamicClassInfo = NULL; + self->_dynamicClassInfo = nullptr; // if we have no CPP class information, try our base class if (!self->classInfo()) { @@ -394,7 +391,7 @@ static PyObject *PythonQtClassWrapper_help(PythonQtClassWrapper* type) PyObject *PythonQtClassWrapper_delete(PythonQtClassWrapper *type, PyObject *args) { - Q_UNUSED(type); + Q_UNUSED(type) Py_ssize_t argc = PyTuple_Size(args); if (argc>0) { @@ -403,42 +400,42 @@ PyObject *PythonQtClassWrapper_delete(PythonQtClassWrapper *type, PyObject *args return PythonQtInstanceWrapper_delete((PythonQtInstanceWrapper*)self); } } - return NULL; + return nullptr; } PyObject *PythonQtClassWrapper_inherits(PythonQtClassWrapper *type, PyObject *args) { - Q_UNUSED(type); - PythonQtInstanceWrapper* wrapper = NULL; - char *name = NULL; + Q_UNUSED(type) + PythonQtInstanceWrapper* wrapper = nullptr; + char *name = nullptr; if (!PyArg_ParseTuple(args, "O!s:PythonQtClassWrapper.inherits",&PythonQtInstanceWrapper_Type, &wrapper, &name)) { - return NULL; + return nullptr; } return PythonQtConv::GetPyBool(wrapper->classInfo()->inherits(name)); } static PyMethodDef PythonQtClassWrapper_methods[] = { - {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS, + {"className", reinterpret_cast(reinterpret_cast(PythonQtClassWrapper_classname)), METH_NOARGS, "Return the classname of the object" }, - {"inherits", (PyCFunction)PythonQtClassWrapper_inherits, METH_VARARGS, + {"inherits", reinterpret_cast(reinterpret_cast(PythonQtClassWrapper_inherits)), METH_VARARGS, "Returns if the class inherits or is of given type name" }, - {"help", (PyCFunction)PythonQtClassWrapper_help, METH_NOARGS, + {"help", reinterpret_cast(reinterpret_cast(PythonQtClassWrapper_help)), METH_NOARGS, "Shows the help of available methods for this class" }, - {"delete", (PyCFunction)PythonQtClassWrapper_delete, METH_VARARGS, + {"delete", reinterpret_cast(reinterpret_cast(PythonQtClassWrapper_delete)), METH_VARARGS, "Deletes the given C++ object" }, - {NULL, NULL, 0 , NULL} /* Sentinel */ + {nullptr, nullptr, 0 , nullptr} /* Sentinel */ }; static PyObject* PythonQtClassWrapper_getDummyInstanceForProperty(PythonQtClassWrapper* wrapper, const QString& property) { PythonQtClassInfo* info = wrapper->classInfo()->getClassInfoForProperty(property); if (info) { - return (PyObject*)PythonQt::priv()->createNewPythonQtInstanceWrapper(NULL, info); + return (PyObject*)PythonQt::priv()->createNewPythonQtInstanceWrapper(nullptr, info); } Py_INCREF(Py_None); return Py_None; @@ -449,8 +446,8 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) const char *attributeName; PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj; - if ((attributeName = PyString_AsString(name)) == NULL) { - return NULL; + if ((attributeName = PyString_AsString(name)) == nullptr) { + return nullptr; } if (obj == (PyObject*)&PythonQtInstanceWrapper_Type) { // if we are called as PythonQtInstanceWrapper_Type, we need to get the properties from the type... @@ -465,10 +462,16 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) return objectDict; } PyObject* dict = PyDict_New(); - - QSet completeSet = QSet::fromList(wrapper->classInfo()->memberList()); - completeSet.unite(QSet::fromList(wrapper->classInfo()->propertyList())); + auto members = wrapper->classInfo()->memberList(); + auto properties = wrapper->classInfo()->propertyList(); +#if QT_VERSION >= 0x060000 + QSet completeSet(members.begin(), members.end()); + completeSet.unite(QSet(properties.begin(), properties.end())); +#else + QSet completeSet = QSet::fromList(members); + completeSet.unite(QSet::fromList(properties)); +#endif Q_FOREACH (QString name, completeSet) { if (name.startsWith("py_")) { // do not expose internal slots @@ -491,7 +494,7 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) PyDict_SetItemString(dict, "__init__", func); Py_DECREF(func); } - for (int i = 0; PythonQtClassWrapper_methods[i].ml_name != NULL; i++) { + for (int i = 0; PythonQtClassWrapper_methods[i].ml_name != nullptr; i++) { PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj); PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func); Py_DECREF(func); @@ -527,15 +530,15 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) PythonQtMemberInfo qualifiedMember = wrapper->classInfo()->member(qualifiedMemberName); if (qualifiedMember._type == PythonQtMemberInfo::Slot) { // return the qualified member, so that virtual calls on classes call the qualified member - return PythonQtSlotFunction_New(qualifiedMember._slot, obj, NULL); + return PythonQtSlotFunction_New(qualifiedMember._slot, obj, nullptr); } else { // we return all slots, even the instance slots, since they are callable as unbound slots with self argument - return PythonQtSlotFunction_New(member._slot, obj, NULL); + return PythonQtSlotFunction_New(member._slot, obj, nullptr); } } else if (member._type == PythonQtMemberInfo::Signal) { // we return all signals, even the instance signals, since they are callable as unbound signals with self argument - return PythonQtSignalFunction_New(member._slot, obj, NULL); + return PythonQtSignalFunction_New(member._slot, obj, nullptr); } else if (member._type == PythonQtMemberInfo::Property) { PyObject* dummy = PythonQtClassWrapper_getDummyInstanceForProperty(wrapper, attributeName); return dummy; @@ -560,7 +563,7 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'"; PyErr_SetString(PyExc_AttributeError, QStringToPythonConstCharPointer(error)); - return NULL; + return nullptr; } static int PythonQtClassWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value) @@ -593,49 +596,49 @@ static PyObject * PythonQtClassWrapper_repr(PyObject * obj) */ PyTypeObject PythonQtClassWrapper_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "PythonQt.PythonQtClassWrapper", /*tp_name*/ - sizeof(PythonQtClassWrapper), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, //PythonQtClassWrapper_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - PythonQtClassWrapper_getattro, /*tp_getattro*/ - PythonQtClassWrapper_setattro, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + PyVarObject_HEAD_INIT(nullptr, 0) + "PythonQt.PythonQtClassWrapper", /*tp_name*/ + sizeof(PythonQtClassWrapper), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + nullptr, /*tp_dealloc*/ + 0, /*tp_vectorcall_offset*/ + nullptr, /*tp_getattr*/ + nullptr, /*tp_setattr*/ + nullptr, /*tp_compare*/ + nullptr, //PythonQtClassWrapper_repr, /*tp_repr*/ + nullptr, /*tp_as_number*/ + nullptr, /*tp_as_sequence*/ + nullptr, /*tp_as_mapping*/ + nullptr, /*tp_hash */ + nullptr, /*tp_call*/ + nullptr, /*tp_str*/ + PythonQtClassWrapper_getattro, /*tp_getattro*/ + PythonQtClassWrapper_setattro, /*tp_setattro*/ + nullptr, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ + nullptr, /* tp_doc */ + nullptr, /* tp_traverse */ + nullptr, /* tp_clear */ + nullptr, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + nullptr, /* tp_iter */ + nullptr, /* tp_iternext */ #ifdef PY3K - PythonQtClassWrapper_methods, /* tp_methods */ + PythonQtClassWrapper_methods, /* tp_methods */ #else - 0, /* tp_methods */ + nullptr, /* tp_methods */ #endif - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)PythonQtClassWrapper_init, /* tp_init */ - PythonQtClassWrapper_alloc, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ + nullptr, /* tp_members */ + nullptr, /* tp_getset */ + nullptr, /* tp_base */ + nullptr, /* tp_dict */ + nullptr, /* tp_descr_get */ + nullptr, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PythonQtClassWrapper_init, /* tp_init */ + PythonQtClassWrapper_alloc, /* tp_alloc */ + nullptr, /* tp_new */ + nullptr, /* tp_free */ }; //------------------------------------------------------- diff --git a/src/PythonQtClassWrapper.h b/src/PythonQtClassWrapper.h index 892dfaa8..53c1d3ca 100644 --- a/src/PythonQtClassWrapper.h +++ b/src/PythonQtClassWrapper.h @@ -49,7 +49,6 @@ #include "structmember.h" #include "methodobject.h" #include "compile.h" -#include "eval.h" #include class PythonQtClassInfo; @@ -63,7 +62,7 @@ struct PythonQtDynamicClassInfo; //! a Python wrapper object for PythonQt wrapped classes //! which inherits from the Python type object to allow //! deriving of wrapped CPP classes from Python. -typedef struct { +struct PythonQtClassWrapper { PyHeapTypeObject _base; //! the additional class information that PythonQt stores for the CPP class @@ -73,8 +72,7 @@ typedef struct { PythonQtClassInfo* classInfo() { return _classInfo; } PythonQtDynamicClassInfo* _dynamicClassInfo; - -} PythonQtClassWrapper; +}; //--------------------------------------------------------------- diff --git a/src/PythonQtConversion.cpp b/src/PythonQtConversion.cpp index 523b3fec..f47506fd 100644 --- a/src/PythonQtConversion.cpp +++ b/src/PythonQtConversion.cpp @@ -51,7 +51,7 @@ QHash PythonQtConv::_metaTypeToPythonConverters; QHash PythonQtConv::_pythonToMetaTypeConverters; -PythonQtConvertPythonSequenceToQVariantListCB* PythonQtConv::_pythonSequenceToQVariantListCB = NULL; +PythonQtConvertPythonSequenceToQVariantListCB* PythonQtConv::_pythonSequenceToQVariantListCB = nullptr; PyObject* PythonQtConv::GetPyBool(bool val) { @@ -87,7 +87,7 @@ PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::Paramet } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) && info.isQList && (info.innerNamePointerCount == 1)) { // it is a QList template: - QList* listPtr = NULL; + QList* listPtr = nullptr; if (info.pointerCount == 1) { listPtr = *((QList**)data); } else if (info.pointerCount == 0) { @@ -96,7 +96,7 @@ PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::Paramet if (listPtr) { return ConvertQListOfPointerTypeToPythonList(listPtr, info); } else { - return NULL; + return nullptr; } } @@ -221,11 +221,11 @@ PyObject* PythonQtConv::convertQtValueToPythonInternal(int type, const void* dat } void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info, PythonQtArgumentFrame* frame) { - void* ptr = NULL; + void* ptr = nullptr; if (info.pointerCount>1) { - return NULL; + return nullptr; } else if (info.pointerCount==1) { - PythonQtArgumentFrame_ADD_VALUE(frame, void*, NULL, ptr); + PythonQtArgumentFrame_ADD_VALUE(frame, void*, nullptr, ptr); } else if (info.enumWrapper) { // create enum return value PythonQtArgumentFrame_ADD_VALUE(frame, long, 0, ptr); @@ -255,14 +255,14 @@ PyObject* PythonQtConv::convertQtValueToPythonInternal(int type, const void* dat // check if we have a QList of pointers, which we can circumvent with a QList if (info.isQList && (info.innerNamePointerCount == 1)) { static int id = QMetaType::type("QList"); - PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, QVariant::Type(id), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID(frame, id, ptr); // return the constData pointer that will be filled with the result value later on ptr = (void*)((QVariant*)ptr)->constData(); } if (!ptr && info.typeId != PythonQtMethodInfo::Unknown) { // everything else is stored in a QVariant, if we know the meta type... - PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, QVariant::Type(info.typeId), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID(frame, info.typeId, ptr); // return the constData pointer that will be filled with the result value later on ptr = (void*)((QVariant*)ptr)->constData(); } @@ -283,7 +283,7 @@ PyObject* PythonQtConv::convertQtValueToPythonInternal(int type, const void* dat if (object) { // if we can be upcasted to the given name, we pass the casted pointer in: object = wrapper->classInfo()->castTo(object, className); - ok = object!=NULL; + ok = object!=nullptr; } else { // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr ok = wrapper->classInfo()->inherits(className); @@ -299,9 +299,9 @@ void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, vo static int brushId = QMetaType::type("QBrush"); static int cursorId = QMetaType::type("QCursor"); static int colorId = QMetaType::type("QColor"); - static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL); + static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", nullptr); if (typeId == cursorId) { - static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL); + static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", nullptr); if ((PyObject*)obj->ob_type == qtCursorShapeEnum) { Qt::CursorShape val = (Qt::CursorShape)PyInt_AsLong(obj); if (!ptr) { @@ -361,13 +361,13 @@ void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, vo return ptr; } } - return NULL; + return nullptr; } void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject, PythonQtArgumentFrame* frame) { bool ok = false; - void* ptr = NULL; + void* ptr = nullptr; // autoconversion of QPen/QBrush/QCursor/QColor from different type if (info.pointerCount==0 && !strict) { @@ -429,8 +429,8 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i QByteArray bytes; bytes = str.toUtf8(); if (ok) { - void* ptr2 = NULL; - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(NULL,frame, QVariant(bytes), ptr2); + void* ptr2 = nullptr; + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr,frame, QVariant(bytes), ptr2); PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr); } } @@ -441,8 +441,8 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i // result value is not useable in Python), or if all these APIs need to be wrapped manually/differently, like PyQt/PySide do. QString str = PyObjGetString(obj, strict, ok); if (ok) { - void* ptr2 = NULL; - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(NULL,frame, QVariant(str), ptr2); + void* ptr2 = nullptr; + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr,frame, QVariant(str), ptr2); PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, void*, (void*)((QVariant*)ptr2)->constData(), ptr); } } else if (info.name == "PyObject") { @@ -450,7 +450,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, void*, obj, ptr); } else if (obj == Py_None) { // None is treated as a NULL ptr - PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, void*, NULL, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, void*, nullptr, ptr); } else { void* foreignWrapper = PythonQt::priv()->unwrapForeignWrapper(info.name, obj); if (foreignWrapper) { @@ -461,7 +461,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i bool ok; int value = PyObjGetInt(obj, true, ok); if (ok && value==0) { - PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, void*, NULL, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, void*, nullptr, ptr); } } } @@ -503,7 +503,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i break; case QMetaType::Long: { - qint64 val = PyObjGetLongLong(obj, strict, ok); + auto val = PyObjGetLongLong(obj, strict, ok); if (ok && (val >= LONG_MIN && val <= LONG_MAX)) { PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, long, val, ptr); } @@ -511,8 +511,8 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i break; case QMetaType::ULong: { - qint64 val = (unsigned long)PyObjGetLongLong(obj, strict, ok); - if (ok && (val >= 0 && val <= ULONG_MAX)) { + auto val = PyObjGetULongLong(obj, strict, ok); + if (ok && val <= ULONG_MAX) { PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, unsigned long, val, ptr); } } @@ -535,7 +535,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i break; case QMetaType::UInt: { - quint64 val = PyObjGetLongLong(obj, strict, ok); + auto val = PyObjGetLongLong(obj, strict, ok); if (ok && (val >= 0 && val <= UINT_MAX)) { PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, unsigned int, val, ptr); } @@ -627,7 +627,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { // check for enum case if (info.enumWrapper) { - unsigned int val; + unsigned int val = 0; ok = false; if ((PyObject*)obj->ob_type == info.enumWrapper) { // we have a exact enum type match: @@ -642,7 +642,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, unsigned int, val, ptr); return ptr; } else { - return NULL; + return nullptr; } } @@ -651,7 +651,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i if (info.isQList && (info.innerNamePointerCount == 1)) { static int id = QMetaType::type("QList"); if (!alreadyAllocatedCPPObject) { - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, QVariant::Type(id), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID_IF_NEEDED(alreadyAllocatedCPPObject, frame, id, ptr); ptr = (void*)((QVariant*)ptr)->constData(); } else { ptr = alreadyAllocatedCPPObject; @@ -660,7 +660,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i if (ok) { return ptr; } else { - return NULL; + return nullptr; } } } @@ -672,7 +672,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i if (converter) { if (!alreadyAllocatedCPPObject) { // create a new empty variant of concrete type: - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, QVariant::Type(info.typeId), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID_IF_NEEDED(alreadyAllocatedCPPObject,frame, info.typeId, ptr); ptr = (void*)((QVariant*)ptr)->constData(); } else { ptr = alreadyAllocatedCPPObject; @@ -682,7 +682,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i if (ok) { return ptr; } else { - return NULL; + return nullptr; } } } @@ -967,6 +967,17 @@ void PythonQtConv::pythonToMapVariant(PyObject* val, QVariant& result) } } +namespace +{ + QVariant variantFromType(int typeId, const void *copy) + { +#if QT_VERSION >= 0x060000 + return QVariant(QMetaType(typeId), copy); +#else + return QVariant(typeId, copy); +#endif + } +} QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) { @@ -979,7 +990,9 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) #endif ) { // no special type requested - if (PyBytes_Check(val)) { + if (val == nullptr) { + type = QVariant::Invalid; + } else if (PyBytes_Check(val)) { #ifdef PY3K // In Python 3, it is a ByteArray type = QVariant::ByteArray; @@ -1013,17 +1026,17 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) if (wrap->classInfo()->isCPPWrapper()) { if (wrap->classInfo()->metaTypeId()>0) { // construct a new variant from the C++ object if it has a meta type (this will COPY the object!) - v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr); + v = variantFromType(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr); } else { // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass // the pointer here... // is this worth anything? we loose the knowledge of the cpp object type - v = qVariantFromValue(wrap->_wrappedPtr); + v = QVariant::fromValue(wrap->_wrappedPtr); } } else { // this gives us a QObject pointer QObject* myObject = wrap->_obj; - v = qVariantFromValue(myObject); + v = QVariant::fromValue(myObject); } return v; } else if (val == Py_None) { @@ -1066,62 +1079,62 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) { double d = PyObjGetDouble(val,false,ok); if (ok) v = QVariant(d); - break; } + break; case QMetaType::Float: { float d = (float) PyObjGetDouble(val,false,ok); - if (ok) v = qVariantFromValue(d); - break; + if (ok) v = QVariant::fromValue(d); } + break; case QMetaType::Long: { long d = (long) PyObjGetLongLong(val,false,ok); - if (ok) v = qVariantFromValue(d); - break; + if (ok) v = QVariant::fromValue(d); } + break; case QMetaType::ULong: { unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok); - if (ok) v = qVariantFromValue(d); - break; + if (ok) v = QVariant::fromValue(d); } + break; case QMetaType::LongLong: { qint64 d = PyObjGetLongLong(val, false, ok); - if (ok) v = qVariantFromValue(d); + if (ok) v = QVariant::fromValue(d); } break; case QMetaType::ULongLong: { quint64 d = PyObjGetULongLong(val, false, ok); - if (ok) v = qVariantFromValue(d); + if (ok) v = QVariant::fromValue(d); } break; case QMetaType::Short: { short d = (short) PyObjGetInt(val,false,ok); - if (ok) v = qVariantFromValue(d); - break; + if (ok) v = QVariant::fromValue(d); } + break; case QMetaType::UShort: { unsigned short d = (unsigned short) PyObjGetInt(val,false,ok); - if (ok) v = qVariantFromValue(d); - break; + if (ok) v = QVariant::fromValue(d); } + break; case QMetaType::Char: { char d = (char) PyObjGetInt(val,false,ok); - if (ok) v = qVariantFromValue(d); - break; + if (ok) v = QVariant::fromValue(d); } + break; case QMetaType::UChar: { unsigned char d = (unsigned char) PyObjGetInt(val,false,ok); - if (ok) v = qVariantFromValue(d); - break; + if (ok) v = QVariant::fromValue(d); } + break; case QVariant::ByteArray: { @@ -1131,7 +1144,9 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) #else v = QVariant(PyObjGetString(val, false, ok)); #endif + break; } + break; case QVariant::String: { bool ok; @@ -1186,7 +1201,7 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val; if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) { // construct a new variant from the C++ object if it has the same meta type - v = QVariant(type, wrap->_wrappedPtr); + v = variantFromType(type, wrap->_wrappedPtr); } else { // Try to convert the object to a QVariant based on the typeName bool ok; @@ -1199,20 +1214,20 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) void* object = castWrapperTo(wrap, typeName, ok); if (ok) { if (isPtr) { - v = QVariant(type, &object); + v = variantFromType(type, &object); } else { - v = QVariant(type, object); + v = variantFromType(type, object); } } } - } else if (type >= QVariant::UserType) { + } else if (static_cast(type) >= QVariant::UserType) { // not an instance wrapper, but there might be other converters // Maybe we have a special converter that is registered for that type: PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(type); if (converter) { // allocate a default object of the needed type: - v = QVariant(type, (const void*)NULL); + v = variantFromType(type, (const void*)nullptr); // now call the converter, passing the internal object of the variant ok = (*converter)(val, (void*)v.constData(), type, true); if (!ok) { @@ -1223,7 +1238,7 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) const PythonQtMethodInfo::ParameterInfo& info = PythonQtMethodInfo::getParameterInfoForMetaType(type); if (info.isQList && (info.innerNamePointerCount == 1)) { // allocate a default object of the needed type: - v = QVariant(type, (const void*)NULL); + v = variantFromType(type, (const void*)nullptr); ok = ConvertPythonListToQListOfPointerType(val, (QList*)v.constData(), info, true); if (!ok) { v = QVariant(); @@ -1240,7 +1255,7 @@ PyObject* PythonQtConv::QStringToPyObject(const QString& str) if (str.isNull()) { return PyString_FromString(""); } else { - return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL); + return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, nullptr, nullptr); } } @@ -1275,7 +1290,7 @@ PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v) Py_INCREF(Py_None); return Py_None; } - PyObject* obj = NULL; + PyObject* obj = nullptr; if (v.userType() >= QMetaType::User && !PythonQt::priv()->isPythonQtAnyObjectPtrMetaId(v.userType())) { // try the slower way, which supports more conversions, e.g. QList const PythonQtMethodInfo::ParameterInfo& info = PythonQtMethodInfo::getParameterInfoForMetaType(v.userType()); @@ -1456,10 +1471,9 @@ QString PythonQtConv::CPPObjectToString(int type, const void* data) { //TODO: add more printing for other variant types default: // this creates a copy, but that should not be expensive for typical simple variants - // (but we do not want to do this for our won user types! + // (but we do not want to do this for our own user types!) if (type>0 && type < (int)QVariant::UserType) { - QVariant v(type, data); - r = v.toString(); + r = variantFromType(type, data).toString(); } } return r; @@ -1480,10 +1494,12 @@ PyObject* PythonQtConv::createCopyFromMetaType( int type, const void* data ) return (PyObject*)wrap; } +#if QT_VERSION < 0x060000 PyObject* PythonQtConv::convertFromStringRef(const void* inObject, int /*metaTypeId*/) { return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString()); } +#endif QByteArray PythonQtConv::getCPPTypeName(PyObject* type) { @@ -1514,7 +1530,7 @@ QByteArray PythonQtConv::getCPPTypeName(PyObject* type) } else if (isStringType(typeObject)) { result = "QString"; } else { - result = "PyObject*"; + result = "PythonQtSafeObjectPtr"; } } } else if (type == Py_None) { @@ -1595,4 +1611,4 @@ PyObject* PythonQtConv::convertFromPythonQtSafeObjectPtr(const void* /* PythonQt // extra ref count, since we are supposed to return a newly refcounted object Py_XINCREF(obj); return obj; -} \ No newline at end of file +} diff --git a/src/PythonQtConversion.h b/src/PythonQtConversion.h index 9cf99755..7876b652 100644 --- a/src/PythonQtConversion.h +++ b/src/PythonQtConversion.h @@ -109,7 +109,7 @@ class PYTHONQT_EXPORT PythonQtConv { static PyObject* ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data); //! convert python object to Qt (according to the given parameter) and if the conversion should be strict (classInfo is currently not used anymore) - static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* classInfo, void* alreadyAllocatedCPPObject, PythonQtArgumentFrame* frame = NULL); + static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* classInfo, void* alreadyAllocatedCPPObject, PythonQtArgumentFrame* frame = nullptr); //! creates a data storage for the passed parameter type and returns a void pointer to be set as arg[0] of qt_metacall static void* CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info, PythonQtArgumentFrame* frame); @@ -156,10 +156,10 @@ class PYTHONQT_EXPORT PythonQtConv { static PyObject* QVariantHashToPyObject(const QVariantHash& m); static PyObject* QVariantMapToPyObject(const QVariantMap& m); static PyObject* QVariantListToPyObject(const QVariantList& l); - + //! get human readable string from CPP object (when the metatype is known) static QString CPPObjectToString(int type, const void* data); - + //! register a converter callback from python to cpp for given metatype static void registerPythonToMetaTypeConverter(int metaTypeId, PythonQtConvertPythonToMetaTypeCB* cb) { _pythonToMetaTypeConverters.insert(metaTypeId, cb); } @@ -185,7 +185,9 @@ class PYTHONQT_EXPORT PythonQtConv { static PyObject* convertFromPythonQtSafeObjectPtr(const void* /* PythonQtObjectPtr* */ inObject, int /*metaTypeId*/); static bool convertToQListOfPythonQtObjectPtr(PyObject* obj, void* /* QList* */ outList, int /*metaTypeId*/, bool /*strict*/); static PyObject* convertFromQListOfPythonQtObjectPtr(const void* /* QList* */ inObject, int /*metaTypeId*/); +#if QT_VERSION < 0x060000 static PyObject* convertFromStringRef(const void* inObject, int /*metaTypeId*/); +#endif //! Returns the name of the equivalent CPP type (for signals and slots) static QByteArray getCPPTypeName(PyObject* type); @@ -194,10 +196,10 @@ class PYTHONQT_EXPORT PythonQtConv { static bool isStringType(PyTypeObject* type); protected: - static QHash _metaTypeToPythonConverters; - static QHash _pythonToMetaTypeConverters; + static QHash _metaTypeToPythonConverters; + static QHash _pythonToMetaTypeConverters; static PythonQtConvertPythonSequenceToQVariantListCB* _pythonSequenceToQVariantListCB; - + //! handle automatic conversion of some special types (QColor, QBrush, ...) static void* handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject, PythonQtArgumentFrame* frame); @@ -212,13 +214,13 @@ class PYTHONQT_EXPORT PythonQtConv { //! helper template function for QVariantMapToPyObject/QVariantHashToPyObject template static PyObject* mapToPython (const Map& m); - + }; template PyObject* PythonQtConvertListOfValueTypeToPythonList(const void* /*QList* */ inList, int metaTypeId) { - ListType* list = (ListType*)inList; + ListType* list = (ListType*)inList; static const int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(QByteArray(QMetaType::typeName(metaTypeId))); if (innerType == QVariant::Invalid) { std::cerr << "PythonQtConvertListOfValueTypeToPythonList: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl; @@ -235,7 +237,7 @@ PyObject* PythonQtConvertListOfValueTypeToPythonList(const void* /*QList* */ template bool PythonQtConvertPythonListToListOfValueType(PyObject* obj, void* /*QList* */ outList, int metaTypeId, bool /*strict*/) { - ListType* list = (ListType*)outList; + ListType* list = (ListType*)outList; static const int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(QByteArray(QMetaType::typeName(metaTypeId))); if (innerType == QVariant::Invalid) { std::cerr << "PythonQtConvertPythonListToListOfValueType: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl; @@ -270,7 +272,7 @@ PyObject* PythonQtConvertListOfKnownClassToPythonList(const void* /*QList* */ { ListType* list = (ListType*)inList; static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QByteArray(QMetaType::typeName(metaTypeId)))); - if (innerType == NULL) { + if (innerType == nullptr) { std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type " << innerType->className().constData() << std::endl; } PyObject* result = PyTuple_New(list->size()); @@ -290,7 +292,7 @@ bool PythonQtConvertPythonListToListOfKnownClass(PyObject* obj, void* /*QList { ListType* list = (ListType*)outList; static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QByteArray(QMetaType::typeName(metaTypeId)))); - if (innerType == NULL) { + if (innerType == nullptr) { std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type " << innerType->className().constData() << std::endl; } bool result = false; @@ -500,7 +502,7 @@ bool PythonQtConvertPythonToIntegerMap(PyObject* val, void* /*QMap* */ o tuple = PyList_GetItem(items, i); key = PyTuple_GetItem(tuple, 0); value = PyTuple_GetItem(tuple, 1); - + bool ok; int intKey = PythonQtConv::PyObjGetInt(key, false, ok); // this is quite some overhead, but it avoids having another large switch... diff --git a/src/PythonQtCppWrapperFactory.h b/src/PythonQtCppWrapperFactory.h index e4bf2012..d3cf4f6d 100644 --- a/src/PythonQtCppWrapperFactory.h +++ b/src/PythonQtCppWrapperFactory.h @@ -55,6 +55,7 @@ A factory can be added to PythonQt by PythonQt::addCppWrapperFactory(). */ class PYTHONQT_EXPORT PythonQtCppWrapperFactory { + Q_DISABLE_COPY(PythonQtCppWrapperFactory) public: PythonQtCppWrapperFactory() {}; virtual ~PythonQtCppWrapperFactory() {}; @@ -68,9 +69,10 @@ class PYTHONQT_EXPORT PythonQtCppWrapperFactory //! Python with other means than PythonQt/QObjects. class PYTHONQT_EXPORT PythonQtForeignWrapperFactory { + Q_DISABLE_COPY(PythonQtForeignWrapperFactory) public: - PythonQtForeignWrapperFactory() {}; - virtual ~PythonQtForeignWrapperFactory() {}; + PythonQtForeignWrapperFactory() {} + virtual ~PythonQtForeignWrapperFactory() {} //! create a Python object (with new reference count), wrapping the given \p ptr as class of type \p classname //! Return NULL (and not Py_None) if the object could not be wrapped. diff --git a/src/PythonQtDoc.h b/src/PythonQtDoc.h index 0723b571..ac7d3d56 100644 --- a/src/PythonQtDoc.h +++ b/src/PythonQtDoc.h @@ -197,12 +197,12 @@ Qt framework. longinteger ulong,longlong,ulonglonglong QStringunicode string - QByteArrayQByteArray wrapper + QByteArrayQByteArray wrapper \ref qbytearray-bytes "(1)" char*str QStringListtuple of unicode strings QVariantListtuple of objects QVariantMapdict of objects - QVariantdepends on type, see below + QVariantdepends on type \ref qvariant "(2)" QSize, QRect and all other standard Qt QVariantsvariant wrapper that supports complete API of the respective Qt classes OwnRegisteredMetaTypeC++ wrapper, optionally with additional information/wrapping provided by registerCPPClass() QListconverts to a list of CPP wrappers @@ -210,14 +210,17 @@ Qt framework. EnumTypeEnum wrapper derived from python integer QObject (and derived classes)QObject wrapper C++ objectCPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators - PyObjectPyObject + PyObjectPyObject \ref pyobject "(3)" - PyObject is passed as direct pointer, which allows to pass/return any Python object directly to/from - a Qt slot that uses PyObject* as its argument/return value. - QVariants are mapped recursively as given above, e.g. a dictionary can + -# \anchor qbytearray-bytes The Python 'bytes' type will automatically be converted to QByteArray where required. For converting a QByteArray to 'bytes' use the .data() method. + -# \anchor qvariant QVariants are mapped recursively as given above, e.g. a dictionary can contain lists of dictionaries of doubles. - All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object. + -# \anchor pyobject PyObject is passed as direct pointer, which allows to pass/return any Python object directly to/from + a Qt slot that uses PyObject* as its argument/return value. + + All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these objects. + \section QObject QObject Wrapping diff --git a/src/PythonQtImportFileInterface.h b/src/PythonQtImportFileInterface.h index a6d5026d..ea8afbb1 100644 --- a/src/PythonQtImportFileInterface.h +++ b/src/PythonQtImportFileInterface.h @@ -50,10 +50,11 @@ //! Defines an abstract interface to file access for the Python import statement. //! see PythonQt::setImporter() class PythonQtImportFileInterface { - + Q_DISABLE_COPY(PythonQtImportFileInterface) public: // get rid of warnings virtual ~PythonQtImportFileInterface() {} + PythonQtImportFileInterface() {} //! read the given file as byte array, without doing any linefeed translations virtual QByteArray readFileAsBytes(const QString& filename) = 0; @@ -78,7 +79,7 @@ class PythonQtImportFileInterface { //! called by PythonQt after successful import to allow //! recording of imports - virtual void importedModule(const QString& /*module*/) {}; + virtual void importedModule(const QString& /*module*/) {} }; diff --git a/src/PythonQtImporter.cpp b/src/PythonQtImporter.cpp index 21ec5a43..0855a29f 100644 --- a/src/PythonQtImporter.cpp +++ b/src/PythonQtImporter.cpp @@ -128,7 +128,7 @@ PythonQtImport::ModuleInfo PythonQtImport::getModuleInfo(PythonQtImporter* self, */ int PythonQtImporter_init(PythonQtImporter *self, PyObject *args, PyObject * /*kwds*/) { - self->_path = NULL; + self->_path = nullptr; const char* cpath; if (!PyArg_ParseTuple(args, "s", @@ -177,12 +177,12 @@ PyObject * PythonQtImporter_find_module(PyObject *obj, PyObject *args) { PythonQtImporter *self = (PythonQtImporter *)obj; - PyObject *path = NULL; + PyObject *path = nullptr; char *fullname; if (!PyArg_ParseTuple(args, "s|O:PythonQtImporter.find_module", &fullname, &path)) - return NULL; + return nullptr; //qDebug() << "looking for " << fullname << " at " << *self->_path; @@ -205,7 +205,7 @@ PythonQtImporter_iter_modules(PyObject *obj, PyObject *args) const char* prefix; if (!PyArg_ParseTuple(args, "|s", &prefix)) { - return NULL; + return nullptr; } PythonQtImporter *self = (PythonQtImporter *)obj; PythonQtObjectPtr pkgutil = PythonQt::self()->importModule("pkgutil"); @@ -221,37 +221,37 @@ PyObject * PythonQtImporter_load_module(PyObject *obj, PyObject *args) { PythonQtImporter *self = (PythonQtImporter *)obj; - PyObject *code = NULL, *mod = NULL, *dict = NULL; - char *fullname; + PyObject *code = nullptr, *mod = nullptr, *dict = nullptr; + char *fullname = NULL; if (!PyArg_ParseTuple(args, "s:PythonQtImporter.load_module", &fullname)) - return NULL; + return nullptr; PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname); if (info.type == PythonQtImport::MI_NOT_FOUND) { - return NULL; + return nullptr; } if (info.type == PythonQtImport::MI_PACKAGE || info.type == PythonQtImport::MI_MODULE) { QString fullPath; QString fullCachePath; code = PythonQtImport::getModuleCode(self, fullname, fullPath, fullCachePath); - if (code == NULL) { - return NULL; + if (code == nullptr) { + return nullptr; } mod = PyImport_AddModule(fullname); - if (mod == NULL) { + if (mod == nullptr) { Py_DECREF(code); - return NULL; + return nullptr; } dict = PyModule_GetDict(mod); if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0) { Py_DECREF(code); Py_DECREF(mod); - return NULL; + return nullptr; } if (info.type == PythonQtImport::MI_PACKAGE) { @@ -263,25 +263,25 @@ PythonQtImporter_load_module(PyObject *obj, PyObject *args) QStringToPythonConstCharPointer(*self->_path), SEP, QStringToPythonConstCharPointer(subname)); - if (fullpath == NULL) { + if (fullpath == nullptr) { Py_DECREF(code); Py_DECREF(mod); - return NULL; + return nullptr; } pkgpath = Py_BuildValue("[O]", fullpath); Py_DECREF(fullpath); - if (pkgpath == NULL) { + if (pkgpath == nullptr) { Py_DECREF(code); Py_DECREF(mod); - return NULL; + return nullptr; } err = PyDict_SetItemString(dict, "__path__", pkgpath); Py_DECREF(pkgpath); if (err != 0) { Py_DECREF(code); Py_DECREF(mod); - return NULL; + return nullptr; } // set __package__ only for Python 3, because in Python 2 it causes the exception "__package__ set to non-string" @@ -293,7 +293,7 @@ PythonQtImporter_load_module(PyObject *obj, PyObject *args) if (err != 0) { Py_DECREF(code); Py_DECREF(mod); - return NULL; + return nullptr; } #endif } @@ -301,7 +301,7 @@ PythonQtImporter_load_module(PyObject *obj, PyObject *args) #ifdef PY3K PyObject* fullnameObj = PyUnicode_FromString(fullname); PyObject* fullPathObj = PythonQtConv::QStringToPyObject(fullPath); - PyObject* fullCachePathObj = !fullCachePath.isEmpty() ? PythonQtConv::QStringToPyObject(fullCachePath) : NULL; + PyObject* fullCachePathObj = !fullCachePath.isEmpty() ? PythonQtConv::QStringToPyObject(fullCachePath) : nullptr; mod = PyImport_ExecCodeModuleObject(fullnameObj, code, fullPathObj, fullCachePathObj); Py_XDECREF(fullnameObj); Py_XDECREF(fullPathObj); @@ -338,7 +338,7 @@ PythonQtImporter_load_module(PyObject *obj, PyObject *args) QVariantList list = result.toList(); if (list.count()==3) { // We prepend the full module name (including package prefix) - list.prepend(fullname); + list.prepend(QString(fullname)); #ifdef __linux #ifdef _DEBUG // imp_find_module() does not respect the debug suffix '_d' on Linux, @@ -372,7 +372,7 @@ PyObject * PythonQtImporter_get_data(PyObject* /*obj*/, PyObject* /*args*/) { // EXTRA, NOT YET IMPLEMENTED - return NULL; + return nullptr; } PyObject * @@ -382,7 +382,7 @@ PythonQtImporter_get_code(PyObject *obj, PyObject *args) char *fullname; if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_code", &fullname)) - return NULL; + return nullptr; QString notused; QString notused2; @@ -393,7 +393,7 @@ PyObject * PythonQtImporter_get_source(PyObject * /*obj*/, PyObject * /*args*/) { // EXTRA, NOT YET IMPLEMENTED - return NULL; + return nullptr; } PyDoc_STRVAR(doc_find_module, @@ -447,7 +447,7 @@ PyMethodDef PythonQtImporter_methods[] = { doc_get_code}, {"get_source", PythonQtImporter_get_source, METH_VARARGS, doc_get_source}, - {NULL, NULL, 0 , NULL} /* sentinel */ + {nullptr, nullptr, 0 , nullptr} /* sentinel */ }; @@ -457,48 +457,48 @@ PyDoc_STRVAR(PythonQtImporter_doc, Create a new PythonQtImporter instance. 'path' must be a valid path on disk/or inside of a zip file known to MeVisLab\n\ . Every path is accepted."); -#define DEFERRED_ADDRESS(ADDR) 0 +#define DEFERRED_ADDRESS(ADDR) nullptr PyTypeObject PythonQtImporter_Type = { PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) "PythonQtImport.PythonQtImporter", sizeof(PythonQtImporter), - 0, /* tp_itemsize */ + 0, /* tp_itemsize */ (destructor)PythonQtImporter_dealloc, /* tp_dealloc */ - 0, /* 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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ + 0, /* tp_vectorcall_offset */ + nullptr, /* tp_getattr */ + nullptr, /* tp_setattr */ + nullptr, /* tp_compare */ + nullptr, /* tp_repr */ + nullptr, /* tp_as_number */ + nullptr, /* tp_as_sequence */ + nullptr, /* tp_as_mapping */ + nullptr, /* tp_hash */ + nullptr, /* tp_call */ + nullptr, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + nullptr, /* tp_setattro */ + nullptr, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /* tp_flags */ PythonQtImporter_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PythonQtImporter_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ + nullptr, /* tp_traverse */ + nullptr, /* tp_clear */ + nullptr, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + nullptr, /* tp_iter */ + nullptr, /* tp_iternext */ + PythonQtImporter_methods, /* tp_methods */ + nullptr, /* tp_members */ + nullptr, /* tp_getset */ + nullptr, /* tp_base */ + nullptr, /* tp_dict */ + nullptr, /* tp_descr_get */ + nullptr, /* tp_descr_set */ + 0, /* tp_dictoffset */ (initproc)PythonQtImporter_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - PyObject_Del, /* tp_free */ + PyType_GenericNew, /* tp_new */ + PyObject_Del, /* tp_free */ }; @@ -543,7 +543,7 @@ open_exclusive(const QString& filename) fd = open(filename.toLocal8Bit(), flags, 0666); #endif if (fd < 0) - return NULL; + return nullptr; return fdopen(fd, "wb"); #else /* Best we can do -- on Windows this can't happen anyway */ @@ -560,7 +560,7 @@ void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filena return; } fp = open_exclusive(filename); - if (fp == NULL) { + if (fp == nullptr) { if (Py_VerboseFlag) PySys_WriteStderr( "# can't create %s\n", QStringToPythonConstCharPointer(filename)); @@ -579,6 +579,8 @@ void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filena #endif #ifdef PY3K PyMarshal_WriteLongToFile(sourceSize, fp, Py_MARSHAL_VERSION); +#else + Q_UNUSED(sourceSize) #endif #if PY_VERSION_HEX < 0x02040000 PyMarshal_WriteObjectToFile((PyObject *)co, fp); @@ -650,20 +652,20 @@ PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_ #ifdef PY3K // Python 3 also stores the size of the *.py file, but we ignore it for now int sourceSize = getLong((unsigned char *)buf + 8); - Q_UNUSED(sourceSize); + Q_UNUSED(sourceSize) // read the module code = PyMarshal_ReadObjectFromString(buf + 12, size - 12); #else code = PyMarshal_ReadObjectFromString(buf + 8, size - 8); #endif - if (code == NULL) - return NULL; + if (code == nullptr) + return nullptr; if (!PyCode_Check(code)) { Py_DECREF(code); PyErr_Format(PyExc_TypeError, "compiled module %.200s is not a code object", QStringToPythonConstCharPointer(path)); - return NULL; + return nullptr; } return code; } @@ -675,14 +677,10 @@ PyObject * PythonQtImport::compileSource(const QString& path, const QByteArray& data) { PyObject *code; - QByteArray data1 = data; -// in qt4, data is null terminated -// data1.resize(data.size()+1); -// data1.data()[data.size()-1] = 0; #ifdef PY3K PyObject* filename = PythonQtConv::QStringToPyObject(path); code = Py_CompileStringObject(data.data(), filename, - Py_file_input, NULL, -1); + Py_file_input, nullptr, -1); Py_DECREF(filename); #else code = Py_CompileString(data.data(), QStringToPythonConstCharPointer(path), @@ -707,6 +705,18 @@ QString PythonQtImport::getSourceFilename(const QString& cacheFile) return pyFilename; } +namespace +{ + qint64 toSecsSinceEpoch(const QDateTime& time) + { +#if QT_VERSION < 0x060000 + return time.toTime_t(); +#else + return time.toSecsSinceEpoch(); +#endif + } +} + /* Return the code object for the module named by 'fullname' from the Zip archive as a new reference. */ PyObject * @@ -721,7 +731,7 @@ PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int /*ispack qdata = PythonQt::importInterface()->readSourceFile(path, ok); if (!ok) { // mlabErrorConst("PythonQtImporter","File could not be verified" << path); - return NULL; + return nullptr; } if (qdata == " ") { qdata.clear(); @@ -742,7 +752,7 @@ PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int /*ispack QDateTime time; time = PythonQt::importInterface()->lastModifiedDate(path); QString cacheFilename = getCacheFilename(path, /*isOptimizedFilename=*/false); - writeCompiledModule((PyCodeObject*)code, cacheFilename, time.toTime_t(), /*sourceSize=*/qdata.length()); + writeCompiledModule((PyCodeObject*)code, cacheFilename, toSecsSinceEpoch(time), /*sourceSize=*/qdata.length()); } } return code; @@ -756,7 +766,7 @@ PythonQtImport::getMTimeOfSource(const QString& path) if (PythonQt::importInterface()->exists(path2)) { QDateTime t = PythonQt::importInterface()->lastModifiedDate(path2); if (t.isValid()) { - mtime = t.toTime_t(); + mtime = toSecsSinceEpoch(t); } } @@ -776,7 +786,7 @@ PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QStr QString test; for (zso = mlab_searchorder; *zso->suffix;zso++) { - PyObject *code = NULL; + PyObject *code = nullptr; test = path + zso->suffix; if (Py_VerboseFlag > 1) @@ -800,13 +810,15 @@ PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QStr Py_DECREF(code); continue; } - if (code != NULL) { + if (code != nullptr) { modpath = test; #ifdef PY3K if (isbytecode) { cachemodpath = modpath; modpath = getSourceFilename(modpath); } +#else + Q_UNUSED(cachemodpath) #endif } return code; @@ -814,7 +826,7 @@ PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QStr } PyErr_Format(PythonQtImportError, "can't find module '%.200s'", fullname); - return NULL; + return nullptr; } QString PythonQtImport::replaceExtension(const QString& str, const QString& ext) @@ -845,7 +857,7 @@ PyObject* PythonQtImport::getCodeFromPyc(const QString& file) mtime = getMTimeOfSource(pyc); } code = getCodeFromData(pyc, true, false, mtime); - if (code != Py_None && code != NULL) { + if (code != Py_None && code != nullptr) { return code; } if (code) { @@ -867,11 +879,11 @@ static struct PyModuleDef PythonQtImport_def = { "PythonQtImport", /* m_name */ mlabimport_doc, /* m_doc */ -1, /* m_size */ - NULL, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL /* m_free */ + nullptr, /* m_methods */ + nullptr, /* m_reload */ + nullptr, /* m_traverse */ + nullptr, /* m_clear */ + nullptr /* m_free */ }; #endif @@ -911,19 +923,23 @@ void PythonQtImport::init() #endif PythonQtImportError = PyErr_NewException(const_cast("PythonQtImport.PythonQtImportError"), - PyExc_ImportError, NULL); - if (PythonQtImportError == NULL) + PyExc_ImportError, nullptr); + if (PythonQtImportError == nullptr) return; Py_INCREF(PythonQtImportError); if (PyModule_AddObject(mod, "PythonQtImportError", - PythonQtImportError) < 0) + PythonQtImportError) < 0) { + Py_DECREF(PythonQtImportError); return; + } Py_INCREF(&PythonQtImporter_Type); if (PyModule_AddObject(mod, "PythonQtImporter", - (PyObject *)&PythonQtImporter_Type) < 0) + (PyObject *)&PythonQtImporter_Type) < 0) { + Py_DECREF(&PythonQtImporter_Type); return; + } // set our importer into the path_hooks to handle all path on sys.path PyObject* classobj = PyDict_GetItemString(PyModule_GetDict(mod), "PythonQtImporter"); diff --git a/src/PythonQtImporter.h b/src/PythonQtImporter.h index 0bd54d12..d9595c4c 100644 --- a/src/PythonQtImporter.h +++ b/src/PythonQtImporter.h @@ -44,21 +44,21 @@ #include "PythonQtPythonInclude.h" -#include "structmember.h" -#include "osdefs.h" -#include "marshal.h" #include "compile.h" -#include +#include "marshal.h" +#include "osdefs.h" +#include "structmember.h" +#include #include #include //! defines a python object that stores a Qt slot info -typedef struct _PythonQtImporter { +struct PythonQtImporter { PyObject_HEAD QString* _path; -} PythonQtImporter; +}; //! implements importing of python files into PythonQt diff --git a/src/PythonQtInstanceWrapper.cpp b/src/PythonQtInstanceWrapper.cpp index 55381c96..06a02972 100644 --- a/src/PythonQtInstanceWrapper.cpp +++ b/src/PythonQtInstanceWrapper.cpp @@ -58,13 +58,13 @@ static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr); // we own our qobject, so we delete it now: delete self->_obj; - self->_obj = NULL; + self->_obj = nullptr; // if this object is reference counted, we just unref it: PythonQtVoidPtrCB* unrefCB = self->classInfo()->referenceCountingUnrefCB(); if (unrefCB) { (*unrefCB)(self->_wrappedPtr); - self->_wrappedPtr = NULL; + self->_wrappedPtr = nullptr; } else if (force || self->_ownedByPythonQt) { int type = self->classInfo()->metaTypeId(); @@ -75,10 +75,10 @@ static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, PythonQtSlotInfo* slot = self->classInfo()->destructor(); if (slot) { void* args[2]; - args[0] = NULL; + args[0] = nullptr; args[1] = &self->_wrappedPtr; PythonQtSlotInfo::invokeQtMethod(slot->decorator(), slot, args); - self->_wrappedPtr = NULL; + self->_wrappedPtr = nullptr; } else { if (type>=0) { // use QMetaType to destroy the object @@ -99,7 +99,7 @@ static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB(); if (cb) { // remove the pointer to the Python wrapper from the C++ object: - (*cb)(self->_obj, NULL); + (*cb)(self->_obj, nullptr); } } if (force || self->_ownedByPythonQt) { @@ -107,14 +107,14 @@ static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, delete self->_obj; } } else { - if (self->_obj->parent()==NULL) { + if (self->_obj->parent()==nullptr) { // tell someone who is interested that the qobject is no longer wrapped, if it has no parent PythonQt::qObjectNoLongerWrappedCB(self->_obj); } } } } - self->_obj = NULL; + self->_obj = nullptr; } static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self) @@ -130,16 +130,16 @@ static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*ar { //PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type; PythonQtInstanceWrapper *self; - static PyObject* emptyTuple = NULL; - if (emptyTuple==NULL) { + static PyObject* emptyTuple = nullptr; + if (emptyTuple==nullptr) { emptyTuple = PyTuple_New(0); } - self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL); + self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, nullptr); - if (self != NULL) { + if (self != nullptr) { new (&self->_obj) QPointer(); - self->_wrappedPtr = NULL; + self->_wrappedPtr = nullptr; self->_ownedByPythonQt = false; self->_useQMetaTypeDestroy = false; self->_isShellInstance = false; @@ -157,9 +157,9 @@ int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args // we are called from python, try to construct our object if (self->classInfo()->constructors()) { - void* directCPPPointer = NULL; + void* directCPPPointer = nullptr; PythonQtPassThisOwnershipType ownership; - PythonQtSlotFunction_CallImpl(self->classInfo(), NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer, &ownership); + PythonQtSlotFunction_CallImpl(self->classInfo(), nullptr, self->classInfo()->constructors(), args, kwds, nullptr, &directCPPPointer, &ownership); if (PyErr_Occurred()) { return -1; } @@ -223,7 +223,7 @@ static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wr PythonQtInstanceWrapper* w1 = wrapper; PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)other; // check pointers directly - if (w1->_wrappedPtr != NULL) { + if (w1->_wrappedPtr != nullptr) { if (w1->_wrappedPtr == w2->_wrappedPtr) { areSamePtrs = true; } @@ -301,9 +301,9 @@ static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wr PyObject* args = PyTuple_New(1); Py_INCREF(other); PyTuple_SET_ITEM(args, 0, other); - PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr); + PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, nullptr, wrapper->_wrappedPtr); Py_DECREF(args); - if (result == NULL) { + if (result == nullptr) { // special handling of EQ and NE, if call fails we just return EQ == false / NE == true. if (code == Py_EQ) { PyErr_Clear(); @@ -331,9 +331,9 @@ static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj) PyObject *PythonQtInstanceWrapper_inherits(PythonQtInstanceWrapper* obj, PyObject *args) { - char *name = NULL; + char *name = nullptr; if (!PyArg_ParseTuple(args, "s:PythonQtInstanceWrapper.inherits",&name)) { - return NULL; + return nullptr; } return PythonQtConv::GetPyBool(obj->classInfo()->inherits(name)); } @@ -348,7 +348,7 @@ PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self) PythonQtMemberInfo deleteSlot = self->classInfo()->member("py_delete"); if (deleteSlot._type == PythonQtMemberInfo::Slot) { // call the py_delete slot instead of internal C++ destructor... - PyObject* resultObj = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, deleteSlot._slot, NULL, NULL, self->_wrappedPtr); + PyObject* resultObj = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, deleteSlot._slot, nullptr, nullptr, self->_wrappedPtr); Py_XDECREF(resultObj); } else { PythonQtInstanceWrapper_deleteObject(self, true); @@ -359,19 +359,19 @@ PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self) static PyMethodDef PythonQtInstanceWrapper_methods[] = { - {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS, + {"className", reinterpret_cast(reinterpret_cast(PythonQtInstanceWrapper_classname)), METH_NOARGS, "Return the classname of the object" }, - {"inherits", (PyCFunction)PythonQtInstanceWrapper_inherits, METH_VARARGS, + {"inherits", reinterpret_cast(reinterpret_cast(PythonQtInstanceWrapper_inherits)), METH_VARARGS, "Returns if the class inherits or is of given type name" }, - {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS, + {"help", reinterpret_cast(reinterpret_cast(PythonQtInstanceWrapper_help)), METH_NOARGS, "Shows the help of available methods for this class" }, - {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS, + {"delete", reinterpret_cast(reinterpret_cast(PythonQtInstanceWrapper_delete)), METH_NOARGS, "Deletes the C++ object (at your own risk, my friend!)" }, -{NULL, NULL, 0, NULL} /* Sentinel */ +{nullptr, nullptr, 0, nullptr} /* Sentinel */ }; @@ -380,8 +380,8 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) const char *attributeName; PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj; - if ((attributeName = PyString_AsString(name)) == NULL) { - return NULL; + if ((attributeName = PyString_AsString(name)) == nullptr) { + return nullptr; } if (qstrcmp(attributeName, "__dict__")==0) { @@ -419,7 +419,7 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) PythonQtMemberInfo member = wrapper->classInfo()->member(dynamicDictString); if (member._type == PythonQtMemberInfo::Slot) { PyObject* args = PyTuple_New(0); - PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, args, NULL, wrapper->_wrappedPtr); + PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, args, nullptr, wrapper->_wrappedPtr); Py_DECREF(args); if (result) { if (PyDict_Check(result)) { @@ -448,7 +448,7 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) // we need to bind the class signal to the object PythonQtSignalFunctionObject* sig = (PythonQtSignalFunctionObject*)superAttr; if (sig->_dynamicInfo) { - if (!wrapper->dynamicClassInfo() || wrapper->dynamicClassInfo()->_dynamicMetaObject == NULL) { + if (!wrapper->dynamicClassInfo() || wrapper->dynamicClassInfo()->_dynamicMetaObject == nullptr) { // force creation of meta object: if (wrapper->_obj) { wrapper->_obj->metaObject(); @@ -456,14 +456,14 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) } if (wrapper->dynamicClassInfo()) { // go through the whole inheritance chain to find a signal in the dynamic class info: - PythonQtClassInfo* classInfo = NULL; + PythonQtClassInfo* classInfo = nullptr; PythonQtClassWrapper* classType = (PythonQtClassWrapper*)Py_TYPE(wrapper); while (classType->_dynamicClassInfo) { classInfo = classType->_dynamicClassInfo->_classInfo; if (classInfo) { PythonQtMemberInfo member = classInfo->member(attributeName); if (member._type == PythonQtMemberInfo::Signal) { - PyObject* boundSignal = PythonQtSignalFunction_New(member._slot, (PyObject*)wrapper, NULL); + PyObject* boundSignal = PythonQtSignalFunction_New(member._slot, (PyObject*)wrapper, nullptr); Py_DECREF(superAttr); return boundSignal; } @@ -490,13 +490,13 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) QString methodName = "getProperty('"; methodName += attributeName; methodName += "')"; - profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), QStringToPythonConstCharPointer(methodName), NULL); + profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), QStringToPythonConstCharPointer(methodName), nullptr); } PyObject* value = PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj)); if (profilingCB) { - profilingCB(PythonQt::Leave, NULL, NULL, NULL); + profilingCB(PythonQt::Leave, nullptr, nullptr, nullptr); } return value; @@ -508,14 +508,14 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) } else { QString error = QString("Trying to read property '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object"; PyErr_SetString(PyExc_ValueError, QStringToPythonConstCharPointer(error)); - return NULL; + return nullptr; } break; case PythonQtMemberInfo::Slot: - return PythonQtSlotFunction_New(member._slot, obj, NULL); + return PythonQtSlotFunction_New(member._slot, obj, nullptr); break; case PythonQtMemberInfo::Signal: - return PythonQtSignalFunction_New(member._slot, obj, NULL); + return PythonQtSignalFunction_New(member._slot, obj, nullptr); break; case PythonQtMemberInfo::EnumValue: { @@ -538,7 +538,7 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) // check for a getter slot PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName); if (member._type == PythonQtMemberInfo::Slot) { - return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr); + return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, nullptr, nullptr, wrapper->_wrappedPtr); } { @@ -549,7 +549,7 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) PyObject* args = PyTuple_New(1); Py_INCREF(name); PyTuple_SET_ITEM(args, 0, name); - PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, args, NULL, wrapper->_wrappedPtr); + PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, args, nullptr, wrapper->_wrappedPtr); Py_DECREF(args); if (result) { return result; @@ -603,7 +603,7 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) } PyErr_SetString(PyExc_AttributeError, QStringToPythonConstCharPointer(error)); - return NULL; + return nullptr; } static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value) @@ -612,7 +612,7 @@ static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec const char *attributeName; PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj; - if ((attributeName = PyString_AsString(name)) == NULL) + if ((attributeName = PyString_AsString(name)) == nullptr) return -1; PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName); @@ -641,13 +641,13 @@ static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec QString methodName = "setProperty('"; methodName += attributeName; methodName += "')"; - profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), QStringToPythonConstCharPointer(methodName), NULL); + profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), QStringToPythonConstCharPointer(methodName), nullptr); } success = prop.write(wrapper->_obj, v); if (profilingCB) { - profilingCB(PythonQt::Leave, NULL, NULL, NULL); + profilingCB(PythonQt::Leave, nullptr, nullptr, nullptr); } } if (success) { @@ -681,7 +681,7 @@ static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec PyObject* args = PyTuple_New(1); Py_INCREF(value); PyTuple_SET_ITEM(args, 0, value); - PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, NULL, wrapper->_wrappedPtr, &result); + PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, nullptr, wrapper->_wrappedPtr, &result); Py_DECREF(args); return 0; } @@ -748,7 +748,7 @@ static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) { // next, try to call py_toString PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString"); if (info._type == PythonQtMemberInfo::Slot) { - PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr); + PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, nullptr, nullptr, wrapper->_wrappedPtr); if (resultObj) { result = PythonQtConv::PyObjGetString(resultObj); Py_DECREF(resultObj); @@ -831,13 +831,13 @@ static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj) static int PythonQtInstanceWrapper_builtin_nonzero(PyObject *obj) { PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj; - return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1; + return (wrapper->_wrappedPtr == nullptr && wrapper->_obj == nullptr)?0:1; } static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj) { - if (obj->_wrappedPtr != NULL) { + if (obj->_wrappedPtr != nullptr) { return static_cast(reinterpret_cast(obj->_wrappedPtr)); } else { QObject* qobj = obj->_obj; // get pointer from QPointer wrapper @@ -849,103 +849,103 @@ static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj) // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr static PyNumberMethods PythonQtInstanceWrapper_as_number = { - 0, /* nb_add */ - 0, /* nb_subtract */ - 0, /* nb_multiply */ + nullptr, /* nb_add */ + nullptr, /* nb_subtract */ + nullptr, /* nb_multiply */ #ifndef PY3K - 0, /* nb_divide */ + nullptr, /* nb_divide */ #endif - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ + nullptr, /* nb_remainder */ + nullptr, /* nb_divmod */ + nullptr, /* nb_power */ + nullptr, /* nb_negative */ + nullptr, /* nb_positive */ + nullptr, /* nb_absolute */ PythonQtInstanceWrapper_builtin_nonzero, /* nb_nonzero / nb_bool in Py3K */ - 0, /* nb_invert */ - 0, /* nb_lshift */ - 0, /* nb_rshift */ - 0, /* nb_and */ - 0, /* nb_xor */ - 0, /* nb_or */ + nullptr, /* nb_invert */ + nullptr, /* nb_lshift */ + nullptr, /* nb_rshift */ + nullptr, /* nb_and */ + nullptr, /* nb_xor */ + nullptr, /* nb_or */ #ifndef PY3K - 0, /* nb_coerce */ + nullptr, /* nb_coerce */ #endif - 0, /* nb_int */ - 0, /* nb_long / nb_reserved in Py3K */ - 0, /* nb_float */ + nullptr, /* nb_int */ + nullptr, /* nb_long / nb_reserved in Py3K */ + nullptr, /* nb_float */ #ifndef PY3K - 0, /* nb_oct */ - 0, /* nb_hex */ + nullptr, /* nb_oct */ + nullptr, /* nb_hex */ #endif - 0, /* nb_inplace_add */ - 0, /* nb_inplace_subtract */ - 0, /* nb_inplace_multiply */ + nullptr, /* nb_inplace_add */ + nullptr, /* nb_inplace_subtract */ + nullptr, /* nb_inplace_multiply */ #ifndef PY3K - 0, /* nb_inplace_divide */ + nullptr, /* nb_inplace_divide */ #endif - 0, /* 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 */ + nullptr, /* nb_inplace_remainder */ + nullptr, /* nb_inplace_power */ + nullptr, /* nb_inplace_lshift */ + nullptr, /* nb_inplace_rshift */ + nullptr, /* nb_inplace_and */ + nullptr, /* nb_inplace_xor */ + nullptr, /* nb_inplace_or */ + nullptr, /* nb_floor_divide */ + nullptr, /* nb_true_divide */ + nullptr, /* nb_inplace_floor_divide */ + nullptr, /* nb_inplace_true_divide */ #ifdef PY3K - 0, /* nb_index in Py3K */ + nullptr, /* nb_index in Py3K */ #endif }; PyTypeObject PythonQtInstanceWrapper_Type = { PyVarObject_HEAD_INIT(&PythonQtClassWrapper_Type, 0) - "PythonQt.PythonQtInstanceWrapper", /*tp_name*/ + "PythonQt.PythonQtInstanceWrapper", /*tp_name*/ sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/ - 0, /*tp_itemsize*/ + 0, /*tp_itemsize*/ (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - PythonQtInstanceWrapper_repr, /*tp_repr*/ - &PythonQtInstanceWrapper_as_number, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */ - 0, /*tp_call*/ - PythonQtInstanceWrapper_str, /*tp_str*/ - PythonQtInstanceWrapper_getattro, /*tp_getattro*/ - PythonQtInstanceWrapper_setattro, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + 0, /*tp_vectorcall_offset*/ + nullptr, /*tp_getattr*/ + nullptr, /*tp_setattr*/ + nullptr, /*tp_compare*/ + PythonQtInstanceWrapper_repr, /*tp_repr*/ + &PythonQtInstanceWrapper_as_number, /*tp_as_number*/ + nullptr, /*tp_as_sequence*/ + nullptr, /*tp_as_mapping*/ + (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */ + nullptr, /*tp_call*/ + PythonQtInstanceWrapper_str, /*tp_str*/ + PythonQtInstanceWrapper_getattro, /*tp_getattro*/ + PythonQtInstanceWrapper_setattro, /*tp_setattro*/ + nullptr, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE #ifndef PY3K | Py_TPFLAGS_CHECKTYPES #endif , /*tp_flags*/ - "PythonQtInstanceWrapper object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ -#ifdef PY3K - PythonQtInstanceWrapper_methods, -#else - 0, /* tp_methods */ -#endif - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ + "PythonQtInstanceWrapper object", /* tp_doc */ + nullptr, /* tp_traverse */ + nullptr, /* tp_clear */ + (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + nullptr, /* tp_iter */ + nullptr, /* tp_iternext */ +#ifdef PY3K + PythonQtInstanceWrapper_methods, +#else + 0, /* tp_methods */ +#endif + nullptr, /* tp_members */ + nullptr, /* tp_getset */ + nullptr, /* tp_base */ + nullptr, /* tp_dict */ + nullptr, /* tp_descr_get */ + nullptr, /* tp_descr_set */ + 0, /* tp_dictoffset */ (initproc)PythonQtInstanceWrapper_init, /* tp_init */ - 0, /* tp_alloc */ + nullptr, /* tp_alloc */ PythonQtInstanceWrapper_new, /* tp_new */ }; diff --git a/src/PythonQtInstanceWrapper.h b/src/PythonQtInstanceWrapper.h index 10d1b55b..66f2c34a 100644 --- a/src/PythonQtInstanceWrapper.h +++ b/src/PythonQtInstanceWrapper.h @@ -51,7 +51,6 @@ #include "structmember.h" #include "methodobject.h" #include "compile.h" -#include "eval.h" class PythonQtClassInfo; class QObject; @@ -60,11 +59,11 @@ extern PYTHONQT_EXPORT PyTypeObject PythonQtInstanceWrapper_Type; //--------------------------------------------------------------- //! a Python wrapper object for Qt objects and C++ objects (that are themselves wrapped by wrapper QObjects) -typedef struct PythonQtInstanceWrapperStruct { +struct PythonQtInstanceWrapper { PyObject_HEAD //! the class information, this is set even if the _obj or _wrappedPtr is NULL to support typed NULL pointers - inline PythonQtClassInfo* classInfo() + inline PythonQtClassInfo* classInfo() { return ((PythonQtClassWrapper*)Py_TYPE(this))->_classInfo; } inline PythonQtDynamicClassInfo* dynamicClassInfo() @@ -126,7 +125,7 @@ typedef struct PythonQtInstanceWrapperStruct { //! stores if the shell instance (C++) owns the wrapper with its ref count bool _shellInstanceRefCountsWrapper; -} PythonQtInstanceWrapper; +}; int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds); diff --git a/src/PythonQtMethodInfo.cpp b/src/PythonQtMethodInfo.cpp index 5010d169..be68743b 100644 --- a/src/PythonQtMethodInfo.cpp +++ b/src/PythonQtMethodInfo.cpp @@ -73,10 +73,10 @@ PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInf PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList& args) { ParameterInfo type; - fillParameterInfo(type, typeName, NULL); + fillParameterInfo(type, typeName, nullptr); _parameters.append(type); Q_FOREACH (const QByteArray& name, args) { - fillParameterInfo(type, name, NULL); + fillParameterInfo(type, name, nullptr); _parameters.append(type); } setupAllowThreads(); @@ -85,7 +85,7 @@ PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList= 0x060000 + QByteArray alias2{ alias }; + QByteArray name2{ name }; + // in Qt6 QPair has been replaced by std::pair, QVector is really QList, and there is no space between ">" + alias2.replace("QPair", "std::pair").replace("QVector", "QList").replace("> >", ">>"); + name2.replace("QPair", "std::pair").replace("QVector", "QList").replace("> >", ">>"); + _parameterNameAliases.insert(alias2, name2); +#else _parameterNameAliases.insert(alias, name); +#endif } const PythonQtMethodInfo::ParameterInfo& PythonQtMethodInfo::getParameterInfoForMetaType(int type) @@ -432,7 +452,7 @@ const PythonQtMethodInfo::ParameterInfo& PythonQtMethodInfo::getParameterInfoFor void PythonQtSlotInfo::deleteOverloadsAndThis() { PythonQtSlotInfo* cur = this; - while(cur->nextInfo()) { + while(cur) { PythonQtSlotInfo* next = cur->nextInfo(); delete cur; cur = next; @@ -654,3 +674,8 @@ void PythonQtSlotInfo::setGlobalShouldAllowThreads(bool flag) { _globalShouldAllowThreads = flag; } + +bool PythonQtSlotInfo::getGlobalShouldAllowThreads() +{ + return _globalShouldAllowThreads; +} diff --git a/src/PythonQtMethodInfo.h b/src/PythonQtMethodInfo.h index 82ab4dd7..db849904 100644 --- a/src/PythonQtMethodInfo.h +++ b/src/PythonQtMethodInfo.h @@ -70,7 +70,7 @@ class PYTHONQT_EXPORT PythonQtMethodInfo PyObject* enumWrapper; // if it is an enum, a pointer to the enum wrapper int typeId; // a mixture from QMetaType and ParameterType char pointerCount; // the number of pointer indirections - char innerNamePointerCount; // the number of pointer indirections in the inner name + char innerNamePointerCount; // the number of pointer indirections in the inner name bool isConst; bool isReference; bool isQList; @@ -113,7 +113,7 @@ class PYTHONQT_EXPORT PythonQtMethodInfo static void addParameterTypeAlias(const QByteArray& alias, const QByteArray& name); //! fill the parameter info for the given type name - static void fillParameterInfo(ParameterInfo& type, const QByteArray& name, PythonQtClassInfo* classInfo = NULL); + static void fillParameterInfo(ParameterInfo& type, const QByteArray& name, PythonQtClassInfo* classInfo = nullptr); //! returns a parameter info for the given metatype (and creates and caches one if it is not yet present) static const ParameterInfo& getParameterInfoForMetaType(int type); @@ -161,20 +161,20 @@ class PYTHONQT_EXPORT PythonQtSlotInfo : public PythonQtMethodInfo _parameters = info._parameters; _shouldAllowThreads = info._shouldAllowThreads; _slotIndex = info._slotIndex; - _next = NULL; + _next = nullptr; _decorator = info._decorator; _type = info._type; _upcastingOffset = 0; } - PythonQtSlotInfo(PythonQtClassInfo* classInfo, const QMetaMethod& meta, int slotIndex, QObject* decorator = NULL, Type type = MemberSlot ):PythonQtMethodInfo() - { + PythonQtSlotInfo(PythonQtClassInfo* classInfo, const QMetaMethod& meta, int slotIndex, QObject* decorator = nullptr, Type type = MemberSlot ):PythonQtMethodInfo() + { const PythonQtMethodInfo* info = getCachedMethodInfo(meta, classInfo); _meta = meta; _parameters = info->parameters(); _shouldAllowThreads = info->shouldAllowThreads(); _slotIndex = slotIndex; - _next = NULL; + _next = nullptr; _decorator = decorator; _type = type; _upcastingOffset = 0; @@ -203,10 +203,10 @@ class PYTHONQT_EXPORT PythonQtSlotInfo : public PythonQtMethodInfo void setNextInfo(PythonQtSlotInfo* next) { _next = next; } //! returns if the slot is a decorator slot - bool isInstanceDecorator() const { return _decorator!=NULL && _type == InstanceDecorator; } + bool isInstanceDecorator() const { return _decorator!=nullptr && _type == InstanceDecorator; } //! returns if the slot is a constructor slot - bool isClassDecorator() const { return _decorator!=NULL && _type == ClassDecorator; } + bool isClassDecorator() const { return _decorator!=nullptr && _type == ClassDecorator; } QObject* decorator() const { return _decorator; } diff --git a/src/PythonQtMisc.cpp b/src/PythonQtMisc.cpp index 3575156d..fdc90871 100644 --- a/src/PythonQtMisc.cpp +++ b/src/PythonQtMisc.cpp @@ -44,11 +44,11 @@ #define PYTHONQT_MAX_ARGUMENT_FRAME_SIZE (PYTHONQT_MAX_ARGS * 2) -PythonQtArgumentFrame* PythonQtArgumentFrame::_freeListHead = NULL; +PythonQtArgumentFrame* PythonQtArgumentFrame::_freeListHead = nullptr; PythonQtArgumentFrame::PythonQtArgumentFrame() { - _freeListNext = NULL; + _freeListNext = nullptr; // it is important to reserve the memory immediately, // otherwise pointers would change while pushing back new arguments. @@ -62,11 +62,11 @@ PythonQtArgumentFrame::~PythonQtArgumentFrame() PythonQtArgumentFrame* PythonQtArgumentFrame::newFrame() { - PythonQtArgumentFrame* frame = NULL; + PythonQtArgumentFrame* frame = nullptr; if (_freeListHead) { frame = _freeListHead; _freeListHead = _freeListHead->_freeListNext; - frame->_freeListNext = NULL; + frame->_freeListNext = nullptr; } else { frame = new PythonQtArgumentFrame(); } @@ -88,7 +88,7 @@ void PythonQtArgumentFrame::cleanupFreeList() head = head->_freeListNext; delete tmp; } - _freeListHead = NULL; + _freeListHead = nullptr; } void PythonQtArgumentFrame::reset() diff --git a/src/PythonQtMisc.h b/src/PythonQtMisc.h index dc04a667..c13eddee 100644 --- a/src/PythonQtMisc.h +++ b/src/PythonQtMisc.h @@ -67,6 +67,18 @@ ptr = (void*)item; \ } +#if QT_VERSION >= 0x060000 + +#define PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID(store, id, ptr) \ + PythonQtArgumentFrame_ADD_VARIANT_VALUE(store, QVariant(QMetaType(id)), ptr) + +#else + +#define PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID(store, id, ptr) \ + PythonQtArgumentFrame_ADD_VARIANT_VALUE(store, QVariant::Type(id), ptr) + +#endif + #define PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedPtr,store, value, ptr) \ { \ QVariant* item = (QVariant*)(alreadyAllocatedPtr?alreadyAllocatedPtr:store->nextVariantPtr()); \ @@ -74,6 +86,18 @@ ptr = (void*)item; \ } +#if QT_VERSION >= 0x060000 + +#define PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID_IF_NEEDED(alreadyAllocatedPtr,store, id, ptr) \ + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedPtr,store, QVariant(QMetaType(id)), ptr) + +#else + +#define PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID_IF_NEEDED(alreadyAllocatedPtr,store, id, ptr) \ + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedPtr,store, QVariant::Type(id), ptr) + +#endif + //! Stores C++ arguments for a qt_metacall (which are created when converting data from Python to C++) class PythonQtArgumentFrame { diff --git a/src/PythonQtObjectPtr.cpp b/src/PythonQtObjectPtr.cpp index ceb6263d..98d877a4 100644 --- a/src/PythonQtObjectPtr.cpp +++ b/src/PythonQtObjectPtr.cpp @@ -41,6 +41,16 @@ #include +#ifndef Py_XSETREF // Some Python2, but not the latest one +#define Py_XSETREF(op1, op2) \ + do { \ + auto **op = &(op1); \ + PyObject *tmp = static_cast(*op); \ + *op = (op2); \ + Py_XDECREF(tmp); \ + } while (0) +#endif + QVariant PythonQtObjectPtr::evalScript(const QString& script, int start) { return PythonQt::self()->evalScript(_object, script, start); @@ -89,8 +99,8 @@ QVariant PythonQtObjectPtr::call(const QVariantList& args, const QVariantMap& kw PythonQtObjectPtr::PythonQtObjectPtr(PyObject* o) { + Py_XINCREF(o); _object = o; - if (o) Py_INCREF(_object); } PythonQtObjectPtr::PythonQtObjectPtr(PythonQtSafeObjectPtr &&p) :_object(p.takeObject()) @@ -99,21 +109,20 @@ PythonQtObjectPtr::PythonQtObjectPtr(PythonQtSafeObjectPtr &&p) :_object(p.takeO PythonQtObjectPtr::~PythonQtObjectPtr() { - if (_object && Py_IsInitialized()) Py_DECREF(_object); + if (_object && Py_IsInitialized()) Py_XDECREF(_object); } void PythonQtObjectPtr::setNewRef(PyObject* o) { if (o != _object) { - if (_object) Py_DECREF(_object); - _object = o; + Py_XSETREF(_object, o); } } bool PythonQtObjectPtr::fromVariant(const QVariant& variant) { if (!variant.isNull()) { - PyObject* object = NULL; + PyObject* object = nullptr; if (PythonQt::priv()->isPythonQtSafeObjectPtrMetaId(variant.userType())) { object = (*((const PythonQtSafeObjectPtr*)variant.constData())).object(); } else if (PythonQt::priv()->isPythonQtObjectPtrMetaId(variant.userType())) { @@ -123,7 +132,7 @@ bool PythonQtObjectPtr::fromVariant(const QVariant& variant) return true; } else { - setObject(NULL); + setObject(nullptr); return false; } } @@ -136,19 +145,15 @@ QVariant PythonQtObjectPtr::toVariant() PythonQtObjectPtr & PythonQtObjectPtr::operator=(PythonQtSafeObjectPtr &&p) { - if (_object) { - setObject(NULL); - } - _object = p.takeObject(); + Py_XSETREF(_object, p.takeObject()); return *this; } void PythonQtObjectPtr::setObject(PyObject* o) { if (o != _object) { - if (_object) Py_DECREF(_object); - _object = o; - if (_object) Py_INCREF(_object); + Py_XINCREF(o); + Py_XSETREF(_object, o); } } @@ -159,7 +164,7 @@ PythonQtSafeObjectPtr::PythonQtSafeObjectPtr(PyObject* o) _object = o; if (o) { PYTHONQT_GIL_SCOPE - Py_INCREF(_object); + Py_INCREF(o); } } @@ -167,7 +172,7 @@ PythonQtSafeObjectPtr::~PythonQtSafeObjectPtr() { if (_object) { PYTHONQT_GIL_SCOPE - Py_DECREF(_object); + if (_object && Py_IsInitialized()) Py_DECREF(_object); } } @@ -175,18 +180,16 @@ void PythonQtSafeObjectPtr::setObject(PyObject* o) { if (o != _object) { PYTHONQT_GIL_SCOPE - if (_object) Py_DECREF(_object); - _object = o; - if (_object) Py_INCREF(_object); + Py_XINCREF(o); + Py_XSETREF(_object, o); } } void PythonQtSafeObjectPtr::setObjectUnsafe(PyObject* o) { if (o != _object) { - if (_object) Py_DECREF(_object); - _object = o; - if (_object) Py_INCREF(_object); + Py_XINCREF(o); + Py_XSETREF(_object, o); } } diff --git a/src/PythonQtObjectPtr.h b/src/PythonQtObjectPtr.h index 0300e7df..84e6ed70 100644 --- a/src/PythonQtObjectPtr.h +++ b/src/PythonQtObjectPtr.h @@ -56,15 +56,15 @@ class PythonQtSafeObjectPtr; class PYTHONQT_EXPORT PythonQtObjectPtr { public: - PythonQtObjectPtr():_object(NULL) {} + PythonQtObjectPtr():_object(nullptr) {} PythonQtObjectPtr(const PythonQtObjectPtr &p) - :_object(NULL) { + :_object(nullptr) { setObject(p.object()); } //! rvalue copy constructor, does not need any incref/decref. - PythonQtObjectPtr(PythonQtObjectPtr &&p) + PythonQtObjectPtr(PythonQtObjectPtr &&p) noexcept :_object(p.takeObject()) { } @@ -72,14 +72,14 @@ class PYTHONQT_EXPORT PythonQtObjectPtr PythonQtObjectPtr(PythonQtSafeObjectPtr &&p); //! If the given variant holds a PythonQtObjectPtr, extract the value from it and hold onto the reference. This results in an increment of the reference count. - PythonQtObjectPtr(const QVariant& variant):_object(NULL) { + PythonQtObjectPtr(const QVariant& variant):_object(nullptr) { fromVariant(variant); } PythonQtObjectPtr(PyObject* o); - + ~PythonQtObjectPtr(); - + //! If the given variant holds a PythonQtObjectPtr, extract the value from it and hold onto the reference. This results in an increment of the reference count. bool fromVariant(const QVariant& variant); @@ -95,9 +95,9 @@ class PYTHONQT_EXPORT PythonQtObjectPtr } //! rvalue assignment operator that steals the reference from p - PythonQtObjectPtr &operator=(PythonQtObjectPtr &&p) { + PythonQtObjectPtr &operator=(PythonQtObjectPtr &&p) noexcept { if (_object) { - setObject(NULL); + setObject(nullptr); } _object = p.takeObject(); return *this; @@ -144,7 +144,7 @@ class PYTHONQT_EXPORT PythonQtObjectPtr //! sets the object and passes the ownership (stealing the reference, in Python slang) void setNewRef(PyObject* o); - + PyObject* object() const { return _object; } @@ -181,14 +181,14 @@ class PYTHONQT_EXPORT PythonQtObjectPtr //! the caller has to take care about the decref of the taken object! PyObject* takeObject() { PyObject* o = _object; - _object = NULL; + _object = nullptr; return o; } protected: void setObject(PyObject* o); - + private: PyObject* _object; }; @@ -197,22 +197,22 @@ class PYTHONQT_EXPORT PythonQtObjectPtr class PYTHONQT_EXPORT PythonQtSafeObjectPtr { public: - PythonQtSafeObjectPtr() :_object(NULL) {} + PythonQtSafeObjectPtr() :_object(nullptr) {} PythonQtSafeObjectPtr(const PythonQtSafeObjectPtr &p) - :_object(NULL) { + :_object(nullptr) { setObject(p.object()); } PythonQtSafeObjectPtr(const PythonQtObjectPtr &p) - :_object(NULL) { + :_object(nullptr) { setObject(p.object()); } //! rvalue copy constructor, does not need any incref/decref. - PythonQtSafeObjectPtr(PythonQtSafeObjectPtr &&p) + PythonQtSafeObjectPtr(PythonQtSafeObjectPtr &&p) noexcept :_object(p._object) { - p._object = NULL; + p._object = nullptr; } //! rvalue copy constructor, does not need any incref/decref. @@ -235,19 +235,19 @@ class PYTHONQT_EXPORT PythonQtSafeObjectPtr } //! rvalue assignment operator that steals the reference from p - PythonQtSafeObjectPtr &operator=(PythonQtSafeObjectPtr &&p) { + PythonQtSafeObjectPtr &operator=(PythonQtSafeObjectPtr &&p) noexcept { if (_object) { - setObject(NULL); + setObject(nullptr); } _object = p._object; - p._object = NULL; + p._object = nullptr; return *this; } //! rvalue assignment operator that steals the reference from p PythonQtSafeObjectPtr &operator=(PythonQtObjectPtr &&p) { if (_object) { - setObjectUnsafe(NULL); + setObjectUnsafe(nullptr); } _object = p.takeObject(); return *this; @@ -290,7 +290,7 @@ class PYTHONQT_EXPORT PythonQtSafeObjectPtr //! the caller has to take care about the decref of the taken object! PyObject* takeObject() { PyObject* o = _object; - _object = NULL; + _object = nullptr; return o; } diff --git a/src/PythonQtProperty.cpp b/src/PythonQtProperty.cpp index af306e99..b63ebe3b 100644 --- a/src/PythonQtProperty.cpp +++ b/src/PythonQtProperty.cpp @@ -40,7 +40,7 @@ int PythonQtProperty_init(PyObject *object, PyObject *args, PyObject *kw) self->data = new PythonQtPropertyData(); PythonQtPropertyData* data = self->data; - PyObject* type = 0; + PyObject* type = nullptr; static const char *kwlist[] = { "type", @@ -48,7 +48,7 @@ int PythonQtProperty_init(PyObject *object, PyObject *args, PyObject *kw) "doc", "designable", "scriptable", "stored", "user", "constant", "final", "notify", - 0 + nullptr }; if (!PyArg_ParseTupleAndKeywords(args, kw, @@ -69,19 +69,19 @@ int PythonQtProperty_init(PyObject *object, PyObject *args, PyObject *kw) } if (data->fget == Py_None) { - data->fget = NULL; + data->fget = nullptr; } if (data->fset == Py_None) { - data->fset = NULL; + data->fset = nullptr; } if (data->freset == Py_None) { - data->freset = NULL; + data->freset = nullptr; } if (data->fdel == Py_None) { - data->fdel = NULL; + data->fdel = nullptr; } if (data->doc == Py_None) { - data->doc = NULL; + data->doc = nullptr; } if (data->fdel) { std::cerr << "Property: fdel is not yet supported!" << std::endl; @@ -109,7 +109,7 @@ void PythonQtProperty_dealloc(PyObject* object) Py_CLEAR(self->data->doc); delete self->data; - self->data = NULL; + self->data = nullptr; Py_TYPE(object)->tp_free(object); } @@ -128,7 +128,7 @@ PyObject* PythonQtProperty_setter(PyObject* object, PyObject* func) return object; } else { PyErr_SetString(PyExc_TypeError, "Property needs a callable as fset."); - return 0; + return nullptr; } } @@ -147,18 +147,19 @@ PyObject* PythonQtProperty_getter(PyObject* object, PyObject* func) return object; } else { PyErr_SetString(PyExc_TypeError, "Property needs a callable as fget."); - return 0; + return nullptr; } } PyObject* PythonQtProperty_call(PyObject* object, PyObject* args, PyObject* kw) { + Q_UNUSED(kw) if (PyTuple_Size(args) == 1) { PyObject *func = PyTuple_GetItem(args, 0); return PythonQtProperty_getter(object, func); } else { PyErr_SetString(PyExc_TypeError, "Property expects a single callable."); - return 0; + return nullptr; } } @@ -167,7 +168,7 @@ static PyMethodDef PythonQtProperty_methods[] = { { "getter", (PyCFunction)PythonQtProperty_getter, METH_O, "Sets the fget function." }, { "write", (PyCFunction)PythonQtProperty_setter, METH_O, "Sets the fset function." }, { "read", (PyCFunction)PythonQtProperty_getter, METH_O, "Sets the fget function." }, - { NULL, NULL, 0, NULL } /* Sentinel */ + { nullptr, nullptr, 0, nullptr } /* Sentinel */ }; @@ -184,8 +185,8 @@ static PyObject *PythonQtProperty_get_doc(PythonQtProperty* self, void * /*closu } static PyGetSetDef PythonQtProperty_getsets[] = { - { const_cast("__doc__"), (getter)PythonQtProperty_get_doc, NULL, NULL }, - { NULL, NULL, NULL,NULL }, + { const_cast("__doc__"), (getter)PythonQtProperty_get_doc, nullptr, nullptr }, + { nullptr, nullptr, nullptr,nullptr }, }; PyDoc_STRVAR(PythonQtProperty_doc, @@ -199,47 +200,47 @@ PyTypeObject PythonQtProperty_Type = { sizeof(PythonQtProperty), /*tp_basicsize*/ 0, /*tp_itemsize*/ PythonQtProperty_dealloc, /*tp_dealloc*/ - 0, /*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_vectorcall_offset*/ + nullptr, /*tp_getattr*/ + nullptr, /*tp_setattr*/ + nullptr, /*tp_compare*/ + nullptr, /*tp_repr*/ + nullptr, /*tp_as_number*/ + nullptr, /*tp_as_sequence*/ + nullptr, /*tp_as_mapping*/ + nullptr, /*tp_hash */ PythonQtProperty_call, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + nullptr, /*tp_str*/ + nullptr, /*tp_getattro*/ + nullptr, /*tp_setattro*/ + nullptr, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ PythonQtProperty_doc, /*tp_doc */ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ + nullptr, /*tp_traverse */ + nullptr, /*tp_clear */ + nullptr, /*tp_richcompare */ 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ + nullptr, /*tp_iter */ + nullptr, /*tp_iternext */ PythonQtProperty_methods, /*tp_methods */ - 0, /*tp_members */ + nullptr, /*tp_members */ PythonQtProperty_getsets, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ + nullptr, /*tp_base */ + nullptr, /*tp_dict */ + nullptr, /*tp_descr_get */ + nullptr, /*tp_descr_set */ 0, /*tp_dictoffset */ PythonQtProperty_init, /*tp_init */ - 0, /*tp_alloc */ + nullptr, /*tp_alloc */ PyType_GenericNew, /*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 */ + nullptr, /*tp_free */ + nullptr, /*tp_is_gc */ + nullptr, /*tp_bases */ + nullptr, /*tp_mro */ + nullptr, /*tp_cache */ + nullptr, /*tp_subclasses */ + nullptr, /*tp_weaklist */ + nullptr, /*tp_del */ }; bool PythonQtPropertyData::callSetter(PyObject* wrapper, PyObject* newValue) @@ -253,7 +254,7 @@ bool PythonQtPropertyData::callSetter(PyObject* wrapper, PyObject* newValue) PyObject* result = PyObject_CallObject(fset, pyargs); - bool ok = (result != NULL); + bool ok = (result != nullptr); Py_XDECREF(result); Py_DECREF(pyargs); return ok; @@ -274,7 +275,7 @@ PyObject* PythonQtPropertyData::callGetter(PyObject* wrapper) return value; } else { PyErr_Format(PyExc_TypeError, "Property is write only."); - return NULL; + return nullptr; } } @@ -285,7 +286,7 @@ bool PythonQtPropertyData::callReset(PyObject* wrapper) PyTuple_SET_ITEM(pyargs, 0, wrapper); Py_INCREF(wrapper); PyObject* result = PyObject_CallObject(freset, pyargs); - bool ok = (result != NULL); + bool ok = (result != nullptr); Py_XDECREF(result); Py_DECREF(pyargs); return ok; diff --git a/src/PythonQtProperty.h b/src/PythonQtProperty.h index 5bb59418..ef4d6a3c 100644 --- a/src/PythonQtProperty.h +++ b/src/PythonQtProperty.h @@ -46,12 +46,12 @@ extern PYTHONQT_EXPORT PyTypeObject PythonQtProperty_Type; struct PythonQtPropertyData { PythonQtPropertyData() { - fget = NULL; - fset = NULL; - fdel = NULL; - freset = NULL; - notify = NULL; - doc = NULL; + fget = nullptr; + fset = nullptr; + fdel = nullptr; + freset = nullptr; + notify = nullptr; + doc = nullptr; designable = true; scriptable = true; stored = true; @@ -88,7 +88,7 @@ struct PythonQtPropertyData bool final; }; -typedef struct { +struct PythonQtProperty { PyObject_HEAD PythonQtPropertyData* data; -} PythonQtProperty; +}; diff --git a/src/PythonQtPythonInclude.h b/src/PythonQtPythonInclude.h index f4c012f6..ca915666 100644 --- a/src/PythonQtPythonInclude.h +++ b/src/PythonQtPythonInclude.h @@ -33,10 +33,14 @@ #ifndef __PythonQtPythonInclude_h #define __PythonQtPythonInclude_h -// Undefine macros that Python.h defines to avoid redefinition warning. -#undef _POSIX_C_SOURCE -#undef _POSIX_THREADS -#undef _XOPEN_SOURCE +// Undefine macros that features.h defines to avoid redefinition warning +#ifdef _POSIX_C_SOURCE +# undef _POSIX_C_SOURCE +#endif + +#ifdef _XOPEN_SOURCE +# undef _XOPEN_SOURCE +#endif // Undefine Qt keywords that conflict with Python headers #ifdef slots @@ -44,6 +48,14 @@ #define PYTHONQT_RESTORE_KEYWORDS #endif +//From https://github.com/boostorg/python/pull/253 +// Python.h defines a macro with hypot name, what breaks libstdc++ math header +// that it tries to include afterwards. +# if defined(__MINGW32__) +# include +# include +# endif + // // Use the real python debugging library if it is provided. // Otherwise use the "documented" trick involving checking for _DEBUG diff --git a/src/PythonQtQFileImporter.h b/src/PythonQtQFileImporter.h index 4cffb120..2510b12b 100644 --- a/src/PythonQtQFileImporter.h +++ b/src/PythonQtQFileImporter.h @@ -43,22 +43,22 @@ //---------------------------------------------------------------------------------- #include "PythonQtPythonInclude.h" -#include +#include "PythonQtImportFileInterface.h" //! default importer implementation using QFile to load python code class PythonQtQFileImporter : public PythonQtImportFileInterface { public: PythonQtQFileImporter(); - ~PythonQtQFileImporter(); + ~PythonQtQFileImporter() override; - QByteArray readFileAsBytes (const QString &filename); - - QByteArray readSourceFile (const QString &filename, bool &ok); - - bool exists (const QString &filename); - bool isEggArchive(const QString& filename); - - QDateTime lastModifiedDate (const QString &filename); + QByteArray readFileAsBytes (const QString &filename) override; + + QByteArray readSourceFile (const QString &filename, bool &ok) override; + + bool exists (const QString &filename) override; + bool isEggArchive(const QString& filename) override; + + QDateTime lastModifiedDate (const QString &filename) override; }; diff --git a/src/PythonQtSignal.cpp b/src/PythonQtSignal.cpp index f14408dc..04e19fee 100644 --- a/src/PythonQtSignal.cpp +++ b/src/PythonQtSignal.cpp @@ -56,7 +56,7 @@ //----------------------------------------------------------------------------------- -static PythonQtSignalFunctionObject *PythonQtSignal_free_list = NULL; +static PythonQtSignalFunctionObject *PythonQtSignal_free_list = nullptr; PyObject *PythonQtSignalFunction_Call(PyObject *func, PyObject *args, PyObject *kw) { @@ -66,7 +66,10 @@ PyObject *PythonQtSignalFunction_Call(PyObject *func, PyObject *args, PyObject * PyObject *PythonQtSignalFunction_tpNew(PyTypeObject *subtype, PyObject *args, PyObject *kwds) { - return PythonQtSignalFunction_New(NULL, NULL, NULL); + Q_UNUSED(subtype) + Q_UNUSED(args) + Q_UNUSED(kwds) + return PythonQtSignalFunction_New(nullptr, nullptr, nullptr); } PyObject * @@ -74,16 +77,16 @@ PythonQtSignalFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *modul { PythonQtSignalFunctionObject *op; op = PythonQtSignal_free_list; - if (op != NULL) { + if (op != nullptr) { PythonQtSignal_free_list = (PythonQtSignalFunctionObject *)(op->m_self); PyObject_INIT(op, &PythonQtSignalFunction_Type); } else { op = PyObject_GC_New(PythonQtSignalFunctionObject, &PythonQtSignalFunction_Type); - if (op == NULL) - return NULL; + if (op == nullptr) + return nullptr; } - op->_dynamicInfo = NULL; + op->_dynamicInfo = nullptr; op->m_ml = ml; Py_XINCREF(self); op->m_self = self; @@ -96,12 +99,13 @@ PythonQtSignalFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *modul /* Methods (the standard built-in methods, that is) */ static void -meth_dealloc(PythonQtSignalFunctionObject *m) +meth_dealloc(PyObject *o) { - PyObject_GC_UnTrack(m); + PyObject_GC_UnTrack(o); + auto m = reinterpret_cast(o); if (m->_dynamicInfo) { delete m->_dynamicInfo; - m->_dynamicInfo = NULL; + m->_dynamicInfo = nullptr; } Py_XDECREF(m->m_self); Py_XDECREF(m->m_module); @@ -130,12 +134,12 @@ static int meth_traverse(PythonQtSignalFunctionObject *m, visitproc visit, void *arg) { int err; - if (m->m_self != NULL) { + if (m->m_self != nullptr) { err = visit(m->m_self, arg); if (err) return err; } - if (m->m_module != NULL) { + if (m->m_module != nullptr) { err = visit(m->m_module, arg); if (err) return err; @@ -155,17 +159,17 @@ meth_get__self__(PythonQtSignalFunctionObject *m, void * /*closure*/) } #endif self = m->m_self; - if (self == NULL) + if (self == nullptr) self = Py_None; Py_INCREF(self); return self; } static PyGetSetDef meth_getsets [] = { - {const_cast("__doc__"), (getter)meth_get__doc__, NULL, NULL}, - {const_cast("__name__"), (getter)meth_get__name__, NULL, NULL}, - {const_cast("__self__"), (getter)meth_get__self__, NULL, NULL}, - {NULL, NULL, NULL,NULL}, + {const_cast("__doc__"), (getter)meth_get__doc__, nullptr, nullptr}, + {const_cast("__name__"), (getter)meth_get__name__, nullptr, nullptr}, + {const_cast("__self__"), (getter)meth_get__self__, nullptr, nullptr}, + {nullptr, nullptr, nullptr,nullptr}, }; #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6 @@ -176,11 +180,12 @@ static PyGetSetDef meth_getsets [] = { static PyMemberDef meth_members[] = { {const_cast("__module__"), T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED}, - {NULL} + {nullptr} }; int PythonQtSignalFunction_init(PyObject *object, PyObject *args, PyObject *kw) { + Q_UNUSED(kw) PythonQtSignalFunctionObject* self = (PythonQtSignalFunctionObject*)object; self->_dynamicInfo = new PythonQtDynamicSignalInfo(); @@ -261,7 +266,7 @@ static PyObject *PythonQtSignalFunction_connect(PythonQtSignalFunctionObject* ty } } } - return NULL; + return nullptr; } static PyObject *PythonQtSignalFunction_disconnect(PythonQtSignalFunctionObject* type, PyObject *args) @@ -277,43 +282,43 @@ static PyObject *PythonQtSignalFunction_disconnect(PythonQtSignalFunctionObject* bool result = PythonQt::self()->removeSignalHandler(self->_obj, signal, callable); return PythonQtConv::GetPyBool(result); } else if (argc==0) { - bool result = PythonQt::self()->removeSignalHandler(self->_obj, signal, NULL); - result |= QObject::disconnect(self->_obj, signal, NULL, NULL); + bool result = PythonQt::self()->removeSignalHandler(self->_obj, signal, nullptr); + result |= QObject::disconnect(self->_obj, signal, nullptr, nullptr); return PythonQtConv::GetPyBool(result); } else { PyErr_SetString(PyExc_ValueError, "Called disconnect with wrong number of arguments"); } } } - return NULL; + return nullptr; } static PyObject *PythonQtSignalFunction_emit(PythonQtSignalFunctionObject* func, PyObject *args) { PythonQtSignalFunctionObject* f = (PythonQtSignalFunctionObject*)func; - return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, NULL); + return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, nullptr); } static PyMethodDef meth_methods[] = { - {"parameterTypes", (PyCFunction)PythonQtSignalFunction_parameterTypes, METH_NOARGS, + {"parameterTypes", reinterpret_cast(reinterpret_cast(PythonQtSignalFunction_parameterTypes)), METH_NOARGS, "Returns a tuple of tuples of the C++ parameter types for all overloads of the signal" }, - {"parameterNames", (PyCFunction)PythonQtSignalFunction_parameterNames, METH_NOARGS, + {"parameterNames", reinterpret_cast(reinterpret_cast(PythonQtSignalFunction_parameterNames)), METH_NOARGS, "Returns a tuple of tuples of the C++ parameter type names (if available), for all overloads of the signal" }, - {"typeName", (PyCFunction)PythonQtSignalFunction_typeName, METH_NOARGS, + {"typeName", reinterpret_cast(reinterpret_cast(PythonQtSignalFunction_typeName)), METH_NOARGS, "Returns a tuple of the C++ return value types of each signal overload" }, - {"connect", (PyCFunction)PythonQtSignalFunction_connect, METH_VARARGS, + {"connect", reinterpret_cast(reinterpret_cast(PythonQtSignalFunction_connect)), METH_VARARGS, "Connects the signal to the Python callable" }, - {"disconnect", (PyCFunction)PythonQtSignalFunction_disconnect, METH_VARARGS, + {"disconnect", reinterpret_cast(reinterpret_cast(PythonQtSignalFunction_disconnect)), METH_VARARGS, "Disconnects the signal from the given Python callable or disconnects all if no argument is passed." }, - {"emit", (PyCFunction)PythonQtSignalFunction_emit, METH_VARARGS, + {"emit", reinterpret_cast(reinterpret_cast(PythonQtSignalFunction_emit)), METH_VARARGS, "Emits the signal with given arguments" }, - {NULL, NULL, 0 , NULL} /* Sentinel */ + {nullptr, nullptr, 0 , nullptr} /* Sentinel */ }; static PyObject * @@ -326,11 +331,11 @@ meth_repr(PythonQtSignalFunctionObject *f) if (f->m_self->ob_type == &PythonQtClassWrapper_Type) { PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self; return PyString_FromFormat("", - f->m_ml->slotName().data(), + f->m_ml->slotName().constData(), self->classInfo()->className().constData()); } else { return PyString_FromFormat("", - f->m_ml->slotName().data(), + f->m_ml->slotName().constData(), f->m_self->ob_type->tp_name, f->m_self); } @@ -353,7 +358,7 @@ static long meth_hash(PythonQtSignalFunctionObject *a) { long x,y; - if (a->m_self == NULL) + if (a->m_self == nullptr) x = 0; else { x = PyObject_Hash(a->m_self); @@ -374,7 +379,7 @@ static PyObject* meth_richcompare(PythonQtSignalFunctionObject *a, PythonQtSignalFunctionObject *b, int op) { int x = meth_compare(a, b); - bool r; + bool r = false; if (op == Py_LT) r = x < 0; else if (op == Py_LE) @@ -401,53 +406,53 @@ PyTypeObject PythonQtSignalFunction_Type = { "QtCore.Signal", sizeof(PythonQtSignalFunctionObject), 0, - (destructor)meth_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ + (destructor)meth_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + nullptr, /* tp_getattr */ + nullptr, /* tp_setattr */ #ifdef PY3K - 0, + nullptr, #else - (cmpfunc)meth_compare, /* tp_compare */ + (cmpfunc)meth_compare, /* tp_compare */ #endif (reprfunc)meth_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ + nullptr, /* tp_as_number */ + nullptr, /* tp_as_sequence */ // TODO: implement tp_as_mapping to support overload resolution on the signal - 0, /* tp_as_mapping */ + nullptr, /* tp_as_mapping */ (hashfunc)meth_hash, /* tp_hash */ - PythonQtSignalFunction_Call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ + PythonQtSignalFunction_Call, /* tp_call */ + nullptr, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + nullptr, /* tp_setattro */ + nullptr, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - PythonQtSignalFunction_doc, /* tp_doc */ + PythonQtSignalFunction_doc, /* tp_doc */ (traverseproc)meth_traverse, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)meth_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - meth_methods, /* tp_methods */ - meth_members, /* tp_members */ - meth_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ + nullptr, /* tp_clear */ + (richcmpfunc)meth_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + nullptr, /* tp_iter */ + nullptr, /* tp_iternext */ + meth_methods, /* tp_methods */ + meth_members, /* tp_members */ + meth_getsets, /* tp_getset */ + nullptr, /* tp_base */ + nullptr, /* tp_dict */ + nullptr, /*tp_descr_get */ + nullptr, /*tp_descr_set */ + 0, /*tp_dictoffset */ PythonQtSignalFunction_init, /*tp_init */ - 0, /*tp_alloc */ - PythonQtSignalFunction_tpNew, /*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 */ + nullptr, /*tp_alloc */ + PythonQtSignalFunction_tpNew, /*tp_new */ + nullptr, /*tp_free */ + nullptr, /*tp_is_gc */ + nullptr, /*tp_bases */ + nullptr, /*tp_mro */ + nullptr, /*tp_cache */ + nullptr, /*tp_subclasses */ + nullptr, /*tp_weaklist */ + nullptr, /*tp_del */ }; diff --git a/src/PythonQtSignal.h b/src/PythonQtSignal.h index 143547ae..9e0165dd 100644 --- a/src/PythonQtSignal.h +++ b/src/PythonQtSignal.h @@ -63,13 +63,13 @@ struct PythonQtDynamicSignalInfo }; //! defines a python object that stores a Qt signal info -typedef struct { +struct PythonQtSignalFunctionObject { PyObject_HEAD PythonQtSlotInfo *m_ml; /* Description of the C function to call */ PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */ PyObject *m_module; /* The __module__ attribute, can be anything */ PythonQtDynamicSignalInfo* _dynamicInfo; -} PythonQtSignalFunctionObject; +}; #endif diff --git a/src/PythonQtSignalReceiver.cpp b/src/PythonQtSignalReceiver.cpp index f09a2b07..2fe6e4b0 100644 --- a/src/PythonQtSignalReceiver.cpp +++ b/src/PythonQtSignalReceiver.cpp @@ -45,7 +45,6 @@ #include "PythonQtConversion.h" #include #include -#include "funcobject.h" // use -2 to signal that the variable is uninitialized int PythonQtSignalReceiver::_destroyedSignal1Id = -2; @@ -55,6 +54,7 @@ void PythonQtSignalTarget::call(void **arguments) const { PYTHONQT_GIL_SCOPE PyObject* result = call(_callable, methodInfo(), arguments); if (result) { + PythonQt::priv()->checkAndRunCoroutine(result); Py_DECREF(result); } } @@ -100,7 +100,7 @@ PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf } } - PyObject* pargs = NULL; + PyObject* pargs = nullptr; if (count>1) { pargs = PyTuple_New(count-1); } @@ -117,14 +117,14 @@ PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf } if (arg) { // steals reference, no unref - PyTuple_SetItem(pargs, i-1,arg); + PyTuple_SetItem(pargs, i-1, arg); } else { err = true; break; } } - PyObject* result = NULL; + PyObject* result = nullptr; if (!err) { PyErr_Clear(); result = PyObject_CallObject(callable, pargs); @@ -198,7 +198,7 @@ bool PythonQtSignalReceiver::addSignalHandler(const char* signal, PyObject* call PythonQtSignalTarget t(sigId, signalInfo, _slotCount, callable); _targets.append(t); // now connect to ourselves with the new slot id - QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, 0); + QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, nullptr); _slotCount++; flag = true; @@ -240,7 +240,7 @@ bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* c } } } - if ((foundCount>0) && (sigId == _destroyedSignal1Id) || (sigId == _destroyedSignal2Id)) { + if ((foundCount>0) && ((sigId == _destroyedSignal1Id) || (sigId == _destroyedSignal2Id))) { _destroyedSignalCount -= foundCount; if (_destroyedSignalCount==0) { // make ourself child of QObject again, to get deleted when the object gets deleted @@ -268,11 +268,11 @@ int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **argu } bool shouldDelete = false; - for(const PythonQtSignalTarget& t : _targets) { + for(const PythonQtSignalTarget& t : qAsConst(_targets)) { if (t.slotId() == id) { + const int sigId = t.signalId(); t.call(arguments); // if the signal is the last destroyed signal, we delete ourselves - int sigId = t.signalId(); if ((sigId == _destroyedSignal1Id) || (sigId == _destroyedSignal2Id)) { _destroyedSignalCount--; if (_destroyedSignalCount == 0) { diff --git a/src/PythonQtSignalReceiver.h b/src/PythonQtSignalReceiver.h index 16682cf2..d0b6b491 100644 --- a/src/PythonQtSignalReceiver.h +++ b/src/PythonQtSignalReceiver.h @@ -57,7 +57,7 @@ class PYTHONQT_EXPORT PythonQtSignalTarget { public: PythonQtSignalTarget() { _signalId = -1; - _methodInfo = NULL; + _methodInfo = nullptr; _slotId = -1; } @@ -94,7 +94,7 @@ class PYTHONQT_EXPORT PythonQtSignalTarget { int _signalId; int _slotId; const PythonQtMethodInfo* _methodInfo; - PythonQtObjectPtr _callable; + PythonQtSafeObjectPtr _callable; }; //! base class for signal receivers @@ -113,16 +113,16 @@ class PythonQtSignalReceiver : public PythonQtSignalReceiverBase { public: PythonQtSignalReceiver(QObject* obj); - ~PythonQtSignalReceiver(); + ~PythonQtSignalReceiver() override; //! add a signal handler bool addSignalHandler(const char* signal, PyObject* callable); //! remove a signal handler for given callable (or all callables on that signal if callable is NULL) - bool removeSignalHandler(const char* signal, PyObject* callable = NULL); + bool removeSignalHandler(const char* signal, PyObject* callable = nullptr); //! we implement this method to simulate a number of slots that match the ids in _targets - virtual int qt_metacall(QMetaObject::Call c, int id, void **arguments); + int qt_metacall(QMetaObject::Call c, int id, void **arguments) override; private: //! get the index of the signal diff --git a/src/PythonQtSlot.cpp b/src/PythonQtSlot.cpp index 5a99101c..45878aca 100644 --- a/src/PythonQtSlot.cpp +++ b/src/PythonQtSlot.cpp @@ -59,13 +59,13 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer, PythonQtPassThisOwnershipType* passThisOwnershipToCPP) { if (directReturnValuePointer) { - *directReturnValuePointer = NULL; + *directReturnValuePointer = nullptr; } PythonQtArgumentFrame* frame = PythonQtArgumentFrame::newFrame(); // the arguments that are passed to qt_metacall void* argList[PYTHONQT_MAX_ARGS]; - PyObject* result = NULL; + PyObject* result = nullptr; int argc = info->parameterCount(); const QList& params = info->parameters(); @@ -73,7 +73,7 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj bool isVoidReturnValue = (returnValueParam.typeId == QMetaType::Void); // set return argument to NULL - argList[0] = NULL; + argList[0] = nullptr; bool ok = true; PythonQtPassThisOwnershipType passThisOwnership = IgnoreOwnership; @@ -81,7 +81,7 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj int instanceDecoOffset = 0; // it is important to keep arg1 on this scope, because it is stored in argList[1] and // would go away if it is moved into the if scope - void* arg1 = NULL; + void* arg1 = nullptr; if (info->isInstanceDecorator()) { instanceDecoOffset = 1; @@ -99,14 +99,14 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj } for (int i = 1 + instanceDecoOffset; i pass ownership of this to someObject) - if (argList[i] && (*(void**)argList[i])==NULL) { + if (argList[i] && (*(void**)argList[i])==nullptr) { // if the object to which the ownership should be passed is NULL, // we need to pass the ownership to Python passThisOwnership = PassOwnershipToPython; @@ -128,14 +128,14 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj if (!directReturnValuePointer) { // create empty default value for the return value argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam, frame); - if (argList[0]==NULL) { + if (argList[0]==nullptr) { // return value could not be created, maybe we have a registered class with a default constructor, so that we can construct the pythonqt wrapper object and // pass its internal pointer PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name); if (info && info->pythonQtClassWrapper()) { PyObject* emptyTuple = PyTuple_New(0); // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments - result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL); + result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, nullptr); if (result) { argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr; } @@ -151,7 +151,7 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB(); if (profilingCB) { - const char* className = NULL; + const char* className = nullptr; if (info->decorator()) { className = info->decorator()->metaObject()->className(); } else { @@ -208,14 +208,14 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj } if (profilingCB) { - profilingCB(PythonQt::Leave, NULL, NULL, NULL); + profilingCB(PythonQt::Leave, nullptr, nullptr, nullptr); } // handle the return value (which in most cases still needs to be converted to a Python object) if (!hadException) { if (argList[0] || isVoidReturnValue) { if (directReturnValuePointer) { - result = NULL; + result = nullptr; } else { // the resulting object maybe present already, because we created it above at 1)... if (!result) { @@ -225,11 +225,11 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj } else { QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probably you should register it using qRegisterMetaType() or add a default constructor decorator to the class."; PyErr_SetString(PyExc_ValueError, QStringToPythonConstCharPointer(e)); - result = NULL; + result = nullptr; ok = false; } } else { - result = NULL; + result = nullptr; ok = false; } } @@ -256,7 +256,7 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj //----------------------------------------------------------------------------------- -static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL; +static PythonQtSlotFunctionObject *pythonqtslot_free_list = nullptr; PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw) { @@ -268,13 +268,13 @@ PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, { if (PyObject_TypeCheck(m_self, &PythonQtInstanceWrapper_Type)) { PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) m_self; - if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) { + if (!info->isClassDecorator() && (self->_obj==nullptr && self->_wrappedPtr==nullptr)) { QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object"; PyErr_SetString(PyExc_ValueError, QStringToPythonConstCharPointer(error)); - return NULL; + return nullptr; } else { PythonQtPassThisOwnershipType ownership; - PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr, NULL, &ownership); + PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr, nullptr, &ownership); if (ownership == PassOwnershipToCPP) { self->passOwnershipToCPP(); } else if (ownership == PassOwnershipToPython) { @@ -285,7 +285,7 @@ PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, } else if (m_self->ob_type == &PythonQtClassWrapper_Type) { PythonQtClassWrapper* type = (PythonQtClassWrapper*) m_self; if (info->isClassDecorator()) { - return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw); + return PythonQtSlotFunction_CallImpl(type->classInfo(), nullptr, info, args, kw); } else { // otherwise, it is an unbound call and we have an instanceDecorator or normal slot... Py_ssize_t argc = PyTuple_Size(args); @@ -294,15 +294,15 @@ PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type) && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) { PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg; - if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) { + if (!info->isClassDecorator() && (self->_obj==nullptr && self->_wrappedPtr==nullptr)) { QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object"; PyErr_SetString(PyExc_ValueError, QStringToPythonConstCharPointer(error)); - return NULL; + return nullptr; } // strip the first argument... PyObject* newargs = PyTuple_GetSlice(args, 1, argc); PythonQtPassThisOwnershipType ownership; - PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr, NULL, &ownership); + PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr, nullptr, &ownership); if (ownership == PassOwnershipToCPP) { self->passOwnershipToCPP(); } else if (ownership == PassOwnershipToPython) { @@ -314,19 +314,33 @@ PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, // first arg is not of correct type! QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name; PyErr_SetString(PyExc_ValueError, QStringToPythonConstCharPointer(error)); - return NULL; + return nullptr; } } else { // wrong number of args QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument."; PyErr_SetString(PyExc_ValueError, QStringToPythonConstCharPointer(error)); - return NULL; + return nullptr; } } } - return NULL; + return nullptr; } +namespace { + QString limitString(const QString& aString, int maxLength = 2000, const QString& ellipsis = "...") + { + if (aString.length() <= maxLength) + return aString; + + const int beforeSize = (maxLength - ellipsis.length()) / 2; + auto beforeEllipsis = aString.left(beforeSize); + auto afterEllipsis = aString.right(maxLength - ellipsis.length() - beforeSize); + + return beforeEllipsis + ellipsis + afterEllipsis; + } +}; + PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * kw, void* firstArg, void** directReturnValuePointer, PythonQtPassThisOwnershipType* passThisOwnershipToCPP) { int argc = args?PyTuple_Size(args):0; @@ -335,14 +349,14 @@ PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* o *passThisOwnershipToCPP = IgnoreOwnership; } - PyObject* r = NULL; + PyObject* r = nullptr; bool ok = false; if (directReturnValuePointer) { - *directReturnValuePointer = NULL; + *directReturnValuePointer = nullptr; } - if( (kw != NULL && PyDict_Check(kw) && (PyDict_Size(kw) > 0)) ) { + if( (kw != nullptr && PyDict_Check(kw) && (PyDict_Size(kw) > 0)) ) { // -------------------keyword args slot call ------------------------- // keyword arguments are given as dict, must be mapped to arguments in correct order @@ -372,6 +386,7 @@ PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* o kwSlotFound = true; break; } + slotInfo = slotInfo->nextInfo(); } if (kwSlotFound) { #ifdef PYTHONQT_DEBUG @@ -380,7 +395,7 @@ PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* o ok = PythonQtCallSlot(classInfo, objectToCall, combinedArgs, false, slotInfo, firstArg, &r, directReturnValuePointer, passThisOwnershipToCPP); if (!ok && !PyErr_Occurred()) { - QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args); + QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + limitString(PythonQtConv::PyObjGetString(args)); PyErr_SetString(PyExc_ValueError, QStringToPythonConstCharPointer(e)); } } else { @@ -412,7 +427,7 @@ PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* o } } if (!ok && !PyErr_Occurred()) { - QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n"); + QString e = QString("Could not find matching overload for given arguments:\n" + limitString(PythonQtConv::PyObjGetString(args)) + "\n The following slots are available:\n"); PythonQtSlotInfo* i = info; while (i) { e += QString(i->fullSignature()) + "\n"; @@ -430,11 +445,11 @@ PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* o #endif ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer, passThisOwnershipToCPP); if (!ok && !PyErr_Occurred()) { - QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args); + QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + limitString(PythonQtConv::PyObjGetString(args)); PyErr_SetString(PyExc_ValueError, QStringToPythonConstCharPointer(e)); } } else { - QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args); + QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + limitString(PythonQtConv::PyObjGetString(args)); PyErr_SetString(PyExc_ValueError, QStringToPythonConstCharPointer(e)); } } @@ -448,14 +463,14 @@ PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module) { PythonQtSlotFunctionObject *op; op = pythonqtslot_free_list; - if (op != NULL) { + if (op != nullptr) { pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self); PyObject_INIT(op, &PythonQtSlotFunction_Type); } else { op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type); - if (op == NULL) - return NULL; + if (op == nullptr) + return nullptr; } op->m_ml = ml; Py_XINCREF(self); @@ -471,7 +486,7 @@ PythonQtSlotFunction_GetSlotInfo(PyObject *op) { if (!PythonQtSlotFunction_Check(op)) { PyErr_Format(PyExc_SystemError, "%s:%d: bad argument to internal function", __FILE__, __LINE__); - return NULL; + return nullptr; } return ((PythonQtSlotFunctionObject *)op) -> m_ml; } @@ -481,7 +496,7 @@ PythonQtSlotFunction_GetSelf(PyObject *op) { if (!PythonQtSlotFunction_Check(op)) { PyErr_Format(PyExc_SystemError, "%s:%d: bad argument to internal function", __FILE__, __LINE__); - return NULL; + return nullptr; } return ((PythonQtSlotFunctionObject *)op) -> m_self; } @@ -489,9 +504,10 @@ PythonQtSlotFunction_GetSelf(PyObject *op) /* Methods (the standard built-in methods, that is) */ static void -meth_dealloc(PythonQtSlotFunctionObject *m) +meth_dealloc(PyObject *o) { - PyObject_GC_UnTrack(m); + PyObject_GC_UnTrack(o); + auto m = static_cast(static_cast(o)); Py_XDECREF(m->m_self); Py_XDECREF(m->m_module); m->m_self = (PyObject *)pythonqtslot_free_list; @@ -524,7 +540,7 @@ meth_get__doc__(PythonQtSlotFunctionObject * m, void * /*closure*/) if (!names.at(i - 1).isEmpty()) { doc += names.at(i - 1); } else { - doc += QString('a' + i - firstArgOffset); + doc += QString(QChar((char) ('a' + i - firstArgOffset))).toLatin1(); } } doc += ")"; @@ -551,7 +567,8 @@ meth_get__doc__(PythonQtSlotFunctionObject * m, void * /*closure*/) pyReturnType = "float"; } else { PythonQtClassInfo* returnTypeClassInfo = PythonQt::priv()->getClassInfo(returnType); - if (returnTypeClassInfo) { + // a class wrapper does not necessarily need to exist + if (returnTypeClassInfo && returnTypeClassInfo->pythonQtClassWrapper()) { PyObject* s = PyObject_GetAttrString(returnTypeClassInfo->pythonQtClassWrapper(), "__module__"); if (s) { pyReturnType = QByteArray(PyString_AsString(s)) + "." + returnType; @@ -575,12 +592,12 @@ static int meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg) { int err; - if (m->m_self != NULL) { + if (m->m_self != nullptr) { err = visit(m->m_self, arg); if (err) return err; } - if (m->m_module != NULL) { + if (m->m_module != nullptr) { err = visit(m->m_module, arg); if (err) return err; @@ -596,21 +613,21 @@ meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/) if (PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "method.__self__ not accessible in restricted mode"); - return NULL; + return nullptr; } #endif self = m->m_self; - if (self == NULL) + if (self == nullptr) self = Py_None; Py_INCREF(self); return self; } static PyGetSetDef meth_getsets [] = { - {const_cast("__doc__"), (getter)meth_get__doc__, NULL, NULL}, - {const_cast("__name__"), (getter)meth_get__name__, NULL, NULL}, - {const_cast("__self__"), (getter)meth_get__self__, NULL, NULL}, - {NULL, NULL, NULL,NULL}, + {const_cast("__doc__"), (getter)meth_get__doc__, nullptr, nullptr}, + {const_cast("__name__"), (getter)meth_get__name__, nullptr, nullptr}, + {const_cast("__self__"), (getter)meth_get__self__, nullptr, nullptr}, + {nullptr, nullptr, nullptr,nullptr}, }; #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6 @@ -621,7 +638,7 @@ static PyGetSetDef meth_getsets [] = { static PyMemberDef meth_members[] = { {const_cast("__module__"), T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED}, - {NULL} + {nullptr} }; static PyObject *PythonQtSlotFunction_parameterTypes(PythonQtSlotFunctionObject* type) @@ -702,16 +719,16 @@ PyObject *PythonQtMemberFunction_typeName(PythonQtSlotInfo* theInfo) } static PyMethodDef meth_methods[] = { - {"parameterTypes", (PyCFunction)PythonQtSlotFunction_parameterTypes, METH_NOARGS, + {"parameterTypes", reinterpret_cast(reinterpret_cast(PythonQtSlotFunction_parameterTypes)), METH_NOARGS, "Returns a tuple of tuples of the C++ parameter types for all overloads of the slot" }, - {"parameterNames", (PyCFunction)PythonQtSlotFunction_parameterNames, METH_NOARGS, + {"parameterNames", reinterpret_cast(reinterpret_cast(PythonQtSlotFunction_parameterNames)), METH_NOARGS, "Returns a tuple of tuples of the C++ parameter type names (if available), for all overloads of the slot" }, - {"typeName", (PyCFunction)PythonQtSlotFunction_typeName, METH_NOARGS, + {"typeName", reinterpret_cast(reinterpret_cast(PythonQtSlotFunction_typeName)), METH_NOARGS, "Returns a tuple of the C++ return value types of each slot overload" }, - {NULL, NULL, 0 , NULL} /* Sentinel */ + {nullptr, nullptr, 0 , nullptr} /* Sentinel */ }; static PyObject * @@ -720,11 +737,11 @@ meth_repr(PythonQtSlotFunctionObject *f) if (f->m_self->ob_type == &PythonQtClassWrapper_Type) { PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self; return PyString_FromFormat("", - f->m_ml->slotName().data(), + f->m_ml->slotName().constData(), self->classInfo()->className().constData()); } else { return PyString_FromFormat("", - f->m_ml->slotName().data(), + f->m_ml->slotName().constData(), f->m_self->ob_type->tp_name, f->m_self); } @@ -747,7 +764,7 @@ static long meth_hash(PythonQtSlotFunctionObject *a) { long x,y; - if (a->m_self == NULL) + if (a->m_self == nullptr) x = 0; else { x = PyObject_Hash(a->m_self); @@ -787,43 +804,59 @@ meth_richcompare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b, i Py_RETURN_FALSE; } +static PyObject* +meth_descr_get(PyObject *descr, PyObject *obj, PyObject* type) +{ + Q_UNUSED(type) + if (PythonQtSlotFunction_Check(descr)) { + PythonQtSlotFunctionObject *slotObj = (PythonQtSlotFunctionObject*)descr; + return PythonQtSlotFunction_New(slotObj->m_ml, obj, NULL); + } + else { + // wrong type + Py_IncRef(descr); + return descr; + } +} + PyTypeObject PythonQtSlotFunction_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "builtin_qt_slot", sizeof(PythonQtSlotFunctionObject), 0, - (destructor)meth_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ + (destructor)meth_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + nullptr, /* tp_getattr */ + nullptr, /* tp_setattr */ #ifdef PY3K - 0, + nullptr, #else (cmpfunc)meth_compare, /* tp_compare */ #endif - (reprfunc)meth_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)meth_hash, /* tp_hash */ - PythonQtSlotFunction_Call, /* tp_call */ - 0, /* tp_str */ + (reprfunc)meth_repr, /* tp_repr */ + nullptr, /* tp_as_number */ + nullptr, /* tp_as_sequence */ + nullptr, /* tp_as_mapping */ + (hashfunc)meth_hash, /* tp_hash */ + PythonQtSlotFunction_Call, /* tp_call */ + nullptr, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ + nullptr, /* tp_setattro */ + nullptr, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)meth_traverse, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)meth_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - meth_methods, /* tp_methods */ - meth_members, /* tp_members */ - meth_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ + nullptr, /* tp_doc */ + (traverseproc)meth_traverse, /* tp_traverse */ + nullptr, /* tp_clear */ + (richcmpfunc)meth_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + nullptr, /* tp_iter */ + nullptr, /* tp_iternext */ + meth_methods, /* tp_methods */ + meth_members, /* tp_members */ + meth_getsets, /* tp_getset */ + nullptr, /* tp_base */ + nullptr, /* tp_dict */ + meth_descr_get, /* tp_descr_get */ }; /* Clear out the free list */ diff --git a/src/PythonQtSlot.h b/src/PythonQtSlot.h index 72db42f5..1040a922 100644 --- a/src/PythonQtSlot.h +++ b/src/PythonQtSlot.h @@ -70,7 +70,7 @@ PyObject* PythonQtSlotFunction_GetSelf(PyObject *); PyObject* PythonQtSlotFunction_Call(PyObject *, PyObject *, PyObject *); -PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL, void** directReturnValuePointer=NULL, PythonQtPassThisOwnershipType* passThisOwnershipToCPP = NULL); +PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=nullptr, void** directReturnValuePointer=nullptr, PythonQtPassThisOwnershipType* passThisOwnershipToCPP = nullptr); PyObject* PythonQtSlotFunction_New(PythonQtSlotInfo *, PyObject *, PyObject *); @@ -81,12 +81,12 @@ PyObject *PythonQtMemberFunction_parameterNames(PythonQtSlotInfo* theInfo); PyObject *PythonQtMemberFunction_typeName(PythonQtSlotInfo* theInfo); //! defines a python object that stores a Qt slot info -typedef struct { +struct PythonQtSlotFunctionObject { PyObject_HEAD PythonQtSlotInfo *m_ml; /* Description of the C function to call */ PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */ PyObject *m_module; /* The __module__ attribute, can be anything */ -} PythonQtSlotFunctionObject; +}; #endif diff --git a/src/PythonQtSlotDecorator.cpp b/src/PythonQtSlotDecorator.cpp index 1c7f9e73..f8933b97 100644 --- a/src/PythonQtSlotDecorator.cpp +++ b/src/PythonQtSlotDecorator.cpp @@ -39,10 +39,10 @@ int PythonQtSlotDecorator_init(PyObject *object, PyObject *args, PyObject *kw) self->returnType = new QByteArray(); self->args = new QByteArray(); - char* argName = 0; - PyObject* argResult = 0; + char* argName = nullptr; + PyObject* argResult = nullptr; - static const char* kwlist[] = {"name", "result", 0}; + static const char* kwlist[] = {"name", "result", nullptr}; static PyObject* emptyTuple = PyTuple_New(0); if (!PyArg_ParseTupleAndKeywords(emptyTuple, kw, "|sO:QtCore.Slot", (char**) kwlist, &argName, &argResult)) { return 0; @@ -85,6 +85,7 @@ int PythonQtSlotDecorator_init(PyObject *object, PyObject *args, PyObject *kw) PyObject* PythonQtSlotDecorator_call(PyObject* object, PyObject* args, PyObject* kw) { + Q_UNUSED(kw) PythonQtSlotDecorator* self = (PythonQtSlotDecorator*)object; PyObject* function = PyTuple_GetItem(args, 0); @@ -96,7 +97,7 @@ PyObject* PythonQtSlotDecorator_call(PyObject* object, PyObject* args, PyObject* QByteArray signature = returnType + " " + slotName + "(" + *self->args + ")"; static PyObject* qtSlots = PyString_FromString("_qtSlots"); - PyObject* signatures = NULL; + PyObject* signatures = nullptr; if (!PyObject_HasAttr(function, qtSlots)) { // create a new list signatures = PyList_New(0); @@ -127,49 +128,49 @@ PyDoc_STRVAR(PythonQtSlotDecorator_doc, PyTypeObject PythonQtSlotDecorator_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - "PythonQt.QtCore.Slot", /*tp_name*/ - sizeof(PythonQtSlotDecorator),/*tp_basicsize*/ + "PythonQt.QtCore.Slot", /*tp_name*/ + sizeof(PythonQtSlotDecorator), /*tp_basicsize*/ 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*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 */ - PythonQtSlotDecorator_call, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + nullptr, /*tp_dealloc*/ + 0, /*tp_vectorcall_offset*/ + nullptr, /*tp_getattr*/ + nullptr, /*tp_setattr*/ + nullptr, /*tp_compare*/ + nullptr, /*tp_repr*/ + nullptr, /*tp_as_number*/ + nullptr, /*tp_as_sequence*/ + nullptr, /*tp_as_mapping*/ + nullptr, /*tp_hash */ + PythonQtSlotDecorator_call, /*tp_call*/ + nullptr, /*tp_str*/ + nullptr, /*tp_getattro*/ + nullptr, /*tp_setattro*/ + nullptr, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ PythonQtSlotDecorator_doc, /*tp_doc */ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ + nullptr, /*tp_traverse */ + nullptr, /*tp_clear */ + nullptr, /*tp_richcompare */ 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - 0, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ + nullptr, /*tp_iter */ + nullptr, /*tp_iternext */ + nullptr, /*tp_methods */ + nullptr, /*tp_members */ + nullptr, /*tp_getset */ + nullptr, /*tp_base */ + nullptr, /*tp_dict */ + nullptr, /*tp_descr_get */ + nullptr, /*tp_descr_set */ 0, /*tp_dictoffset */ - PythonQtSlotDecorator_init, /*tp_init */ - 0, /*tp_alloc */ + PythonQtSlotDecorator_init, /*tp_init */ + nullptr, /*tp_alloc */ PyType_GenericNew, /*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 */ + nullptr, /*tp_free */ + nullptr, /*tp_is_gc */ + nullptr, /*tp_bases */ + nullptr, /*tp_mro */ + nullptr, /*tp_cache */ + nullptr, /*tp_subclasses */ + nullptr, /*tp_weaklist */ + nullptr, /*tp_del */ }; diff --git a/src/PythonQtSlotDecorator.h b/src/PythonQtSlotDecorator.h index ee1e2b7e..092ec611 100644 --- a/src/PythonQtSlotDecorator.h +++ b/src/PythonQtSlotDecorator.h @@ -43,8 +43,8 @@ extern PYTHONQT_EXPORT PyTypeObject PythonQtSlotDecorator_Type; #define PythonQtSlotDecorator_Check(op) (Py_TYPE(op) == &PythonQtSlotDecorator_Type) -typedef struct { +struct PythonQtSlotDecorator { PyObject_HEAD QByteArray* args; QByteArray* returnType; -} PythonQtSlotDecorator; +}; diff --git a/src/PythonQtStdDecorators.cpp b/src/PythonQtStdDecorators.cpp index cc5e2ad3..ca1ddcfb 100644 --- a/src/PythonQtStdDecorators.cpp +++ b/src/PythonQtStdDecorators.cpp @@ -45,6 +45,7 @@ #include "PythonQtConversion.h" #include +#include bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, PyObject* callable) { @@ -113,8 +114,8 @@ bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal } if (sender) { result = PythonQt::self()->removeSignalHandler(sender, signalTmp, callable); - if (callable == NULL) { - result |= QObject::disconnect(sender, signalTmp, NULL, NULL); + if (callable == nullptr) { + result |= QObject::disconnect(sender, signalTmp, nullptr, nullptr); } if (!result) { if (sender->metaObject()->indexOfSignal(QMetaObject::normalizedSignature(signalTmp.constData()+1)) == -1) { @@ -196,7 +197,7 @@ void PythonQtStdDecorators::static_QTimer_singleShot(int msec, PyObject* callabl QObject* PythonQtStdDecorators::findChild(QObject* parent, PyObject* type, const QString& name) { - const QMetaObject* meta = NULL; + const QMetaObject* meta = nullptr; QByteArray typeName; if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) { @@ -208,7 +209,7 @@ QObject* PythonQtStdDecorators::findChild(QObject* parent, PyObject* type, const } if (typeName.isEmpty() && !meta) { - return NULL; + return nullptr; } return findChild(parent, typeName, meta, name); @@ -216,7 +217,7 @@ QObject* PythonQtStdDecorators::findChild(QObject* parent, PyObject* type, const QList PythonQtStdDecorators::findChildren(QObject* parent, PyObject* type, const QString& name) { - const QMetaObject* meta = NULL; + const QMetaObject* meta = nullptr; QByteArray typeName; if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) { @@ -240,9 +241,9 @@ QList PythonQtStdDecorators::findChildren(QObject* parent, PyObject* t return list; } -QList PythonQtStdDecorators::findChildren(QObject* parent, PyObject* type, const QRegExp& regExp) +QList PythonQtStdDecorators::findChildren(QObject* parent, PyObject* type, const QRegularExpression& regExp) { - const QMetaObject* meta = NULL; + const QMetaObject* meta = nullptr; QByteArray typeName; if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) { @@ -274,7 +275,7 @@ QObject* PythonQtStdDecorators::findChild(QObject* parent, const char* typeName, QObject* obj = children.at(i); if (!obj) - return NULL; + return nullptr; // Skip if the name doesn't match. if (!name.isNull() && obj->objectName() != name) @@ -288,11 +289,11 @@ QObject* PythonQtStdDecorators::findChild(QObject* parent, const char* typeName, for (i = 0; i < children.size(); ++i) { QObject* obj = findChild(children.at(i), typeName, meta, name); - if (obj != NULL) + if (obj != nullptr) return obj; } - return NULL; + return nullptr; } int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList& list) @@ -322,7 +323,7 @@ int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, c return 0; } -int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegExp& regExp, QList& list) +int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegularExpression& regExp, QList& list) { const QObjectList& children = parent->children(); int i; @@ -334,7 +335,8 @@ int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, c return -1; // Skip if the name doesn't match. - if (regExp.indexIn(obj->objectName()) == -1) + QRegularExpressionMatch match = regExp.match(obj->objectName()); + if (match.hasMatch() == false) continue; if ((typeName && obj->inherits(typeName)) || @@ -354,6 +356,17 @@ const QMetaObject* PythonQtStdDecorators::metaObject( QObject* obj ) return obj->metaObject(); } +//--------------------------------------------------------------------------- + +void PythonQtConfigAPI::setTaskDoneCallback(PyObject* object) +{ + if (PythonQt::self()) { + PythonQt::self()->priv()->setTaskDoneCallback(object); + } +} + +//--------------------------------------------------------------------------- + bool PythonQtDebugAPI::isOwnedByPython( PyObject* object ) { if (PyObject_TypeCheck(object, &PythonQtInstanceWrapper_Type)) { @@ -421,11 +434,19 @@ PythonQtSingleShotTimer::PythonQtSingleShotTimer(int msec, const PythonQtObjectP connect(this, SIGNAL(timeout()), this, SLOT(slotTimeout())); } +PythonQtSingleShotTimer::~PythonQtSingleShotTimer() +{ + PYTHONQT_GIL_SCOPE + _callable = nullptr; +} + void PythonQtSingleShotTimer::slotTimeout() { if (_callable) { + PYTHONQT_GIL_SCOPE _callable.call(); } // delete ourself deleteLater(); } + diff --git a/src/PythonQtStdDecorators.h b/src/PythonQtStdDecorators.h index ca4d0f17..f3f6948b 100644 --- a/src/PythonQtStdDecorators.h +++ b/src/PythonQtStdDecorators.h @@ -58,6 +58,9 @@ #include #include #include +#if QT_VERSION >= 0x060000 +#include +#endif class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject { @@ -69,9 +72,9 @@ public Q_SLOTS: bool connect(QObject* receiver, QObject* sender, const QByteArray& signal, const QByteArray& slot, Qt::ConnectionType type = Qt::AutoConnection) { return connect(sender, signal, receiver, slot, type); } bool static_QObject_connect(QObject* sender, const QByteArray& signal, PyObject* callable) { return connect(sender, signal, callable); } bool static_QObject_connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot, Qt::ConnectionType type = Qt::AutoConnection) { return connect(sender, signal, receiver, slot, type); } - bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable = NULL); + bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable = nullptr); bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot); - bool static_QObject_disconnect(QObject* sender, const QByteArray& signal, PyObject* callable = NULL) { return disconnect(sender, signal, callable); } + bool static_QObject_disconnect(QObject* sender, const QByteArray& signal, PyObject* callable = nullptr) { return disconnect(sender, signal, callable); } bool static_QObject_disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot) { return disconnect(sender, signal, receiver, slot); } const QMetaObject* metaObject( QObject* obj ); @@ -82,7 +85,7 @@ public Q_SLOTS: const QObjectList* children(QObject* o); QObject* findChild(QObject* parent, PyObject* type, const QString& name = QString()); QList findChildren(QObject* parent, PyObject* type, const QString& name= QString()); - QList findChildren(QObject* parent, PyObject* type, const QRegExp& regExp); + QList findChildren(QObject* parent, PyObject* type, const QRegularExpression& regExp); bool setProperty(QObject* o, const char* name, const QVariant& value); QVariant property(QObject* o, const char* name); @@ -103,8 +106,24 @@ public Q_SLOTS: int static_Qt_qRound(double a) { return qRound(a); } qint64 static_Qt_qRound64(double a) { return qRound64(a); } const char* static_Qt_qVersion() { return qVersion(); } - int static_Qt_qrand() { return qrand(); } - void static_Qt_qsrand(uint a) { qsrand(a); } + + int static_Qt_qrand() + { +#if QT_VERSION < 0x060000 + return qrand(); +#else + return QRandomGenerator::global()->generate(); +#endif + } + + void static_Qt_qsrand(uint a) + { +#if QT_VERSION < 0x060000 + qsrand(a); +#else + QRandomGenerator::global()->seed(a); +#endif + } QString tr(QObject* obj, const QString& text, const QString& ambig = QString(), int n = -1); @@ -116,7 +135,7 @@ public Q_SLOTS: private: QObject* findChild(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name); int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList& list); - int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegExp& regExp, QList& list); + int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegularExpression& regExp, QList& list); }; class PythonQtSingleShotTimer : public QTimer @@ -124,6 +143,7 @@ class PythonQtSingleShotTimer : public QTimer Q_OBJECT public: PythonQtSingleShotTimer(int msec, const PythonQtObjectPtr& callable); + ~PythonQtSingleShotTimer() override; public Q_SLOTS : void slotTimeout(); @@ -173,6 +193,20 @@ public Q_SLOTS: }; +//! Some methods to set properties of PythonQt from Python +class PYTHONQT_EXPORT PythonQtConfigAPI : public QObject +{ + Q_OBJECT +public: + PythonQtConfigAPI(QObject* parent):QObject(parent) {}; + +public slots: + //! Set a callable that is used as the argument for the add_done_callback for the Task/Future + //! created when, e.g., an async function is connected to signal. + void setTaskDoneCallback(PyObject* object); +}; + + //! Some helper methods that allow testing of the ownership class PYTHONQT_EXPORT PythonQtDebugAPI : public QObject { diff --git a/src/PythonQtStdIn.cpp b/src/PythonQtStdIn.cpp index 73df190c..056127b2 100644 --- a/src/PythonQtStdIn.cpp +++ b/src/PythonQtStdIn.cpp @@ -46,8 +46,8 @@ static PyObject *PythonQtStdInRedirect_new(PyTypeObject *type, PyObject * /*args { PythonQtStdInRedirect *self; self = (PythonQtStdInRedirect *)type->tp_alloc(type, 0); - self->_cb = NULL; - self->_callData = NULL; + self->_cb = nullptr; + self->_callData = nullptr; self->_isatty = false; return (PyObject *)self; @@ -55,7 +55,7 @@ static PyObject *PythonQtStdInRedirect_new(PyTypeObject *type, PyObject * /*args static PyObject *PythonQtStdInRedirect_readline(PyObject * self, PyObject * args) { - Q_UNUSED(args); + Q_UNUSED(args) PythonQtStdInRedirect* s = (PythonQtStdInRedirect*)self; QString string; if (s->_cb) { @@ -78,50 +78,50 @@ static PyMethodDef PythonQtStdInRedirect_methods[] = { {"isatty", (PyCFunction)PythonQtStdInRedirect_isatty, METH_NOARGS, "returns True if this is a tty-like device. False by default." }, - {NULL, NULL, 0 , NULL} /* sentinel */ + {nullptr, nullptr, 0 , nullptr} /* sentinel */ }; static PyMemberDef PythonQtStdInRedirect_members[] = { - {NULL} /* Sentinel */ + {nullptr} /* Sentinel */ }; PyTypeObject PythonQtStdInRedirectType = { - PyVarObject_HEAD_INIT(NULL, 0) - "PythonQtStdInRedirect", /*tp_name*/ - sizeof(PythonQtStdInRedirect), /*tp_basicsize*/ + PyVarObject_HEAD_INIT(nullptr, 0) + "PythonQtStdInRedirect", /*tp_name*/ + sizeof(PythonQtStdInRedirect), /*tp_basicsize*/ 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*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*/ + nullptr, /*tp_dealloc*/ + 0, /*tp_vectorcall_offset*/ + nullptr, /*tp_getattr*/ + nullptr, /*tp_setattr*/ + nullptr, /*tp_compare*/ + nullptr, /*tp_repr*/ + nullptr, /*tp_as_number*/ + nullptr, /*tp_as_sequence*/ + nullptr, /*tp_as_mapping*/ + nullptr, /*tp_hash */ + nullptr, /*tp_call*/ + nullptr, /*tp_str*/ + nullptr, /*tp_getattro*/ + nullptr, /*tp_setattro*/ + nullptr, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "PythonQtStdInRedirect", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PythonQtStdInRedirect_methods, /* tp_methods */ - PythonQtStdInRedirect_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ + "PythonQtStdInRedirect", /* tp_doc */ + nullptr, /* tp_traverse */ + nullptr, /* tp_clear */ + nullptr, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + nullptr, /* tp_iter */ + nullptr, /* tp_iternext */ + PythonQtStdInRedirect_methods, /* tp_methods */ + PythonQtStdInRedirect_members, /* tp_members */ + nullptr, /* tp_getset */ + nullptr, /* tp_base */ + nullptr, /* tp_dict */ + nullptr, /* tp_descr_get */ + nullptr, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - PythonQtStdInRedirect_new, /* tp_new */ + nullptr, /* tp_init */ + nullptr, /* tp_alloc */ + PythonQtStdInRedirect_new, /* tp_new */ }; diff --git a/src/PythonQtStdIn.h b/src/PythonQtStdIn.h index a3117eac..c32a1690 100644 --- a/src/PythonQtStdIn.h +++ b/src/PythonQtStdIn.h @@ -54,11 +54,11 @@ extern PyTypeObject PythonQtStdInRedirectType; typedef QString PythonQtInputChangedCB(void* callData); //! declares the stdin redirection class -typedef struct { +struct PythonQtStdInRedirect { PyObject_HEAD PythonQtInputChangedCB* _cb; void * _callData; bool _isatty; -} PythonQtStdInRedirect; +}; #endif diff --git a/src/PythonQtStdOut.cpp b/src/PythonQtStdOut.cpp index 5c69fcd6..4069bd8e 100644 --- a/src/PythonQtStdOut.cpp +++ b/src/PythonQtStdOut.cpp @@ -48,7 +48,7 @@ static PyObject *PythonQtStdOutRedirect_new(PyTypeObject *type, PyObject * /*arg self->softspace = 0; self->closed = false; - self->_cb = NULL; + self->_cb = nullptr; return (PyObject *)self; } @@ -75,7 +75,7 @@ static PyObject *PythonQtStdOutRedirect_write(PyObject *self, PyObject *args) } else { char *string; if (!PyArg_ParseTuple(args, "s", &string)) { - return NULL; + return nullptr; } #ifdef PY3K output = QString::fromUtf8(string); @@ -115,7 +115,7 @@ static PyMethodDef PythonQtStdOutRedirect_methods[] = { {"isatty", (PyCFunction)PythonQtStdOutRedirect_isatty, METH_NOARGS, "return False since this object is not a tty-like device. Needed for logging framework" }, - {NULL, NULL, 0 , NULL} /* sentinel */ + {nullptr, nullptr, 0 , nullptr} /* sentinel */ }; static PyMemberDef PythonQtStdOutRedirect_members[] = { @@ -125,46 +125,46 @@ static PyMemberDef PythonQtStdOutRedirect_members[] = { { const_cast("closed"), T_BOOL, offsetof(PythonQtStdOutRedirect, closed), 0, const_cast("soft space flag") }, - {NULL} /* Sentinel */ + {nullptr} /* Sentinel */ }; PyTypeObject PythonQtStdOutRedirectType = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "PythonQtStdOutRedirect", /*tp_name*/ - sizeof(PythonQtStdOutRedirect), /*tp_basicsize*/ + sizeof(PythonQtStdOutRedirect), /*tp_basicsize*/ 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*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*/ + nullptr, /*tp_dealloc*/ + 0, /*tp_vectorcall_offset*/ + nullptr, /*tp_getattr*/ + nullptr, /*tp_setattr*/ + nullptr, /*tp_compare*/ + nullptr, /*tp_repr*/ + nullptr, /*tp_as_number*/ + nullptr, /*tp_as_sequence*/ + nullptr, /*tp_as_mapping*/ + nullptr, /*tp_hash */ + nullptr, /*tp_call*/ + nullptr, /*tp_str*/ + nullptr, /*tp_getattro*/ + nullptr, /*tp_setattro*/ + nullptr, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "PythonQtStdOutRedirect", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PythonQtStdOutRedirect_methods, /* tp_methods */ - PythonQtStdOutRedirect_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ + "PythonQtStdOutRedirect", /* tp_doc */ + nullptr, /* tp_traverse */ + nullptr, /* tp_clear */ + nullptr, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + nullptr, /* tp_iter */ + nullptr, /* tp_iternext */ + PythonQtStdOutRedirect_methods, /* tp_methods */ + PythonQtStdOutRedirect_members, /* tp_members */ + nullptr, /* tp_getset */ + nullptr, /* tp_base */ + nullptr, /* tp_dict */ + nullptr, /* tp_descr_get */ + nullptr, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - PythonQtStdOutRedirect_new, /* tp_new */ + nullptr, /* tp_init */ + nullptr, /* tp_alloc */ + PythonQtStdOutRedirect_new, /* tp_new */ }; diff --git a/src/PythonQtStdOut.h b/src/PythonQtStdOut.h index ea22f6ec..1b675dfb 100644 --- a/src/PythonQtStdOut.h +++ b/src/PythonQtStdOut.h @@ -55,11 +55,11 @@ extern PyTypeObject PythonQtStdOutRedirectType; typedef void PythonQtOutputChangedCB(const QString& str); //! declares the stdout redirection class -typedef struct { +struct PythonQtStdOutRedirect { PyObject_HEAD PythonQtOutputChangedCB* _cb; int softspace; bool closed; -} PythonQtStdOutRedirect; +}; #endif diff --git a/src/PythonQtSystem.h b/src/PythonQtSystem.h index d7131bb7..d49345ee 100644 --- a/src/PythonQtSystem.h +++ b/src/PythonQtSystem.h @@ -42,15 +42,21 @@ */ //---------------------------------------------------------------------------------- -#ifdef WIN32 -#ifdef PYTHONQT_EXPORTS -#define PYTHONQT_EXPORT __declspec(dllexport) -#else -#define PYTHONQT_EXPORT __declspec(dllimport) -#endif + +#if defined(WIN32) + #ifdef PYTHONQT_EXPORTS + #define PYTHONQT_EXPORT __declspec(dllexport) + #else + #define PYTHONQT_EXPORT __declspec(dllimport) + #endif #else -#define PYTHONQT_EXPORT + #ifdef PYTHONQT_EXPORTS + #define PYTHONQT_EXPORT __attribute__((__visibility__("default"))) + #else + #define PYTHONQT_EXPORT + #endif #endif + #endif diff --git a/src/PythonQtThreadSupport.h b/src/PythonQtThreadSupport.h index cd309b0f..f57e821d 100644 --- a/src/PythonQtThreadSupport.h +++ b/src/PythonQtThreadSupport.h @@ -39,9 +39,9 @@ */ //---------------------------------------------------------------------------------- - -#include -#include +#include //Q_DISABLE_COPY +#include "PythonQtPythonInclude.h" +#include "PythonQtSystem.h" #define PYTHONQT_FULL_THREAD_SUPPORT @@ -103,6 +103,7 @@ class PythonQtGILScope //! from Python code. class PythonQtThreadStateSaver { + Q_DISABLE_COPY(PythonQtThreadStateSaver) public: PythonQtThreadStateSaver() { save(); @@ -119,7 +120,7 @@ class PythonQtThreadStateSaver void restore() { if (_state) { PyEval_RestoreThread(_state); - _state = NULL; + _state = nullptr; } } diff --git a/src/PythonQtVariants.h b/src/PythonQtVariants.h index 7e069101..833f35c8 100644 --- a/src/PythonQtVariants.h +++ b/src/PythonQtVariants.h @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include #include @@ -72,7 +72,6 @@ #include #include #include -#include #endif diff --git a/src/gui/PythonQtScriptingConsole.cpp b/src/gui/PythonQtScriptingConsole.cpp index d1e76666..6e221845 100644 --- a/src/gui/PythonQtScriptingConsole.cpp +++ b/src/gui/PythonQtScriptingConsole.cpp @@ -174,7 +174,7 @@ void PythonQtScriptingConsole::executeCode(const QString& code) _stdOut = ""; _stdErr = ""; PythonQtObjectPtr p; - PyObject* dict = NULL; + PyObject* dict = nullptr; if (PyModule_Check(_context)) { dict = PyModule_GetDict(_context); } else if (PyDict_Check(_context)) { @@ -451,8 +451,9 @@ void PythonQtScriptingConsole::keyPressEvent(QKeyEvent* event) { } if (eventHandled) { - - _completer->popup()->hide(); + if(_completer != nullptr) { + _completer->popup()->hide(); + } event->accept(); } else { @@ -464,7 +465,6 @@ void PythonQtScriptingConsole::keyPressEvent(QKeyEvent* event) { } else { _completer->popup()->hide(); } - eventHandled = true; } } diff --git a/src/gui/PythonQtScriptingConsole.h b/src/gui/PythonQtScriptingConsole.h index 4ad49457..97a31644 100644 --- a/src/gui/PythonQtScriptingConsole.h +++ b/src/gui/PythonQtScriptingConsole.h @@ -55,16 +55,16 @@ class PYTHONQT_EXPORT PythonQtScriptingConsole : public QTextEdit Q_OBJECT public: - PythonQtScriptingConsole(QWidget* parent, const PythonQtObjectPtr& context, Qt::WindowFlags i = 0); + PythonQtScriptingConsole(QWidget* parent, const PythonQtObjectPtr& context, Qt::WindowFlags i = Qt::WindowFlags()); - ~PythonQtScriptingConsole(); + ~PythonQtScriptingConsole() override; public Q_SLOTS: //! execute current line void executeLine(bool storeOnly); //! derived key press event - void keyPressEvent (QKeyEvent * e); + void keyPressEvent (QKeyEvent * e) override; //! output from console void consoleMessage(const QString & message); diff --git a/src/src.pri b/src/src.pri index 79be076f..13fe1f62 100644 --- a/src/src.pri +++ b/src/src.pri @@ -2,8 +2,15 @@ DEFINES += PYTHONQT_EXPORTS INCLUDEPATH += $$PWD +gcc:!no_warn:!clang:QMAKE_CXXFLAGS += -Wno-error=missing-field-initializers +*-clang*:!no_warn:QMAKE_CXXFLAGS += -Wno-error=sometimes-uninitialized + # This was needed to work around "number of sections exceeded object file format limit" linker error -win32:QMAKE_CXXFLAGS += /bigobj +win32-msvc*:QMAKE_CXXFLAGS += /bigobj +!ltcg:win32-g++: QMAKE_CXXFLAGS += -Wa,-mbig-obj + +# Force linker to complain on undefined references for dll/so/dylib build when possible +QMAKE_LFLAGS_SHLIB += $$QMAKE_LFLAGS_NOUNDEF HEADERS += \ $$PWD/PythonQt.h \ diff --git a/src/src.pro b/src/src.pro index 44d96ec8..afae9ce4 100644 --- a/src/src.pro +++ b/src/src.pro @@ -4,18 +4,19 @@ # $Source$ # -------------------------------------------------- -TARGET = PythonQt-Qt5-PythonXY +TARGET = PythonQt-Qt$${QT_MAJOR_VERSION}-PythonXY TEMPLATE = lib - DESTDIR = ../lib CONFIG += qt CONFIG -= flat - # allow to choose static linking through the environment variable PYTHONQT_STATIC +isEmpty(PYTHONQT_STATIC) { PYTHONQT_STATIC = $$(PYTHONQT_STATIC) +} + isEmpty(PYTHONQT_STATIC) { CONFIG += dll } else { @@ -24,15 +25,16 @@ isEmpty(PYTHONQT_STATIC) { DEFINES += PYTHONQT_CATCH_ALL_EXCEPTIONS -contains(QT_MAJOR_VERSION, 5) { - QT += widgets core-private -} +QT += widgets core-private -# Qt 5.4 adds this option, but this is not compatible with the Python API -QMAKE_CXXFLAGS_RELEASE -= -Zc:strictStrings - INCLUDEPATH += $$PWD +macx { + contains(QT_MAJOR_VERSION, 6) { + QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64 + } +} + include ( ../build/common.prf ) include ( ../build/python.prf ) TARGET = $$replace(TARGET, PythonXY, Python$${PYTHON_VERSION}) @@ -44,19 +46,19 @@ include($${PYTHONQT_GENERATED_PATH}/com_trolltech_qt_gui_builtin/com_trolltech_q unix { CONFIG += create_pc create_prl no_install_prl - QMAKE_PKGCONFIG_NAME = PythonQt-Qt$${QT_MAJOR_VERSION}-Python$${PYTHON_VERSION} + QMAKE_PKGCONFIG_NAME = $${TARGET} QMAKE_PKGCONFIG_DESCRIPTION = Dynamic Python binding for the Qt framework QMAKE_PKGCONFIG_PREFIX = $$INSTALLBASE QMAKE_PKGCONFIG_LIBDIR = $$target.path QMAKE_PKGCONFIG_INCDIR = $$headers.path - QMAKE_PKGCONFIG_INCDIR += $$PREFIX/include/PythonQt5 + QMAKE_PKGCONFIG_INCDIR += ${prefix}/include/PythonQt5 QMAKE_PKGCONFIG_VERSION = $$VERSION } -unix: target.path = /lib +unix: target.path = $${INSTALL_PREFIX}/lib win32: target.path = / headers.files = $${HEADERS} $$PWD/PythonQtPythonInclude.h -headers.path = /include +headers.path = $${INSTALL_PREFIX}/include INSTALLS += target headers diff --git a/tests/PythonQtTestMain.cpp b/tests/PythonQtTestMain.cpp index 8b498ab4..006d5411 100644 --- a/tests/PythonQtTestMain.cpp +++ b/tests/PythonQtTestMain.cpp @@ -69,13 +69,13 @@ int main(int argc, char *argv[]) PythonQtTestCleanup cleanup; failCount += QTest::qExec(&cleanup, argc, argv); - if (failCount>0) { + if (failCount) { std::cerr << "Tests failed: " << failCount << std::endl; } else { std::cout << "All tests passed successfully." << std::endl; } #endif - return failCount; + return failCount != 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/tests/PythonQtTests.cpp b/tests/PythonQtTests.cpp index 50d39ba9..dd727756 100644 --- a/tests/PythonQtTests.cpp +++ b/tests/PythonQtTests.cpp @@ -416,8 +416,8 @@ void PythonQtTestSignalHandler::testSignalHandler() QVERIFY(_helper->emitVariantSignal(12)); _helper->setExpectedVariant(QStringList() << "test1" << "test2"); QVERIFY(_helper->emitVariantSignal(QStringList() << "test1" << "test2")); - _helper->setExpectedVariant(qVariantFromValue((QObject*)_helper)); - QVERIFY(_helper->emitVariantSignal(qVariantFromValue((QObject*)_helper))); + _helper->setExpectedVariant(QVariant::fromValue((QObject*)_helper)); + QVERIFY(_helper->emitVariantSignal(QVariant::fromValue((QObject*)_helper))); PyRun_SimpleString("def testComplexSignal(a,b,l,o):\n if a==12 and b==13 and l==('test1','test2') and o == obj: obj.setPassed();\n"); // intentionally not normalized signal: @@ -527,7 +527,7 @@ void PythonQtTestApi::testCall() QVERIFY(_helper->call("testCall1", QVariantList() << QVariant("test"), QVariant(QString("test2")))); PyRun_SimpleString("def testCall2(a, b):\n if a=='test' and b==obj: obj.setPassed();\n return obj;\n"); - QVariant r = PythonQt::self()->call(PythonQt::self()->getMainModule(), "testCall2", QVariantList() << QVariant("test") << qVariantFromValue((QObject*)_helper)); + QVariant r = PythonQt::self()->call(PythonQt::self()->getMainModule(), "testCall2", QVariantList() << QVariant("test") << QVariant::fromValue((QObject*)_helper)); QObject* p = qvariant_cast(r); QVERIFY(p==_helper); } @@ -542,11 +542,17 @@ void PythonQtTestApi::testVariables() QVariant v2 = PythonQt::self()->getVariable(PythonQt::self()->getMainModule(), "someObject2"); QVERIFY(v2==QVariant()); - PythonQt::self()->addVariable(PythonQt::self()->getMainModule(), "someValue", QStringList() << "test1" << "test2"); + QVariant someValue = QStringList() << "test1" << "test2"; + PythonQt::self()->addVariable(PythonQt::self()->getMainModule(), "someValue", someValue); QVariant v3 = PythonQt::self()->getVariable(PythonQt::self()->getMainModule(), "someValue"); - QVERIFY(v3 == QVariant(QStringList() << "test1" << "test2")); +#if QT_VERSION >= 0x060000 + // In Qt6 the behavior of the == operator changed, and it will not try to convert the other + // value first, so we replicate this first (otherwise the comparison QVariantList <-> QStringList fails) + QVERIFY(someValue.convert(v3.metaType())); +#endif + QVERIFY(v3 == someValue); - QStringList l = PythonQt::self()->introspection(PythonQt::self()->getMainModule(), QString::null, PythonQt::Variable); + QStringList l = PythonQt::self()->introspection(PythonQt::self()->getMainModule(), QString(), PythonQt::Variable); QSet s; // check that at least these three variables are set s << "obj" << "someObject" << "someValue"; diff --git a/tests/PythonQtTests.h b/tests/PythonQtTests.h index c511fc57..d6ef486c 100644 --- a/tests/PythonQtTests.h +++ b/tests/PythonQtTests.h @@ -162,7 +162,7 @@ class PythonQtTestApiHelper : public QObject , public PythonQtImportFileInterfac virtual QDateTime lastModifiedDate(const QString& filename); - virtual bool isEggArchive(const QString& filename) { return false; } + virtual bool isEggArchive(const QString&) { return false; } public Q_SLOTS: @@ -328,13 +328,13 @@ class PQCppObjectQFlagOnlyDecorator : public QObject { class PQUnknownValueObject { public: - PQUnknownValueObject() {}; + PQUnknownValueObject() {} }; class PQUnknownButRegisteredValueObject { public: - PQUnknownButRegisteredValueObject() {}; + PQUnknownButRegisteredValueObject() {} }; //! test the calling of Q_SLOTS @@ -379,15 +379,15 @@ class PythonQtTestSlotCallingHelper : public QObject bool runScript(const char* script, int expectedOverload = -1); - Q_PROPERTY(int intProp READ intProp WRITE setIntProp); - Q_PROPERTY(float floatProp READ floatProp WRITE setFloatProp); - Q_PROPERTY(QVariantList variantListProp READ variantListProp WRITE setVariantListProp); - Q_PROPERTY(QVariantMap variantMapProp READ variantMapProp WRITE setVariantMapProp); - Q_PROPERTY(QVariant variantProp READ variantProp WRITE setVariantProp); - Q_PROPERTY(QObject* qObjectProp READ qObjectProp WRITE setQObjectProp); - Q_PROPERTY(QList qObjectListProp READ qObjectListProp WRITE setQObjectListProp); + Q_PROPERTY(int intProp READ intProp WRITE setIntProp) + Q_PROPERTY(float floatProp READ floatProp WRITE setFloatProp) + Q_PROPERTY(QVariantList variantListProp READ variantListProp WRITE setVariantListProp) + Q_PROPERTY(QVariantMap variantMapProp READ variantMapProp WRITE setVariantMapProp) + Q_PROPERTY(QVariant variantProp READ variantProp WRITE setVariantProp) + Q_PROPERTY(QObject* qObjectProp READ qObjectProp WRITE setQObjectProp) + Q_PROPERTY(QList qObjectListProp READ qObjectListProp WRITE setQObjectListProp) - Q_PROPERTY(QSize sizeProp READ sizeProp WRITE setSizeProp); + Q_PROPERTY(QSize sizeProp READ sizeProp WRITE setSizeProp) public: int intProp() const { _called = true; return _intProp; } diff --git a/tests/tests.pro b/tests/tests.pro index 1cc4e006..f864646d 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -7,12 +7,19 @@ TARGET = PythonQtTest TEMPLATE = app DESTDIR = ../lib +QMAKE_RPATHDIR += $$DESTDIR QT += testlib opengl +CONFIG += testcase cmdline exceptions testcase_no_bundle no_testcase_installs -contains(QT_MAJOR_VERSION, 5) { - QT += widgets -} +#Workaround for MinGW build. Qt incorrectly sets it to empty string on Win32 for bash +mingw: TEST_TARGET_DIR = . + +DEFINES += QT_NO_CAST_TO_ASCII + +gcc: QMAKE_CXXFLAGS += -pedantic -Winit-self -Wuninitialized + +QT += widgets include ( ../build/common.prf ) include ( ../build/PythonQt.prf )