summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--coin_test_instructions.py3
-rw-r--r--examples/sql/books/createdb.py8
m---------sources/pyside2-tools0
-rw-r--r--sources/pyside2/PySide2/CMakeLists.txt4
-rw-r--r--sources/pyside2/PySide2/QtCore/typesystem_core_common.xml14
-rw-r--r--sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml18
-rw-r--r--sources/pyside2/PySide2/QtOpenGL/typesystem_opengl.xml4
-rw-r--r--sources/pyside2/PySide2/QtWinExtras/CMakeLists.txt1
-rw-r--r--sources/pyside2/PySide2/QtWinExtras/typesystem_winextras.xml4
-rw-r--r--sources/pyside2/PySide2/glue/qtcore.cpp50
-rw-r--r--sources/pyside2/PySide2/support/__init__.py2
-rw-r--r--sources/pyside2/PySide2/support/deprecated.py80
-rw-r--r--sources/pyside2/PySide2/support/generate_pyi.py4
-rw-r--r--sources/pyside2/libpyside/dynamicqmetaobject.cpp13
-rw-r--r--sources/pyside2/libpyside/globalreceiverv2.cpp4
-rw-r--r--sources/pyside2/libpyside/pysidesignal.cpp23
-rw-r--r--sources/pyside2/libpyside/pysidesignal_p.h3
-rw-r--r--sources/pyside2/tests/QtCore/CMakeLists.txt1
-rw-r--r--sources/pyside2/tests/QtCore/qsettings_test.ini4
-rw-r--r--sources/pyside2/tests/QtCore/qsettings_test.py77
-rw-r--r--sources/pyside2/tests/QtGui/CMakeLists.txt2
-rw-r--r--sources/pyside2/tests/QtGui/timed_app_and_patching_test.py (renamed from sources/pyside2/tests/QtGui/timed_app_test.py)19
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/CMakeLists.txt1
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_1029.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_1029.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_451.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_451.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_456.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_456.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_557.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_726.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_726.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_814.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_814.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_825.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_825.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_847.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_847.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_915.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_926.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_926.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_951.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_951.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_995.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_995.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_997.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/bug_997.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/connect_python_qml.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/hw.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/qqmlnetwork_test.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/qquickview_test.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/registertype.py0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/registertype.qml0
-rw-r--r--sources/pyside2/tests/QtQml/signal_arguments.py67
-rw-r--r--sources/pyside2/tests/QtQml/signal_arguments.qml59
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/view.qml0
-rw-r--r--[-rwxr-xr-x]sources/pyside2/tests/QtQml/viewmodel.qml0
-rw-r--r--sources/shiboken2/ApiExtractor/CMakeLists.txt1
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp8
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp63
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h6
-rw-r--r--sources/shiboken2/ApiExtractor/messages.cpp17
-rw-r--r--sources/shiboken2/ApiExtractor/messages.h2
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel.h1
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase.cpp6
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.cpp2942
-rw-r--r--sources/shiboken2/ApiExtractor/typesystemparser.cpp2974
-rw-r--r--sources/shiboken2/ApiExtractor/typesystemparser.h (renamed from sources/shiboken2/ApiExtractor/typesystem_p.h)21
-rw-r--r--sources/shiboken2/doc/typesystemvariables.rst23
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp41
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp9
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp19
-rw-r--r--sources/shiboken2/libshiboken/signature_doc.rst10
-rw-r--r--sources/shiboken2/shibokenmodule/CMakeLists.txt4
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py103
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py15
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py135
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py12
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py459
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py279
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py15
-rw-r--r--sources/shiboken2/tests/minimalbinding/brace_pattern_test.py121
-rw-r--r--sources/shiboken2/tests/samplebinding/pointerprimitivetype_test.py79
-rw-r--r--testing/wheel_tester.py16
85 files changed, 4520 insertions, 3328 deletions
diff --git a/.gitignore b/.gitignore
index b8977159..c4bc8c8f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -69,7 +69,7 @@ develop-eggs/
downloads/
eggs/
.eggs/
-lib/
+/lib/
lib64/
parts/
sdist/
diff --git a/coin_test_instructions.py b/coin_test_instructions.py
index c560f217..8ba82c26 100644
--- a/coin_test_instructions.py
+++ b/coin_test_instructions.py
@@ -66,7 +66,8 @@ def call_testrunner(python_ver, buildnro):
_pExe, _env, env_pip, env_python = get_qtci_virtualEnv(python_ver, CI_HOST_OS, CI_HOST_ARCH, CI_TARGET_ARCH)
rmtree(_env, True)
run_instruction(["virtualenv", "-p", _pExe, _env], "Failed to create virtualenv")
- install_pip_dependencies(env_pip, ["pip", "numpy", "PyOpenGL", "setuptools", "six", "pyinstaller", "wheel"])
+ # Keeping PyInstaller 3.4, because 3.5 seems to have broken our test
+ install_pip_dependencies(env_pip, ["pip", "numpy", "PyOpenGL", "setuptools", "six", "pyinstaller==3.4", "wheel"])
cmd = [env_python, "testrunner.py", "test",
"--blacklist", "build_history/blacklist.txt",
"--buildno=" + buildnro]
diff --git a/examples/sql/books/createdb.py b/examples/sql/books/createdb.py
index 1ca52470..d03060ad 100644
--- a/examples/sql/books/createdb.py
+++ b/examples/sql/books/createdb.py
@@ -101,10 +101,10 @@ def init_db():
check(db.open)
q = QSqlQuery()
- check(q.exec_,BOOKS_SQL)
- check(q.exec_,AUTHORS_SQL)
- check(q.exec_,GENRES_SQL)
- check(q.prepare,INSERT_AUTHOR_SQL)
+ check(q.exec_, BOOKS_SQL)
+ check(q.exec_, AUTHORS_SQL)
+ check(q.exec_, GENRES_SQL)
+ check(q.prepare, INSERT_AUTHOR_SQL)
asimovId = add_author(q, "Isaac Asimov", datetime(1920, 2, 1))
greeneId = add_author(q, "Graham Greene", datetime(1904, 10, 2))
diff --git a/sources/pyside2-tools b/sources/pyside2-tools
-Subproject b921df17318a67f846ff9a86e047119f2e4bc4b
+Subproject e067832f2864c30e90cb2a25b840775ae2a3497
diff --git a/sources/pyside2/PySide2/CMakeLists.txt b/sources/pyside2/PySide2/CMakeLists.txt
index d666751e..e39db75a 100644
--- a/sources/pyside2/PySide2/CMakeLists.txt
+++ b/sources/pyside2/PySide2/CMakeLists.txt
@@ -37,6 +37,10 @@ endif()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/__init__.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/__init__.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/generate_pyi.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/generate_pyi.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/deprecated.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/deprecated.py" COPYONLY)
# now compile all modules.
file(READ "${CMAKE_CURRENT_BINARY_DIR}/pyside2_global.h" pyside2_global_contents)
diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
index 58db97aa..eb4e502e 100644
--- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
+++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
@@ -171,7 +171,6 @@
<primitive-type name="quint16"/>
<primitive-type name="quint32"/>
<primitive-type name="quint64"/>
- <primitive-type name="bool"/>
<primitive-type name="double"/>
<primitive-type name="qreal"/>
<primitive-type name="float"/>
@@ -2300,8 +2299,10 @@
<object-type name="QRandomGenerator" since="5.10">
<modify-function signature="global()" rename="global_" allow-thread="yes"/>
<modify-function signature="operator()()" remove="all"/>
+ <modify-function signature="generate(quint32*,quint32*)" remove="all"/>
</object-type>
<object-type name="QRandomGenerator64" since="5.10">
+ <modify-function signature="global()" rename="global_" allow-thread="yes"/>
<modify-function signature="operator()()" remove="all"/>
</object-type>
<object-type name="QSemaphore">
@@ -2515,11 +2516,12 @@
<define-ownership class="target" owner="default"/>
</modify-argument>
</modify-function>
- <modify-function signature="value(const QString&amp;,const QVariant&amp;)const">
- <inject-documentation mode="append" format="target">
- .. warning:: QSettings.value can return different types (QVariant types) depending on the platform it's running on, so the safest way to use it is always casting the result to the desired type, e.g.: int(settings.value("myKey"))
- </inject-documentation>
- </modify-function>
+ <!-- PYSIDE-1010:
+ We remove the original implementation of value() to include the optional parameter -->
+ <modify-function signature="value(const QString&amp;,const QVariant&amp;)const" remove="all"/>
+ <add-function signature="value(const QString&amp;, const QVariant&amp; @defaultValue@ = 0, PyObject* @type@ = 0)" return-type="PyObject*">
+ <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qsettings-value"/>
+ </add-function>
</object-type>
<object-type name="QEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::None">
<enum-type name="Type"/>
diff --git a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
index 95b85a91..ab40e395 100644
--- a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
+++ b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
@@ -1117,6 +1117,7 @@
<modify-function signature="boundingRect(QRectF,int,QString,int,int*)const">
<modify-argument index="5">
<replace-type modified-type="PyObject"/>
+ <array/>
</modify-argument>
<inject-code class="target" position="beginning" file="../glue/qtgui.cpp" snippet="qfontmetricsf-boundingrect"/>
</modify-function>
@@ -1124,6 +1125,7 @@
<modify-function signature="size(int,QString,int,int*)const">
<modify-argument index="4">
<replace-type modified-type="PyObject"/>
+ <array/>
</modify-argument>
<inject-code class="target" position="beginning" file="../glue/qtgui.cpp" snippet="qfontmetricsf-size"/>
</modify-function>
@@ -1150,7 +1152,8 @@
<modify-function signature="boundingRect(int,int,int,int,int,QString,int,int*)const">
<modify-argument index="8">
- <replace-type modified-type="PyObject"/>
+ <replace-type modified-type="PyObject"/>
+ <array/>
</modify-argument>
<inject-code class="target" position="beginning" file="../glue/qtgui.cpp" snippet="qfontmetrics-boundingrect-1"/>
</modify-function>
@@ -1158,6 +1161,7 @@
<modify-function signature="boundingRect(QRect,int,QString,int,int*)const">
<modify-argument index="5">
<replace-type modified-type="PyObject"/>
+ <array/>
</modify-argument>
<inject-code class="target" position="beginning" file="../glue/qtgui.cpp" snippet="qfontmetrics-boundingrect-2"/>
</modify-function>
@@ -1165,6 +1169,7 @@
<modify-function signature="size(int,QString,int,int*)const">
<modify-argument index="4">
<replace-type modified-type="PyObject"/>
+ <array/>
</modify-argument>
<inject-code class="target" position="beginning" file="../glue/qtgui.cpp" snippet="qfontmetrics-size"/>
</modify-function>
@@ -1935,6 +1940,7 @@
<value-type name="QMatrix2x2" since="4.6">
<modify-function signature="QMatrix2x2(const float*)" remove="all"/>
<modify-function signature="copyDataTo(float*) const" remove="all"/>
+ <modify-function signature="constData()const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -1971,6 +1977,7 @@
<value-type name="QMatrix2x3" since="4.6">
<modify-function signature="QMatrix2x3(const float*)" remove="all"/>
<modify-function signature="copyDataTo(float*) const" remove="all"/>
+ <modify-function signature="constData()const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2007,6 +2014,7 @@
<value-type name="QMatrix2x4" since="4.6">
<modify-function signature="QMatrix2x4(const float*)" remove="all"/>
<modify-function signature="copyDataTo(float*) const" remove="all"/>
+ <modify-function signature="constData()const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2043,6 +2051,7 @@
<value-type name="QMatrix3x2" since="4.6">
<modify-function signature="QMatrix3x2(const float*)" remove="all"/>
<modify-function signature="copyDataTo(float*) const" remove="all"/>
+ <modify-function signature="constData()const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2079,6 +2088,7 @@
<value-type name="QMatrix3x3" since="4.6">
<modify-function signature="QMatrix3x3(const float*)" remove="all"/>
<modify-function signature="copyDataTo(float*) const" remove="all"/>
+ <modify-function signature="constData()const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2115,6 +2125,7 @@
<value-type name="QMatrix3x4" since="4.6">
<modify-function signature="QMatrix3x4(const float*)" remove="all"/>
<modify-function signature="copyDataTo(float*) const" remove="all"/>
+ <modify-function signature="constData()const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2151,6 +2162,7 @@
<value-type name="QMatrix4x2" since="4.6">
<modify-function signature="QMatrix4x2(const float*)" remove="all"/>
<modify-function signature="copyDataTo(float*) const" remove="all"/>
+ <modify-function signature="constData()const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2187,6 +2199,7 @@
<value-type name="QMatrix4x3" since="4.6">
<modify-function signature="QMatrix4x3(const float*)" remove="all"/>
<modify-function signature="copyDataTo(float*) const" remove="all"/>
+ <modify-function signature="constData()const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2267,6 +2280,7 @@
<modify-function signature="QMatrix4x4(const float*)">
<modify-argument index="1">
<replace-type modified-type="PySequence"/>
+ <array/>
</modify-argument>
<inject-code class="target" position="beginning" file="../glue/qtgui.cpp" snippet="qmatrix4x4"/>
</modify-function>
@@ -2734,7 +2748,7 @@
<modify-argument index="3"><array/></modify-argument>
</modify-function>
<modify-function signature="^glTexParameterI?u?[fi]v\(.*$">
- <modify-argument index="3"><array/></modify-argument>
+ <modify-argument index="3"><array/></modify-argument>
</modify-function>
<modify-function signature="glUniform1uiv(int,int,const unsigned int*)">
<modify-argument index="3"><array/></modify-argument>
diff --git a/sources/pyside2/PySide2/QtOpenGL/typesystem_opengl.xml b/sources/pyside2/PySide2/QtOpenGL/typesystem_opengl.xml
index 27c51517..5e864ca4 100644
--- a/sources/pyside2/PySide2/QtOpenGL/typesystem_opengl.xml
+++ b/sources/pyside2/PySide2/QtOpenGL/typesystem_opengl.xml
@@ -221,6 +221,7 @@
<modify-function signature="setUniformValueArray(int,const GLint*,int)" rename="setUniformValueArrayInt">
<modify-argument index="2" >
<replace-type modified-type="PySequence"/>
+ <array/>
</modify-argument>
<modify-argument index="3">
<remove-argument />
@@ -237,6 +238,7 @@
<modify-function signature="setUniformValueArray(int,const GLuint*,int)" rename="setUniformValueArrayUint">
<modify-argument index="2" >
<replace-type modified-type="PySequence"/>
+ <array/>
</modify-argument>
<modify-argument index="3">
<remove-argument />
@@ -445,6 +447,7 @@
<modify-function signature="setUniformValueArray(const char*,const GLint*,int)" rename="setUniformValueArrayInt">
<modify-argument index="2" >
<replace-type modified-type="PySequence"/>
+ <array/>
</modify-argument>
<modify-argument index="3">
<remove-argument />
@@ -461,6 +464,7 @@
<modify-function signature="setUniformValueArray(const char*,const GLuint*,int)" rename="setUniformValueArrayUint">
<modify-argument index="2" >
<replace-type modified-type="PySequence"/>
+ <array/>
</modify-argument>
<modify-argument index="3">
<remove-argument />
diff --git a/sources/pyside2/PySide2/QtWinExtras/CMakeLists.txt b/sources/pyside2/PySide2/QtWinExtras/CMakeLists.txt
index cf308c31..0e0b3d58 100644
--- a/sources/pyside2/PySide2/QtWinExtras/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtWinExtras/CMakeLists.txt
@@ -1,6 +1,7 @@
project(QtWinExtras)
set(QtWinExtras_SRC
+${QtWinExtras_GEN_DIR}/qtwin_wrapper.cpp
${QtWinExtras_GEN_DIR}/qwincolorizationchangeevent_wrapper.cpp
${QtWinExtras_GEN_DIR}/qwincompositionchangeevent_wrapper.cpp
${QtWinExtras_GEN_DIR}/qwinevent_wrapper.cpp
diff --git a/sources/pyside2/PySide2/QtWinExtras/typesystem_winextras.xml b/sources/pyside2/PySide2/QtWinExtras/typesystem_winextras.xml
index ec17428a..db7416a2 100644
--- a/sources/pyside2/PySide2/QtWinExtras/typesystem_winextras.xml
+++ b/sources/pyside2/PySide2/QtWinExtras/typesystem_winextras.xml
@@ -43,6 +43,10 @@
<load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
<load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
+ <namespace-type name="QtWin">
+ <enum-type name="HBitmapFormat"/>
+ <enum-type name="WindowFlip3DPolicy"/>
+ </namespace-type>
<object-type name="QWinEvent" since="5.2"/>
<object-type name="QWinColorizationChangeEvent" since="5.2"/>
<object-type name="QWinCompositionChangeEvent" since="5.2"/>
diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp
index 930ad934..3e1bab97 100644
--- a/sources/pyside2/PySide2/glue/qtcore.cpp
+++ b/sources/pyside2/PySide2/glue/qtcore.cpp
@@ -56,6 +56,56 @@ bool py2kStrCheck(PyObject *obj)
}
// @snippet pystring-check
+// @snippet qsettings-value
+QVariant out = %CPPSELF.value(%1, %2);
+PyTypeObject *typeObj = reinterpret_cast<PyTypeObject*>(%PYARG_3);
+
+if (typeObj) {
+ if (typeObj == &PyList_Type) {
+ QByteArrayList valuesList = out.toByteArray().split(',');
+ const int valuesSize = valuesList.size();
+ if (valuesSize > 0) {
+ PyObject *list = PyList_New(valuesSize);
+ for (int i = 0; i < valuesSize; i++) {
+ PyObject *item = PyUnicode_FromString(valuesList[i].data());
+ PyList_SET_ITEM(list, i, item);
+ Py_DECREF(item);
+ }
+ %PYARG_0 = list;
+
+ } else {
+ %PYARG_0 = %CONVERTTOPYTHON[QVariant](out);
+ }
+ } else if (typeObj == &PyBytes_Type) {
+ QByteArray asByteArray = out.toByteArray();
+ %PYARG_0 = PyBytes_FromString(asByteArray.data());
+ } else if (typeObj == &PyUnicode_Type) {
+ QByteArray asByteArray = out.toByteArray();
+ %PYARG_0 = PyUnicode_FromString(asByteArray.data());
+#ifdef IS_PY3K
+ } else if (typeObj == &PyLong_Type) {
+ float asFloat = out.toFloat();
+ pyResult = PyLong_FromDouble(asFloat);
+#else
+ } else if (typeObj == &PyInt_Type) {
+ float asFloat = out.toFloat();
+ pyResult = PyInt_FromLong(long(asFloat));
+#endif
+ } else if (typeObj == &PyFloat_Type) {
+ float asFloat = out.toFloat();
+ %PYARG_0 = PyFloat_FromDouble(asFloat);
+ }
+ // TODO: PyDict_Type and PyTuple_Type
+}
+else {
+ if (out == 0)
+ %PYARG_0 = Py_None;
+ else
+ %PYARG_0 = %CONVERTTOPYTHON[QVariant](out);
+}
+
+// @snippet qsettings-value
+
// @snippet qvariant-conversion
static const char *QVariant_resolveMetaType(PyTypeObject *type, int *typeId)
{
diff --git a/sources/pyside2/PySide2/support/__init__.py b/sources/pyside2/PySide2/support/__init__.py
index dda01474..8764fb5c 100644
--- a/sources/pyside2/PySide2/support/__init__.py
+++ b/sources/pyside2/PySide2/support/__init__.py
@@ -38,3 +38,5 @@
#############################################################################
from shiboken2 import VoidPtr
+
+#eof
diff --git a/sources/pyside2/PySide2/support/deprecated.py b/sources/pyside2/PySide2/support/deprecated.py
new file mode 100644
index 00000000..8538826e
--- /dev/null
+++ b/sources/pyside2/PySide2/support/deprecated.py
@@ -0,0 +1,80 @@
+# This Python file uses the following encoding: utf-8
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+"""
+deprecated.py
+
+This module contains deprecated things that are removed from the interface.
+They are implemented in Python again, together with a deprecation warning.
+
+Functions that are to be called for
+ PySide2.<module> must be named
+ fix_for_<module> .
+
+Note that this fixing code is run after all initializations, but before the
+import is finished. But that is no problem since the module is passed in.
+"""
+
+import warnings
+from textwrap import dedent
+
+
+class PySideDeprecationWarningRemovedInQt6(Warning):
+ pass
+
+
+def constData(self):
+ cls = self.__class__
+ name = cls.__name__
+ warnings.warn(dedent("""
+ {name}.constData is unpythonic and will be removed in Qt For Python 6.0 .
+ Please use {name}.data instead."""
+ .format(**locals())), PySideDeprecationWarningRemovedInQt6, stacklevel=2)
+ return cls.data(self)
+
+
+def fix_for_QtGui(QtGui):
+ for name, cls in QtGui.__dict__.items():
+ if name.startswith("QMatrix") and "data" in cls.__dict__:
+ cls.constData = constData
+
+# eof
diff --git a/sources/pyside2/PySide2/support/generate_pyi.py b/sources/pyside2/PySide2/support/generate_pyi.py
index 294cdc91..c732227f 100644
--- a/sources/pyside2/PySide2/support/generate_pyi.py
+++ b/sources/pyside2/PySide2/support/generate_pyi.py
@@ -252,6 +252,10 @@ def generate_all_pyi(outpath, options):
from PySide2.support.signature import inspect
from PySide2.support.signature.lib.enum_sig import HintingEnumerator
+ # propagate USE_PEP563 to the mapping module.
+ # Perhaps this can be automated?
+ PySide2.support.signature.mapping.USE_PEP563 = USE_PEP563
+
outpath = outpath or os.path.dirname(PySide2.__file__)
name_list = PySide2.__all__ if options.modules == ["all"] else options.modules
errors = ", ".join(set(name_list) - set(PySide2.__all__))
diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.cpp b/sources/pyside2/libpyside/dynamicqmetaobject.cpp
index c5de54aa..857d242a 100644
--- a/sources/pyside2/libpyside/dynamicqmetaobject.cpp
+++ b/sources/pyside2/libpyside/dynamicqmetaobject.cpp
@@ -467,8 +467,17 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
data->data->signalName = Shiboken::String::toCString(key);
for (const auto &s : data->data->signatures) {
const auto sig = data->data->signalName + '(' + s.signature + ')';
- if (m_baseObject->indexOfSignal(sig) == -1)
- m_builder->addSignal(sig);
+ if (m_baseObject->indexOfSignal(sig) == -1) {
+ // Registering the parameterNames to the QMetaObject (PYSIDE-634)
+ // from:
+ // Signal(..., arguments=['...', ...]
+ // the arguments are now on data-data->signalArguments
+ if (!data->data->signalArguments->isEmpty()) {
+ m_builder->addSignal(sig).setParameterNames(*data->data->signalArguments);
+ } else {
+ m_builder->addSignal(sig);
+ }
+ }
}
}
}
diff --git a/sources/pyside2/libpyside/globalreceiverv2.cpp b/sources/pyside2/libpyside/globalreceiverv2.cpp
index 283fb9cd..84ec9268 100644
--- a/sources/pyside2/libpyside/globalreceiverv2.cpp
+++ b/sources/pyside2/libpyside/globalreceiverv2.cpp
@@ -283,7 +283,11 @@ int GlobalReceiverV2::refCount(const QObject *link) const
void GlobalReceiverV2::notify()
{
+#if QT_VERSION >= 0x050E00
const QSet<const QObject *> objSet(m_refs.cbegin(), m_refs.cend());
+#else
+ const auto objSet = QSet<const QObject *>::fromList(m_refs);
+#endif
Py_BEGIN_ALLOW_THREADS
for (const QObject *o : objSet) {
QMetaObject::disconnect(o, DESTROY_SIGNAL_ID, this, DESTROY_SLOT_ID);
diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp
index 169028f0..47a5fff4 100644
--- a/sources/pyside2/libpyside/pysidesignal.cpp
+++ b/sources/pyside2/libpyside/pysidesignal.cpp
@@ -203,14 +203,15 @@ PyTypeObject *PySideSignalInstanceTypeF(void)
int signalTpInit(PyObject *self, PyObject *args, PyObject *kwds)
{
static PyObject *emptyTuple = nullptr;
- static const char *kwlist[] = {"name", nullptr};
+ static const char *kwlist[] = {"name", "arguments", nullptr};
char *argName = nullptr;
+ PyObject *argArguments = nullptr;
if (emptyTuple == 0)
emptyTuple = PyTuple_New(0);
if (!PyArg_ParseTupleAndKeywords(emptyTuple, kwds,
- "|s:QtCore." SIGNAL_CLASS_NAME, const_cast<char **>(kwlist), &argName))
+ "|sO:QtCore." SIGNAL_CLASS_NAME, const_cast<char **>(kwlist), &argName, &argArguments))
return 0;
bool tupledArgs = false;
@@ -220,6 +221,24 @@ int signalTpInit(PyObject *self, PyObject *args, PyObject *kwds)
if (argName)
data->data->signalName = argName;
+ data->data->signalArguments = new QByteArrayList();
+ if (argArguments && PySequence_Check(argArguments)) {
+ Py_ssize_t argument_size = PySequence_Size(argArguments);
+ for (Py_ssize_t i = 0; i < argument_size; ++i) {
+ PyObject *item = PySequence_GetItem(argArguments, i);
+#ifdef IS_PY3K
+ PyObject *strObj = PyUnicode_AsUTF8String(item);
+ char *s = PyBytes_AsString(strObj);
+ Py_DECREF(strObj);
+#else
+ char *s = PyBytes_AsString(item);
+#endif
+ Py_DECREF(item);
+ if (s != nullptr)
+ data->data->signalArguments->append(QByteArray(s));
+ }
+ }
+
for (Py_ssize_t i = 0, i_max = PyTuple_Size(args); i < i_max; i++) {
PyObject *arg = PyTuple_GET_ITEM(args, i);
if (PySequence_Check(arg) && !Shiboken::String::check(arg)) {
diff --git a/sources/pyside2/libpyside/pysidesignal_p.h b/sources/pyside2/libpyside/pysidesignal_p.h
index a5cd67f6..8027f445 100644
--- a/sources/pyside2/libpyside/pysidesignal_p.h
+++ b/sources/pyside2/libpyside/pysidesignal_p.h
@@ -55,6 +55,7 @@ struct PySideSignalData
QByteArray signalName;
QVector<Signature> signatures;
+ QByteArrayList *signalArguments;
};
extern "C"
@@ -64,7 +65,7 @@ extern "C"
struct PySideSignal {
PyObject_HEAD
PySideSignalData *data;
- PyObject* homonymousMethod;
+ PyObject *homonymousMethod;
};
struct PySideSignalInstance;
diff --git a/sources/pyside2/tests/QtCore/CMakeLists.txt b/sources/pyside2/tests/QtCore/CMakeLists.txt
index 08e63d04..d05699f1 100644
--- a/sources/pyside2/tests/QtCore/CMakeLists.txt
+++ b/sources/pyside2/tests/QtCore/CMakeLists.txt
@@ -96,6 +96,7 @@ PYSIDE_TEST(qrect_test.py)
PYSIDE_TEST(qregexp_test.py)
PYSIDE_TEST(qregularexpression_test.py)
PYSIDE_TEST(qresource_test.py)
+PYSIDE_TEST(qsettings_test.py)
PYSIDE_TEST(qsize_test.py)
PYSIDE_TEST(qslot_object_test.py)
PYSIDE_TEST(qsocketnotifier_test.py)
diff --git a/sources/pyside2/tests/QtCore/qsettings_test.ini b/sources/pyside2/tests/QtCore/qsettings_test.ini
new file mode 100644
index 00000000..f54ae002
--- /dev/null
+++ b/sources/pyside2/tests/QtCore/qsettings_test.ini
@@ -0,0 +1,4 @@
+[General]
+var1=a, b, c
+var2=a
+
diff --git a/sources/pyside2/tests/QtCore/qsettings_test.py b/sources/pyside2/tests/QtCore/qsettings_test.py
new file mode 100644
index 00000000..6d64b0db
--- /dev/null
+++ b/sources/pyside2/tests/QtCore/qsettings_test.py
@@ -0,0 +1,77 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+'''Test cases for QDate'''
+
+import unittest
+
+import os
+from helper import adjust_filename
+import py3kcompat as py3k
+from PySide2.QtCore import QSettings
+
+class TestQSettings(unittest.TestCase):
+ def testConversions(self):
+ file_path = adjust_filename('qsettings_test.ini', __file__)
+ settings = QSettings(file_path, QSettings.IniFormat)
+
+ r = settings.value('var1')
+ self.assertEqual(type(r), list)
+
+ r = settings.value('var2')
+ if py3k.IS_PY3K:
+ self.assertEqual(type(r), str)
+ else:
+ self.assertEqual(type(r), unicode)
+
+ r = settings.value('var2', type=list)
+ self.assertEqual(type(r), list)
+
+
+ def testDefaultValueConversion(self):
+ settings = QSettings('foo.ini', QSettings.IniFormat)
+ r = settings.value('lala', 22)
+ if py3k.IS_PY3K:
+ self.assertEqual(type(r), int)
+ else:
+ self.assertEqual(type(r), long)
+
+ r = settings.value('lala', 22, type=str)
+ self.assertEqual(type(r), str)
+
+ r = settings.value('lala', 22, type=bytes)
+ self.assertEqual(type(r), bytes)
+
+ r = settings.value('lala', 22, type=int)
+ self.assertEqual(type(r), int)
+
+ r = settings.value('lala', 22, type=float)
+ self.assertEqual(type(r), float)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside2/tests/QtGui/CMakeLists.txt b/sources/pyside2/tests/QtGui/CMakeLists.txt
index 927e7246..172703ab 100644
--- a/sources/pyside2/tests/QtGui/CMakeLists.txt
+++ b/sources/pyside2/tests/QtGui/CMakeLists.txt
@@ -46,4 +46,4 @@ PYSIDE_TEST(qtextdocumentwriter_test.py)
PYSIDE_TEST(qtextline_test.py)
PYSIDE_TEST(qtransform_test.py)
PYSIDE_TEST(repr_test.py)
-PYSIDE_TEST(timed_app_test.py)
+PYSIDE_TEST(timed_app_and_patching_test.py)
diff --git a/sources/pyside2/tests/QtGui/timed_app_test.py b/sources/pyside2/tests/QtGui/timed_app_and_patching_test.py
index dc0e7c4b..014aeec1 100644
--- a/sources/pyside2/tests/QtGui/timed_app_test.py
+++ b/sources/pyside2/tests/QtGui/timed_app_and_patching_test.py
@@ -29,6 +29,10 @@
import unittest
from helper import TimedQApplication
+from PySide2.support import deprecated
+from PySide2.support.signature import importhandler
+from PySide2 import QtGui
+
class TestTimedApp(TimedQApplication):
'''Simple test case for TimedQApplication'''
@@ -37,5 +41,20 @@ class TestTimedApp(TimedQApplication):
#Simple test of TimedQApplication
self.app.exec_()
+
+def fix_for_QtGui(QtGui):
+ QtGui.something = 42
+
+class TestPatchingFramework(unittest.TestCase):
+ """Simple test that verifies that deprecated.py works"""
+
+ deprecated.fix_for_QtGui = fix_for_QtGui
+
+ def test_patch_works(self):
+ something = "something"
+ self.assertFalse(hasattr(QtGui, something))
+ importhandler.finish_import(QtGui)
+ self.assertTrue(hasattr(QtGui, something))
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/QtQml/CMakeLists.txt b/sources/pyside2/tests/QtQml/CMakeLists.txt
index 8460a8f0..e2beb951 100755..100644
--- a/sources/pyside2/tests/QtQml/CMakeLists.txt
+++ b/sources/pyside2/tests/QtQml/CMakeLists.txt
@@ -18,3 +18,4 @@ PYSIDE_TEST(registertype.py)
PYSIDE_TEST(javascript_exceptions.py)
PYSIDE_TEST(qqmlincubator_incubateWhile.py)
PYSIDE_TEST(qquickitem_grabToImage.py)
+PYSIDE_TEST(signal_arguments.py)
diff --git a/sources/pyside2/tests/QtQml/bug_1029.py b/sources/pyside2/tests/QtQml/bug_1029.py
index 92734cb3..92734cb3 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_1029.py
+++ b/sources/pyside2/tests/QtQml/bug_1029.py
diff --git a/sources/pyside2/tests/QtQml/bug_1029.qml b/sources/pyside2/tests/QtQml/bug_1029.qml
index 000a7568..000a7568 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_1029.qml
+++ b/sources/pyside2/tests/QtQml/bug_1029.qml
diff --git a/sources/pyside2/tests/QtQml/bug_451.py b/sources/pyside2/tests/QtQml/bug_451.py
index 5a6df7ff..5a6df7ff 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_451.py
+++ b/sources/pyside2/tests/QtQml/bug_451.py
diff --git a/sources/pyside2/tests/QtQml/bug_451.qml b/sources/pyside2/tests/QtQml/bug_451.qml
index 71bf691b..71bf691b 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_451.qml
+++ b/sources/pyside2/tests/QtQml/bug_451.qml
diff --git a/sources/pyside2/tests/QtQml/bug_456.py b/sources/pyside2/tests/QtQml/bug_456.py
index 9c94e76a..9c94e76a 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_456.py
+++ b/sources/pyside2/tests/QtQml/bug_456.py
diff --git a/sources/pyside2/tests/QtQml/bug_456.qml b/sources/pyside2/tests/QtQml/bug_456.qml
index 9b1b8c03..9b1b8c03 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_456.qml
+++ b/sources/pyside2/tests/QtQml/bug_456.qml
diff --git a/sources/pyside2/tests/QtQml/bug_557.py b/sources/pyside2/tests/QtQml/bug_557.py
index bc18ba2a..bc18ba2a 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_557.py
+++ b/sources/pyside2/tests/QtQml/bug_557.py
diff --git a/sources/pyside2/tests/QtQml/bug_726.py b/sources/pyside2/tests/QtQml/bug_726.py
index 20fa4d19..20fa4d19 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_726.py
+++ b/sources/pyside2/tests/QtQml/bug_726.py
diff --git a/sources/pyside2/tests/QtQml/bug_726.qml b/sources/pyside2/tests/QtQml/bug_726.qml
index 79f96024..79f96024 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_726.qml
+++ b/sources/pyside2/tests/QtQml/bug_726.qml
diff --git a/sources/pyside2/tests/QtQml/bug_814.py b/sources/pyside2/tests/QtQml/bug_814.py
index 31eada2d..31eada2d 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_814.py
+++ b/sources/pyside2/tests/QtQml/bug_814.py
diff --git a/sources/pyside2/tests/QtQml/bug_814.qml b/sources/pyside2/tests/QtQml/bug_814.qml
index 41189677..41189677 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_814.qml
+++ b/sources/pyside2/tests/QtQml/bug_814.qml
diff --git a/sources/pyside2/tests/QtQml/bug_825.py b/sources/pyside2/tests/QtQml/bug_825.py
index fe67f64b..fe67f64b 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_825.py
+++ b/sources/pyside2/tests/QtQml/bug_825.py
diff --git a/sources/pyside2/tests/QtQml/bug_825.qml b/sources/pyside2/tests/QtQml/bug_825.qml
index 6ae06d5b..6ae06d5b 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_825.qml
+++ b/sources/pyside2/tests/QtQml/bug_825.qml
diff --git a/sources/pyside2/tests/QtQml/bug_847.py b/sources/pyside2/tests/QtQml/bug_847.py
index c3827853..c3827853 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_847.py
+++ b/sources/pyside2/tests/QtQml/bug_847.py
diff --git a/sources/pyside2/tests/QtQml/bug_847.qml b/sources/pyside2/tests/QtQml/bug_847.qml
index 3833b163..3833b163 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_847.qml
+++ b/sources/pyside2/tests/QtQml/bug_847.qml
diff --git a/sources/pyside2/tests/QtQml/bug_915.py b/sources/pyside2/tests/QtQml/bug_915.py
index b0f231ae..b0f231ae 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_915.py
+++ b/sources/pyside2/tests/QtQml/bug_915.py
diff --git a/sources/pyside2/tests/QtQml/bug_926.py b/sources/pyside2/tests/QtQml/bug_926.py
index 6eef7b1a..6eef7b1a 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_926.py
+++ b/sources/pyside2/tests/QtQml/bug_926.py
diff --git a/sources/pyside2/tests/QtQml/bug_926.qml b/sources/pyside2/tests/QtQml/bug_926.qml
index 9217403a..9217403a 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_926.qml
+++ b/sources/pyside2/tests/QtQml/bug_926.qml
diff --git a/sources/pyside2/tests/QtQml/bug_951.py b/sources/pyside2/tests/QtQml/bug_951.py
index 38cf597e..38cf597e 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_951.py
+++ b/sources/pyside2/tests/QtQml/bug_951.py
diff --git a/sources/pyside2/tests/QtQml/bug_951.qml b/sources/pyside2/tests/QtQml/bug_951.qml
index 8242223f..8242223f 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_951.qml
+++ b/sources/pyside2/tests/QtQml/bug_951.qml
diff --git a/sources/pyside2/tests/QtQml/bug_995.py b/sources/pyside2/tests/QtQml/bug_995.py
index 7363f0e1..7363f0e1 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_995.py
+++ b/sources/pyside2/tests/QtQml/bug_995.py
diff --git a/sources/pyside2/tests/QtQml/bug_995.qml b/sources/pyside2/tests/QtQml/bug_995.qml
index 1369dcca..1369dcca 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_995.qml
+++ b/sources/pyside2/tests/QtQml/bug_995.qml
diff --git a/sources/pyside2/tests/QtQml/bug_997.py b/sources/pyside2/tests/QtQml/bug_997.py
index 45c777f8..45c777f8 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_997.py
+++ b/sources/pyside2/tests/QtQml/bug_997.py
diff --git a/sources/pyside2/tests/QtQml/bug_997.qml b/sources/pyside2/tests/QtQml/bug_997.qml
index f36a7e8f..f36a7e8f 100755..100644
--- a/sources/pyside2/tests/QtQml/bug_997.qml
+++ b/sources/pyside2/tests/QtQml/bug_997.qml
diff --git a/sources/pyside2/tests/QtQml/connect_python_qml.qml b/sources/pyside2/tests/QtQml/connect_python_qml.qml
index 249debf9..249debf9 100755..100644
--- a/sources/pyside2/tests/QtQml/connect_python_qml.qml
+++ b/sources/pyside2/tests/QtQml/connect_python_qml.qml
diff --git a/sources/pyside2/tests/QtQml/hw.qml b/sources/pyside2/tests/QtQml/hw.qml
index 8b086f31..8b086f31 100755..100644
--- a/sources/pyside2/tests/QtQml/hw.qml
+++ b/sources/pyside2/tests/QtQml/hw.qml
diff --git a/sources/pyside2/tests/QtQml/qqmlnetwork_test.py b/sources/pyside2/tests/QtQml/qqmlnetwork_test.py
index 3e6d1c2a..3e6d1c2a 100755..100644
--- a/sources/pyside2/tests/QtQml/qqmlnetwork_test.py
+++ b/sources/pyside2/tests/QtQml/qqmlnetwork_test.py
diff --git a/sources/pyside2/tests/QtQml/qquickview_test.py b/sources/pyside2/tests/QtQml/qquickview_test.py
index 62b20738..62b20738 100755..100644
--- a/sources/pyside2/tests/QtQml/qquickview_test.py
+++ b/sources/pyside2/tests/QtQml/qquickview_test.py
diff --git a/sources/pyside2/tests/QtQml/registertype.py b/sources/pyside2/tests/QtQml/registertype.py
index 5be65b7b..5be65b7b 100755..100644
--- a/sources/pyside2/tests/QtQml/registertype.py
+++ b/sources/pyside2/tests/QtQml/registertype.py
diff --git a/sources/pyside2/tests/QtQml/registertype.qml b/sources/pyside2/tests/QtQml/registertype.qml
index c4122601..c4122601 100755..100644
--- a/sources/pyside2/tests/QtQml/registertype.qml
+++ b/sources/pyside2/tests/QtQml/registertype.qml
diff --git a/sources/pyside2/tests/QtQml/signal_arguments.py b/sources/pyside2/tests/QtQml/signal_arguments.py
new file mode 100644
index 00000000..096fa688
--- /dev/null
+++ b/sources/pyside2/tests/QtQml/signal_arguments.py
@@ -0,0 +1,67 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import unittest
+from helper import adjust_filename, TimedQApplication
+from PySide2.QtQuick import QQuickView
+from PySide2.QtCore import QObject, Signal, Slot, QUrl, QTimer, Property
+
+class Obj(QObject):
+ def __init__(self):
+ QObject.__init__(self)
+ self.value = 0
+
+ sumResult = Signal(int, name="sumResult", arguments=['sum'])
+
+ @Slot(int, int)
+ def sum(self, arg1, arg2):
+ self.sumResult.emit(arg1 + arg2)
+
+ @Slot(str)
+ def sendValue(self, s):
+ self.value = int(s)
+
+
+class TestConnectionWithQml(TimedQApplication):
+
+ def testSignalArguments(self):
+ view = QQuickView()
+ obj = Obj()
+
+ context = view.rootContext()
+ context.setContextProperty("o", obj)
+ view.setSource(QUrl.fromLocalFile(adjust_filename('signal_arguments.qml', __file__)))
+ root = view.rootObject()
+ self.assertTrue(root)
+ button = root.findChild(QObject, "button")
+ view.show()
+ button.clicked.emit()
+ self.assertEqual(obj.value, 42)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside2/tests/QtQml/signal_arguments.qml b/sources/pyside2/tests/QtQml/signal_arguments.qml
new file mode 100644
index 00000000..0c65b947
--- /dev/null
+++ b/sources/pyside2/tests/QtQml/signal_arguments.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import QtQuick.Layouts 1.2
+
+Rectangle {
+ visible: true
+ GridLayout {
+ Button {
+ id: "button"
+ objectName: "button"
+ text: "sum!"
+ onClicked: {
+ o.sum(40, 2)
+ }
+ }
+ Text {
+ id: sumResultText
+ }
+ }
+ Connections {
+ target: o
+ onSumResult: {
+ // set the value on the Qml side
+ sumResultText.text = sum
+ // set internal Python value from the already
+ // modified value
+ o.sendValue(sumResultText.text)
+ }
+ }
+}
diff --git a/sources/pyside2/tests/QtQml/view.qml b/sources/pyside2/tests/QtQml/view.qml
index dcc0076a..dcc0076a 100755..100644
--- a/sources/pyside2/tests/QtQml/view.qml
+++ b/sources/pyside2/tests/QtQml/view.qml
diff --git a/sources/pyside2/tests/QtQml/viewmodel.qml b/sources/pyside2/tests/QtQml/viewmodel.qml
index 61366a73..61366a73 100755..100644
--- a/sources/pyside2/tests/QtQml/viewmodel.qml
+++ b/sources/pyside2/tests/QtQml/viewmodel.qml
diff --git a/sources/shiboken2/ApiExtractor/CMakeLists.txt b/sources/shiboken2/ApiExtractor/CMakeLists.txt
index 6cc8cd58..c8a5fb33 100644
--- a/sources/shiboken2/ApiExtractor/CMakeLists.txt
+++ b/sources/shiboken2/ApiExtractor/CMakeLists.txt
@@ -15,6 +15,7 @@ messages.cpp
reporthandler.cpp
typeparser.cpp
typesystem.cpp
+typesystemparser.cpp
include.cpp
typedatabase.cpp
# Clang
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
index c91ac4dd..9c930dcd 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
@@ -1052,6 +1052,10 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem
reason = AbstractMetaBuilder::GenerationDisabled;
}
if (reason != AbstractMetaBuilder::NoReason) {
+ if (fullClassName.isEmpty()) {
+ QTextStream(&fullClassName) << "anonymous struct at " << classItem->fileName()
+ << ':' << classItem->startLine();
+ }
m_rejectedClasses.insert(fullClassName, reason);
return nullptr;
}
@@ -1594,7 +1598,11 @@ void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem,
const QStringList &enumsDeclarations)
{
const EnumList &enums = scopeItem->enums();
+#if QT_VERSION >= 0x050E00
const QSet<QString> enumsDeclarationSet(enumsDeclarations.cbegin(), enumsDeclarations.cend());
+#else
+ const QSet<QString> enumsDeclarationSet = QSet<QString>::fromList(enumsDeclarations);
+#endif
for (const EnumModelItem &enumItem : enums) {
AbstractMetaEnum* metaEnum = traverseEnum(enumItem, metaClass, enumsDeclarationSet);
if (metaEnum) {
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
index 455140e5..4ca448d5 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -268,6 +268,15 @@ QString AbstractMetaType::cppSignature() const
return m_cachedCppSignature;
}
+QString AbstractMetaType::pythonSignature() const
+{
+ // PYSIDE-921: Handle container returntypes correctly.
+ // This is now a clean reimplementation.
+ if (m_cachedPythonSignature.isEmpty())
+ m_cachedPythonSignature = formatPythonSignature(false);
+ return m_cachedPythonSignature;
+}
+
AbstractMetaType::TypeUsagePattern AbstractMetaType::determineUsagePattern() const
{
if (m_typeEntry->isTemplateArgument() || m_referenceType == RValueReference)
@@ -2555,6 +2564,58 @@ QString AbstractMetaType::formatSignature(bool minimal) const
return result;
}
+QString AbstractMetaType::formatPythonSignature(bool minimal) const
+{
+ /*
+ * This is a version of the above, more suitable for Python.
+ * We avoid extra keywords that are not needed in Python.
+ * We prepend the package name, unless it is a primitive type.
+ *
+ * Primitive types like 'int', 'char' etc.:
+ * When we have a primitive with an indirection, we use that '*'
+ * character for later postprocessing, since those indirections
+ * need to be modified into a result tuple.
+ */
+ QString result;
+ if (m_pattern == AbstractMetaType::NativePointerAsArrayPattern)
+ result += QLatin1String("array ");
+ // We no longer use the "const" qualifier for heuristics. Instead,
+ // NativePointerAsArrayPattern indicates when we have <array> in XML.
+ // if (m_typeEntry->isPrimitive() && isConstant())
+ // result += QLatin1String("const ");
+ if (!m_typeEntry->isPrimitive() && !package().isEmpty())
+ result += package() + QLatin1Char('.');
+ if (isArray()) {
+ // Build nested array dimensions a[2][3] in correct order
+ result += m_arrayElementType->formatPythonSignature(true);
+ const int arrayPos = result.indexOf(QLatin1Char('['));
+ if (arrayPos != -1)
+ result.insert(arrayPos, formatArraySize(m_arrayElementCount));
+ else
+ result.append(formatArraySize(m_arrayElementCount));
+ } else {
+ result += typeEntry()->qualifiedCppName();
+ }
+ if (!m_instantiations.isEmpty()) {
+ result += QLatin1Char('[');
+ for (int i = 0, size = m_instantiations.size(); i < size; ++i) {
+ if (i > 0)
+ result += QLatin1String(", ");
+ result += m_instantiations.at(i)->formatPythonSignature(true);
+ }
+ result += QLatin1Char(']');
+ }
+ if (m_typeEntry->isPrimitive())
+ for (Indirection i : m_indirections)
+ result += TypeInfo::indirectionKeyword(i);
+ // If it is a flags type, we replace it with the full name:
+ // "PySide2.QtCore.Qt.ItemFlags" instead of "PySide2.QtCore.QFlags<Qt.ItemFlag>"
+ if (m_typeEntry->isFlags())
+ result = fullName();
+ result.replace(QLatin1String("::"), QLatin1String("."));
+ return result;
+}
+
bool AbstractMetaType::isCppPrimitive() const
{
return m_pattern == PrimitivePattern && m_typeEntry->isCppPrimitive();
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h
index afb4e5fb..7f0f9fba 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -483,6 +483,8 @@ public:
QString cppSignature() const;
+ QString pythonSignature() const;
+
AbstractMetaType *copy() const;
bool applyArrayModification(QString *errorMessage);
@@ -540,12 +542,14 @@ public:
private:
TypeUsagePattern determineUsagePattern() const;
QString formatSignature(bool minimal) const;
+ QString formatPythonSignature(bool minimal) const;
const TypeEntry *m_typeEntry = nullptr;
AbstractMetaTypeList m_instantiations;
QString m_package;
mutable QString m_name;
mutable QString m_cachedCppSignature;
+ mutable QString m_cachedPythonSignature;
QString m_originalTypeDescription;
int m_arrayElementCount = -1;
diff --git a/sources/shiboken2/ApiExtractor/messages.cpp b/sources/shiboken2/ApiExtractor/messages.cpp
index a6e75aac..5b3a57fc 100644
--- a/sources/shiboken2/ApiExtractor/messages.cpp
+++ b/sources/shiboken2/ApiExtractor/messages.cpp
@@ -311,6 +311,23 @@ QString msgCannotUseEnumAsInt(const QString &name)
"Compilation errors may occur when used as a function argument.");
}
+QString msgConversionTypesDiffer(const QString &varType, const QString &conversionType)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Types of receiver variable ('" << varType
+ << "') and %%CONVERTTOCPP type system variable ('" << conversionType
+ << "') differ";
+ QString strippedVarType = varType;
+ QString strippedConversionType = conversionType;
+ TypeInfo::stripQualifiers(&strippedVarType);
+ TypeInfo::stripQualifiers(&strippedConversionType);
+ if (strippedVarType == strippedConversionType)
+ str << " in qualifiers. Please make sure the type is a distinct token";
+ str << '.';
+ return result;
+}
+
// main.cpp
QString msgLeftOverArguments(const QMap<QString, QString> &remainingArgs)
diff --git a/sources/shiboken2/ApiExtractor/messages.h b/sources/shiboken2/ApiExtractor/messages.h
index ab2bf64b..2fee0de8 100644
--- a/sources/shiboken2/ApiExtractor/messages.h
+++ b/sources/shiboken2/ApiExtractor/messages.h
@@ -115,6 +115,8 @@ QString msgCannotOpenForWriting(const QFile &f);
QString msgCannotUseEnumAsInt(const QString &name);
+QString msgConversionTypesDiffer(const QString &varType, const QString &conversionType);
+
QString msgLeftOverArguments(const QMap<QString, QString> &remainingArgs);
QString msgInvalidVersion(const QString &package, const QString &version);
diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.h b/sources/shiboken2/ApiExtractor/parser/codemodel.h
index 777b2d10..80db2cce 100644
--- a/sources/shiboken2/ApiExtractor/parser/codemodel.h
+++ b/sources/shiboken2/ApiExtractor/parser/codemodel.h
@@ -287,6 +287,7 @@ public:
FileModelItem file() const;
void getStartPosition(int *line, int *column);
+ int startLine() const { return m_startLine; }
void setStartPosition(int line, int column);
void getEndPosition(int *line, int *column);
diff --git a/sources/shiboken2/ApiExtractor/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp
index 144795c6..4f8887bd 100644
--- a/sources/shiboken2/ApiExtractor/typedatabase.cpp
+++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -28,7 +28,7 @@
#include "typedatabase.h"
#include "typesystem.h"
-#include "typesystem_p.h"
+#include "typesystemparser.h"
#include <QtCore/QFile>
#include <QtCore/QDebug>
@@ -572,7 +572,7 @@ bool TypeDatabase::parseFile(const QString &filename, const QString &currentPath
bool TypeDatabase::parseFile(QIODevice* device, bool generate)
{
QXmlStreamReader reader(device);
- Handler handler(this, generate);
+ TypeSystemParser handler(this, generate);
const bool result = handler.parse(reader);
if (!result)
qCWarning(lcShiboken, "%s", qPrintable(handler.errorString()));
diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp
index 65e3443d..fa141670 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.cpp
+++ b/sources/shiboken2/ApiExtractor/typesystem.cpp
@@ -27,2962 +27,22 @@
****************************************************************************/
#include "typesystem.h"
-#include "typesystem_p.h"
#include "typedatabase.h"
#include "messages.h"
-#include "reporthandler.h"
-#include <QtCore/QDir>
-#include <QtCore/QFile>
-#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
#include <QtCore/QRegularExpression>
#include <QtCore/QSet>
-#include <QtCore/QStringView>
-#include <QtCore/QStringAlgorithms>
-#include <QtCore/QXmlStreamAttributes>
-#include <QtCore/QXmlStreamReader>
-#include <QtCore/QXmlStreamEntityResolver>
#include <algorithm>
-const char *TARGET_CONVERSION_RULE_FLAG = "0";
-const char *NATIVE_CONVERSION_RULE_FLAG = "1";
-
static QString strings_Object = QLatin1String("Object");
static QString strings_String = QLatin1String("String");
static QString strings_char = QLatin1String("char");
static QString strings_jchar = QLatin1String("jchar");
static QString strings_jobject = QLatin1String("jobject");
-static inline QString allowThreadAttribute() { return QStringLiteral("allow-thread"); }
-static inline QString colonColon() { return QStringLiteral("::"); }
-static inline QString copyableAttribute() { return QStringLiteral("copyable"); }
-static inline QString accessAttribute() { return QStringLiteral("access"); }
-static inline QString actionAttribute() { return QStringLiteral("action"); }
-static inline QString quoteAfterLineAttribute() { return QStringLiteral("quote-after-line"); }
-static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote-before-line"); }
-static inline QString textAttribute() { return QStringLiteral("text"); }
-static inline QString nameAttribute() { return QStringLiteral("name"); }
-static inline QString sinceAttribute() { return QStringLiteral("since"); }
-static inline QString defaultSuperclassAttribute() { return QStringLiteral("default-superclass"); }
-static inline QString deleteInMainThreadAttribute() { return QStringLiteral("delete-in-main-thread"); }
-static inline QString deprecatedAttribute() { return QStringLiteral("deprecated"); }
-static inline QString exceptionHandlingAttribute() { return QStringLiteral("exception-handling"); }
-static inline QString extensibleAttribute() { return QStringLiteral("extensible"); }
-static inline QString flagsAttribute() { return QStringLiteral("flags"); }
-static inline QString forceAbstractAttribute() { return QStringLiteral("force-abstract"); }
-static inline QString forceIntegerAttribute() { return QStringLiteral("force-integer"); }
-static inline QString formatAttribute() { return QStringLiteral("format"); }
-static inline QString classAttribute() { return QStringLiteral("class"); }
-static inline QString generateAttribute() { return QStringLiteral("generate"); }
-static inline QString genericClassAttribute() { return QStringLiteral("generic-class"); }
-static inline QString indexAttribute() { return QStringLiteral("index"); }
-static inline QString invalidateAfterUseAttribute() { return QStringLiteral("invalidate-after-use"); }
-static inline QString locationAttribute() { return QStringLiteral("location"); }
-static inline QString modifiedTypeAttribute() { return QStringLiteral("modified-type"); }
-static inline QString modifierAttribute() { return QStringLiteral("modifier"); }
-static inline QString ownershipAttribute() { return QStringLiteral("owner"); }
-static inline QString packageAttribute() { return QStringLiteral("package"); }
-static inline QString positionAttribute() { return QStringLiteral("position"); }
-static inline QString preferredConversionAttribute() { return QStringLiteral("preferred-conversion"); }
-static inline QString preferredTargetLangTypeAttribute() { return QStringLiteral("preferred-target-lang-type"); }
-static inline QString removeAttribute() { return QStringLiteral("remove"); }
-static inline QString renameAttribute() { return QStringLiteral("rename"); }
-static inline QString readAttribute() { return QStringLiteral("read"); }
-static inline QString writeAttribute() { return QStringLiteral("write"); }
-static inline QString replaceAttribute() { return QStringLiteral("replace"); }
-static inline QString toAttribute() { return QStringLiteral("to"); }
-static inline QString signatureAttribute() { return QStringLiteral("signature"); }
-static inline QString snippetAttribute() { return QStringLiteral("snippet"); }
-static inline QString staticAttribute() { return QStringLiteral("static"); }
-static inline QString threadAttribute() { return QStringLiteral("thread"); }
-static inline QString sourceAttribute() { return QStringLiteral("source"); }
-static inline QString streamAttribute() { return QStringLiteral("stream"); }
-static inline QString xPathAttribute() { return QStringLiteral("xpath"); }
-static inline QString virtualSlotAttribute() { return QStringLiteral("virtual-slot"); }
-static inline QString enumIdentifiedByValueAttribute() { return QStringLiteral("identified-by-value"); }
-
-static inline QString noAttributeValue() { return QStringLiteral("no"); }
-static inline QString yesAttributeValue() { return QStringLiteral("yes"); }
-static inline QString trueAttributeValue() { return QStringLiteral("true"); }
-static inline QString falseAttributeValue() { return QStringLiteral("false"); }
-
static inline QString callOperator() { return QStringLiteral("operator()"); }
-static QVector<CustomConversion *> customConversionsForReview;
-
-// Set a regular expression for rejection from text. By legacy, those are fixed
-// strings, except for '*' meaning 'match all'. Enclosing in "^..$"
-// indicates regular expression.
-static bool setRejectionRegularExpression(const QString &patternIn,
- QRegularExpression *re,
- QString *errorMessage)
-{
- QString pattern;
- if (patternIn.startsWith(QLatin1Char('^')) && patternIn.endsWith(QLatin1Char('$')))
- pattern = patternIn;
- else if (patternIn == QLatin1String("*"))
- pattern = QStringLiteral("^.*$");
- else
- pattern = QLatin1Char('^') + QRegularExpression::escape(patternIn) + QLatin1Char('$');
- re->setPattern(pattern);
- if (!re->isValid()) {
- *errorMessage = msgInvalidRegularExpression(patternIn, re->errorString());
- return false;
- }
- return true;
-}
-
-// Extract a snippet from a file within annotation "// @snippet label".
-static QString extractSnippet(const QString &code, const QString &snippetLabel)
-{
- if (snippetLabel.isEmpty())
- return code;
- const QString pattern = QStringLiteral(R"(^\s*//\s*@snippet\s+)")
- + QRegularExpression::escape(snippetLabel)
- + QStringLiteral(R"(\s*$)");
- const QRegularExpression snippetRe(pattern);
- Q_ASSERT(snippetRe.isValid());
-
- bool useLine = false;
- QString result;
- const auto lines = code.splitRef(QLatin1Char('\n'));
- for (const QStringRef &line : lines) {
- if (snippetRe.match(line).hasMatch()) {
- useLine = !useLine;
- if (!useLine)
- break; // End of snippet reached
- } else if (useLine)
- result += line.toString() + QLatin1Char('\n');
- }
- return result;
-}
-
-template <class EnumType, Qt::CaseSensitivity cs = Qt::CaseInsensitive>
-struct EnumLookup
-{
- QStringView name;
- EnumType value;
-};
-
-template <class EnumType, Qt::CaseSensitivity cs>
-bool operator==(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2)
-{
- return e1.name.compare(e2.name, cs) == 0;
-}
-
-template <class EnumType, Qt::CaseSensitivity cs>
-bool operator<(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2)
-{
- return e1.name.compare(e2.name, cs) < 0;
-}
-
-// Helper macros to define lookup functions that take a QStringView needle
-// and an optional default return value.
-#define ENUM_LOOKUP_BEGIN(EnumType, caseSensitivity, functionName, defaultReturnValue) \
-static EnumType functionName(QStringView needle, EnumType defaultValue = defaultReturnValue) \
-{ \
- typedef EnumLookup<EnumType, caseSensitivity> HaystackEntry; \
- static const HaystackEntry haystack[] =
-
-#define ENUM_LOOKUP_LINEAR_SEARCH() \
- const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \
- const auto it = std::find(haystack, end, HaystackEntry{needle, defaultValue}); \
- return it != end ? it->value : defaultValue; \
-}
-
-#define ENUM_LOOKUP_BINARY_SEARCH() \
- const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \
- const HaystackEntry needleEntry{needle, defaultValue}; \
- const auto lb = std::lower_bound(haystack, end, needleEntry); \
- return lb != end && *lb == needleEntry ? lb->value : defaultValue; \
-}
-
-ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive,
- allowThreadFromAttribute, TypeSystem::AllowThread::Unspecified)
- {
- {QStringViewLiteral("yes"), TypeSystem::AllowThread::Allow},
- {QStringViewLiteral("true"), TypeSystem::AllowThread::Allow},
- {QStringViewLiteral("auto"), TypeSystem::AllowThread::Auto},
- {QStringViewLiteral("no"), TypeSystem::AllowThread::Disallow},
- {QStringViewLiteral("false"), TypeSystem::AllowThread::Disallow},
- };
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive,
- languageFromAttribute, TypeSystem::NoLanguage)
- {
- {QStringViewLiteral("all"), TypeSystem::All}, // sorted!
- {QStringViewLiteral("constructors"), TypeSystem::Constructors},
- {QStringViewLiteral("destructor-function"), TypeSystem::DestructorFunction},
- {QStringViewLiteral("interface"), TypeSystem::Interface},
- {QStringViewLiteral("library-initializer"), TypeSystem::PackageInitializer},
- {QStringViewLiteral("native"), TypeSystem::NativeCode}, // em algum lugar do cpp
- {QStringViewLiteral("shell"), TypeSystem::ShellCode}, // coloca no header, mas antes da declaracao da classe
- {QStringViewLiteral("shell-declaration"), TypeSystem::ShellDeclaration},
- {QStringViewLiteral("target"), TypeSystem::TargetLangCode} // em algum lugar do cpp
- };
-ENUM_LOOKUP_BINARY_SEARCH()
-
-ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive,
- ownershipFromFromAttribute, TypeSystem::InvalidOwnership)
- {
- {QStringViewLiteral("target"), TypeSystem::TargetLangOwnership},
- {QStringViewLiteral("c++"), TypeSystem::CppOwnership},
- {QStringViewLiteral("default"), TypeSystem::DefaultOwnership}
- };
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive,
- addedFunctionAccessFromAttribute, AddedFunction::InvalidAccess)
- {
- {QStringViewLiteral("public"), AddedFunction::Public},
- {QStringViewLiteral("protected"), AddedFunction::Protected},
- };
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(Modification::Modifiers, Qt::CaseSensitive,
- modifierFromAttribute, Modification::InvalidModifier)
- {
- {QStringViewLiteral("private"), Modification::Private},
- {QStringViewLiteral("public"), Modification::Public},
- {QStringViewLiteral("protected"), Modification::Protected},
- {QStringViewLiteral("friendly"), Modification::Friendly},
- {QStringViewLiteral("rename"), Modification::Rename},
- {QStringViewLiteral("final"), Modification::Final},
- {QStringViewLiteral("non-final"), Modification::NonFinal}
- };
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive,
- referenceCountFromAttribute, ReferenceCount::Invalid)
- {
- {QStringViewLiteral("add"), ReferenceCount::Add},
- {QStringViewLiteral("add-all"), ReferenceCount::AddAll},
- {QStringViewLiteral("remove"), ReferenceCount::Remove},
- {QStringViewLiteral("set"), ReferenceCount::Set},
- {QStringViewLiteral("ignore"), ReferenceCount::Ignore}
- };
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive,
- argumentOwnerActionFromAttribute, ArgumentOwner::Invalid)
- {
- {QStringViewLiteral("add"), ArgumentOwner::Add},
- {QStringViewLiteral("remove"), ArgumentOwner::Remove}
- };
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(TypeSystem::CodeSnipPosition, Qt::CaseInsensitive,
- codeSnipPositionFromAttribute, TypeSystem::CodeSnipPositionInvalid)
- {
- {QStringViewLiteral("beginning"), TypeSystem::CodeSnipPositionBeginning},
- {QStringViewLiteral("end"), TypeSystem::CodeSnipPositionEnd},
- {QStringViewLiteral("declaration"), TypeSystem::CodeSnipPositionDeclaration},
- {QStringViewLiteral("prototype-initialization"), TypeSystem::CodeSnipPositionPrototypeInitialization},
- {QStringViewLiteral("constructor-initialization"), TypeSystem::CodeSnipPositionConstructorInitialization},
- {QStringViewLiteral("constructor"), TypeSystem::CodeSnipPositionConstructor}
- };
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive,
- locationFromAttribute, Include::InvalidInclude)
- {
- {QStringViewLiteral("global"), Include::IncludePath},
- {QStringViewLiteral("local"), Include::LocalPath},
- {QStringViewLiteral("target"), Include::TargetLangImport}
- };
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive,
- docModificationFromAttribute, TypeSystem::DocModificationInvalid)
- {
- {QStringViewLiteral("append"), TypeSystem::DocModificationAppend},
- {QStringViewLiteral("prepend"), TypeSystem::DocModificationPrepend},
- {QStringViewLiteral("replace"), TypeSystem::DocModificationReplace}
- };
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(ContainerTypeEntry::Type, Qt::CaseSensitive,
- containerTypeFromAttribute, ContainerTypeEntry::NoContainer)
- {
- {QStringViewLiteral("list"), ContainerTypeEntry::ListContainer},
- {QStringViewLiteral("string-list"), ContainerTypeEntry::StringListContainer},
- {QStringViewLiteral("linked-list"), ContainerTypeEntry::LinkedListContainer},
- {QStringViewLiteral("vector"), ContainerTypeEntry::VectorContainer},
- {QStringViewLiteral("stack"), ContainerTypeEntry::StackContainer},
- {QStringViewLiteral("queue"), ContainerTypeEntry::QueueContainer},
- {QStringViewLiteral("set"), ContainerTypeEntry::SetContainer},
- {QStringViewLiteral("map"), ContainerTypeEntry::MapContainer},
- {QStringViewLiteral("multi-map"), ContainerTypeEntry::MultiMapContainer},
- {QStringViewLiteral("hash"), ContainerTypeEntry::HashContainer},
- {QStringViewLiteral("multi-hash"), ContainerTypeEntry::MultiHashContainer},
- {QStringViewLiteral("pair"), ContainerTypeEntry::PairContainer}
- };
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive,
- typeRejectionFromAttribute, TypeRejection::Invalid)
- {
- {QStringViewLiteral("class"), TypeRejection::ExcludeClass},
- {QStringViewLiteral("function-name"), TypeRejection::Function},
- {QStringViewLiteral("field-name"), TypeRejection::Field},
- {QStringViewLiteral("enum-name"), TypeRejection::Enum },
- {QStringViewLiteral("argument-type"), TypeRejection::ArgumentType},
- {QStringViewLiteral("return-type"), TypeRejection::ReturnType}
- };
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive,
- exceptionHandlingFromAttribute, TypeSystem::ExceptionHandling::Unspecified)
-{
- {QStringViewLiteral("no"), TypeSystem::ExceptionHandling::Off},
- {QStringViewLiteral("false"), TypeSystem::ExceptionHandling::Off},
- {QStringViewLiteral("auto-off"), TypeSystem::ExceptionHandling::AutoDefaultToOff},
- {QStringViewLiteral("auto-on"), TypeSystem::ExceptionHandling::AutoDefaultToOn},
- {QStringViewLiteral("yes"), TypeSystem::ExceptionHandling::On},
- {QStringViewLiteral("true"), TypeSystem::ExceptionHandling::On},
-};
-ENUM_LOOKUP_LINEAR_SEARCH()
-
-ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive,
- elementFromTag, StackElement::None)
- {
- {QStringViewLiteral("access"), StackElement::Access}, // sorted!
- {QStringViewLiteral("add-conversion"), StackElement::AddConversion},
- {QStringViewLiteral("add-function"), StackElement::AddFunction},
- {QStringViewLiteral("argument-map"), StackElement::ArgumentMap},
- {QStringViewLiteral("array"), StackElement::Array},
- {QStringViewLiteral("container-type"), StackElement::ContainerTypeEntry},
- {QStringViewLiteral("conversion-rule"), StackElement::ConversionRule},
- {QStringViewLiteral("custom-constructor"), StackElement::CustomMetaConstructor},
- {QStringViewLiteral("custom-destructor"), StackElement::CustomMetaDestructor},
- {QStringViewLiteral("custom-type"), StackElement::CustomTypeEntry},
- {QStringViewLiteral("define-ownership"), StackElement::DefineOwnership},
- {QStringViewLiteral("enum-type"), StackElement::EnumTypeEntry},
- {QStringViewLiteral("extra-includes"), StackElement::ExtraIncludes},
- {QStringViewLiteral("function"), StackElement::FunctionTypeEntry},
- {QStringViewLiteral("include"), StackElement::Include},
- {QStringViewLiteral("inject-code"), StackElement::InjectCode},
- {QStringViewLiteral("inject-documentation"), StackElement::InjectDocumentation},
- {QStringViewLiteral("insert-template"), StackElement::TemplateInstanceEnum},
- {QStringViewLiteral("interface-type"), StackElement::InterfaceTypeEntry},
- {QStringViewLiteral("load-typesystem"), StackElement::LoadTypesystem},
- {QStringViewLiteral("modify-argument"), StackElement::ModifyArgument},
- {QStringViewLiteral("modify-documentation"), StackElement::ModifyDocumentation},
- {QStringViewLiteral("modify-field"), StackElement::ModifyField},
- {QStringViewLiteral("modify-function"), StackElement::ModifyFunction},
- {QStringViewLiteral("namespace-type"), StackElement::NamespaceTypeEntry},
- {QStringViewLiteral("native-to-target"), StackElement::NativeToTarget},
- {QStringViewLiteral("no-null-pointer"), StackElement::NoNullPointers},
- {QStringViewLiteral("object-type"), StackElement::ObjectTypeEntry},
- {QStringViewLiteral("parent"), StackElement::ParentOwner},
- {QStringViewLiteral("primitive-type"), StackElement::PrimitiveTypeEntry},
- {QStringViewLiteral("reference-count"), StackElement::ReferenceCount},
- {QStringViewLiteral("reject-enum-value"), StackElement::RejectEnumValue},
- {QStringViewLiteral("rejection"), StackElement::Rejection},
- {QStringViewLiteral("remove"), StackElement::Removal},
- {QStringViewLiteral("remove-argument"), StackElement::RemoveArgument},
- {QStringViewLiteral("remove-default-expression"), StackElement::RemoveDefaultExpression},
- {QStringViewLiteral("rename"), StackElement::Rename},
- {QStringViewLiteral("replace"), StackElement::Replace},
- {QStringViewLiteral("replace-default-expression"), StackElement::ReplaceDefaultExpression},
- {QStringViewLiteral("replace-type"), StackElement::ReplaceType},
- {QStringViewLiteral("smart-pointer-type"), StackElement::SmartPointerTypeEntry},
- {QStringViewLiteral("suppress-warning"), StackElement::SuppressedWarning},
- {QStringViewLiteral("target-to-native"), StackElement::TargetToNative},
- {QStringViewLiteral("template"), StackElement::Template},
- {QStringViewLiteral("typedef-type"), StackElement::TypedefTypeEntry},
- {QStringViewLiteral("typesystem"), StackElement::Root},
- {QStringViewLiteral("value-type"), StackElement::ValueTypeEntry},
- };
-ENUM_LOOKUP_BINARY_SEARCH()
-
-static int indexOfAttribute(const QXmlStreamAttributes &atts,
- QStringView name)
-{
- for (int i = 0, size = atts.size(); i < size; ++i) {
- if (atts.at(i).qualifiedName() == name)
- return i;
- }
- return -1;
-}
-
-static QString msgMissingAttribute(const QString &a)
-{
- return QLatin1String("Required attribute '") + a
- + QLatin1String("' missing.");
-}
-
-QTextStream &operator<<(QTextStream &str, const QXmlStreamAttribute &attribute)
-{
- str << attribute.qualifiedName() << "=\"" << attribute.value() << '"';
- return str;
-}
-
-static QString msgInvalidAttributeValue(const QXmlStreamAttribute &attribute)
-{
- QString result;
- QTextStream(&result) << "Invalid attribute value:" << attribute;
- return result;
-}
-
-static QString msgUnusedAttributes(const QStringRef &tag, const QXmlStreamAttributes &attributes)
-{
- QString result;
- QTextStream str(&result);
- str << attributes.size() << " attributes(s) unused on <" << tag << ">: ";
- for (int i = 0, size = attributes.size(); i < size; ++i) {
- if (i)
- str << ", ";
- str << attributes.at(i);
- }
- return result;
-}
-
-// QXmlStreamEntityResolver::resolveEntity(publicId, systemId) is not
-// implemented; resolve via undeclared entities instead.
-class TypeSystemEntityResolver : public QXmlStreamEntityResolver
-{
-public:
- explicit TypeSystemEntityResolver(const QString &currentPath) :
- m_currentPath(currentPath) {}
-
- QString resolveUndeclaredEntity(const QString &name) override;
-
-private:
- QString readFile(const QString &entityName, QString *errorMessage) const;
-
- const QString m_currentPath;
- QHash<QString, QString> m_cache;
-};
-
-QString TypeSystemEntityResolver::readFile(const QString &entityName, QString *errorMessage) const
-{
- QString fileName = entityName;
- if (!fileName.contains(QLatin1Char('.')))
- fileName += QLatin1String(".xml");
- QString path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath);
- if (!QFileInfo::exists(path)) // PySide2-specific hack
- fileName.prepend(QLatin1String("typesystem_"));
- path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath);
- if (!QFileInfo::exists(path)) {
- *errorMessage = QLatin1String("Unable to resolve: ") + entityName;
- return QString();
- }
- QFile file(path);
- if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- *errorMessage = msgCannotOpenForReading(file);
- return QString();
- }
- QString result = QString::fromUtf8(file.readAll()).trimmed();
- // Remove license header comments on which QXmlStreamReader chokes
- if (result.startsWith(QLatin1String("<!--"))) {
- const int commentEnd = result.indexOf(QLatin1String("-->"));
- if (commentEnd != -1) {
- result.remove(0, commentEnd + 3);
- result = result.trimmed();
- }
- }
- return result;
-}
-
-QString TypeSystemEntityResolver::resolveUndeclaredEntity(const QString &name)
-{
- auto it = m_cache.find(name);
- if (it == m_cache.end()) {
- QString errorMessage;
- it = m_cache.insert(name, readFile(name, &errorMessage));
- if (it.value().isEmpty()) { // The parser will fail and display the line number.
- qCWarning(lcShiboken, "%s",
- qPrintable(msgCannotResolveEntity(name, errorMessage)));
- }
- }
- return it.value();
-}
-
-Handler::Handler(TypeDatabase *database, bool generate) :
- m_database(database),
- m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
-{
-}
-
-Handler::~Handler() = default;
-
-static QString readerFileName(const QXmlStreamReader &reader)
-{
- const auto *file = qobject_cast<const QFile *>(reader.device());
- return file != nullptr ? file->fileName() : QString();
-}
-
-static QString msgReaderMessage(const QXmlStreamReader &reader,
- const char *type,
- const QString &what)
-{
- QString message;
- QTextStream str(&message);
- str << type << ": ";
- const QString fileName = readerFileName(reader);
- if (fileName.isEmpty())
- str << "<stdin>:";
- else
- str << QDir::toNativeSeparators(fileName) << ':';
- str << reader.lineNumber() << ':' << reader.columnNumber()
- << ": " << what;
- return message;
-}
-
-static QString msgReaderWarning(const QXmlStreamReader &reader, const QString &what)
-{
- return msgReaderMessage(reader, "Warning", what);
-}
-
-static QString msgReaderError(const QXmlStreamReader &reader, const QString &what)
-{
- return msgReaderMessage(reader, "Error", what);
-}
-
-static QString msgUnimplementedElementWarning(const QXmlStreamReader &reader,
- const QStringRef &name)
-{
- const QString message = QLatin1String("The element \"") +
- name + QLatin1String("\" is not implemented.");
- return msgReaderMessage(reader, "Warning", message);
-}
-
-static QString msgUnimplementedAttributeWarning(const QXmlStreamReader &reader,
- const QStringRef &name)
-{
- const QString message = QLatin1String("The attribute \"") +
- name + QLatin1String("\" is not implemented.");
- return msgReaderMessage(reader, "Warning", message);
-}
-
-static inline QString msgUnimplementedAttributeWarning(const QXmlStreamReader &reader,
- const QXmlStreamAttribute &attribute)
-{
- return msgUnimplementedAttributeWarning(reader, attribute.qualifiedName());
-}
-
-static QString
- msgUnimplementedAttributeValueWarning(const QXmlStreamReader &reader,
- QStringView name, QStringView value)
-{
- QString message;
- QTextStream(&message) << "The value \"" << value
- << "\" of the attribute \"" << name << "\" is not implemented.";
- return msgReaderMessage(reader, "Warning", message);
-}
-
-static inline
- QString msgUnimplementedAttributeValueWarning(const QXmlStreamReader &reader,
- const QXmlStreamAttribute &attribute)
-{
- return msgUnimplementedAttributeValueWarning(reader,
- attribute.qualifiedName(),
- attribute.value());
-}
-
-static QString msgInvalidVersion(const QStringRef &version, const QString &package = QString())
-{
- QString result;
- QTextStream str(&result);
- str << "Invalid version \"" << version << '"';
- if (!package.isEmpty())
- str << "\" specified for package " << package;
- str << '.';
- return result;
-}
-
-static bool addRejection(TypeDatabase *database, QXmlStreamAttributes *attributes,
- QString *errorMessage)
-{
- const int classIndex = indexOfAttribute(*attributes, classAttribute());
- if (classIndex == -1) {
- *errorMessage = msgMissingAttribute(classAttribute());
- return false;
- }
-
- TypeRejection rejection;
- const QString className = attributes->takeAt(classIndex).value().toString();
- if (!setRejectionRegularExpression(className, &rejection.className, errorMessage))
- return false;
-
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- const TypeRejection::MatchType type = typeRejectionFromAttribute(name);
- switch (type) {
- case TypeRejection::Function:
- case TypeRejection::Field:
- case TypeRejection::Enum:
- case TypeRejection::ArgumentType:
- case TypeRejection::ReturnType: {
- const QString pattern = attributes->takeAt(i).value().toString();
- if (!setRejectionRegularExpression(pattern, &rejection.pattern, errorMessage))
- return false;
- rejection.matchType = type;
- database->addRejection(rejection);
- return true;
- }
- break;
- default:
- break;
- }
- }
-
- // Special case: When all fields except class are empty, completely exclude class
- if (className == QLatin1String("*")) {
- *errorMessage = QLatin1String("bad reject entry, neither 'class', 'function-name'"
- " nor 'field' specified");
- return false;
- }
- rejection.matchType = TypeRejection::ExcludeClass;
- database->addRejection(rejection);
- return true;
-}
-
-bool Handler::parse(QXmlStreamReader &reader)
-{
- m_error.clear();
- m_currentPath.clear();
- const QString fileName = readerFileName(reader);
- if (!fileName.isEmpty())
- m_currentPath = QFileInfo(fileName).absolutePath();
- m_entityResolver.reset(new TypeSystemEntityResolver(m_currentPath));
- reader.setEntityResolver(m_entityResolver.data());
-
- while (!reader.atEnd()) {
- switch (reader.readNext()) {
- case QXmlStreamReader::NoToken:
- case QXmlStreamReader::Invalid:
- m_error = msgReaderError(reader, reader.errorString());
- return false;
- case QXmlStreamReader::StartElement:
- if (!startElement(reader)) {
- m_error = msgReaderError(reader, m_error);
- return false;
- }
-
- break;
- case QXmlStreamReader::EndElement:
- if (!endElement(reader.name())) {
- m_error = msgReaderError(reader, m_error);
- return false;
- }
- break;
- case QXmlStreamReader::Characters:
- if (!characters(reader.text())) {
- m_error = msgReaderError(reader, m_error);
- return false;
- }
- break;
- case QXmlStreamReader::StartDocument:
- case QXmlStreamReader::EndDocument:
- case QXmlStreamReader::Comment:
- case QXmlStreamReader::DTD:
- case QXmlStreamReader::EntityReference:
- case QXmlStreamReader::ProcessingInstruction:
- break;
- }
- }
- return true;
-}
-
-bool Handler::endElement(const QStringRef &localName)
-{
- if (m_ignoreDepth) {
- --m_ignoreDepth;
- return true;
- }
-
- if (m_currentDroppedEntry) {
- if (m_currentDroppedEntryDepth == 1) {
- m_current = m_currentDroppedEntry->parent;
- delete m_currentDroppedEntry;
- m_currentDroppedEntry = nullptr;
- m_currentDroppedEntryDepth = 0;
- } else {
- --m_currentDroppedEntryDepth;
- }
- return true;
- }
-
- if (!localName.compare(QLatin1String("import-file"), Qt::CaseInsensitive))
- return true;
-
- if (!m_current)
- return true;
-
- switch (m_current->type) {
- case StackElement::Root:
- if (m_generate == TypeEntry::GenerateAll) {
- TypeDatabase::instance()->addGlobalUserFunctions(m_contextStack.top()->addedFunctions);
- TypeDatabase::instance()->addGlobalUserFunctionModifications(m_contextStack.top()->functionMods);
- for (CustomConversion *customConversion : qAsConst(customConversionsForReview)) {
- const CustomConversion::TargetToNativeConversions &toNatives = customConversion->targetToNativeConversions();
- for (CustomConversion::TargetToNativeConversion *toNative : toNatives)
- toNative->setSourceType(m_database->findType(toNative->sourceTypeName()));
- }
- }
- break;
- case StackElement::ObjectTypeEntry:
- case StackElement::ValueTypeEntry:
- case StackElement::InterfaceTypeEntry:
- case StackElement::NamespaceTypeEntry: {
- auto *centry = static_cast<ComplexTypeEntry *>(m_current->entry);
- centry->setAddedFunctions(m_contextStack.top()->addedFunctions);
- centry->setFunctionModifications(m_contextStack.top()->functionMods);
- centry->setFieldModifications(m_contextStack.top()->fieldMods);
- centry->setCodeSnips(m_contextStack.top()->codeSnips);
- centry->setDocModification(m_contextStack.top()->docModifications);
-
- if (centry->designatedInterface()) {
- centry->designatedInterface()->setCodeSnips(m_contextStack.top()->codeSnips);
- centry->designatedInterface()->setFunctionModifications(m_contextStack.top()->functionMods);
- }
- }
- break;
- case StackElement::AddFunction: {
- // Leaving add-function: Assign all modifications to the added function
- StackElementContext *top = m_contextStack.top();
- const int modIndex = top->addedFunctionModificationIndex;
- top->addedFunctionModificationIndex = -1;
- Q_ASSERT(modIndex >= 0);
- Q_ASSERT(!top->addedFunctions.isEmpty());
- while (modIndex < top->functionMods.size())
- top->addedFunctions.last()->modifications.append(top->functionMods.takeAt(modIndex));
- }
- break;
- case StackElement::NativeToTarget:
- case StackElement::AddConversion: {
- CustomConversion* customConversion = static_cast<TypeEntry*>(m_current->entry)->customConversion();
- if (!customConversion) {
- m_error = QLatin1String("CustomConversion object is missing.");
- return false;
- }
-
- QString code = m_contextStack.top()->codeSnips.takeLast().code();
- if (m_current->type == StackElement::AddConversion) {
- if (customConversion->targetToNativeConversions().isEmpty()) {
- m_error = QLatin1String("CustomConversion's target to native conversions missing.");
- return false;
- }
- customConversion->targetToNativeConversions().last()->setConversion(code);
- } else {
- customConversion->setNativeToTargetConversion(code);
- }
- }
- break;
- case StackElement::CustomMetaConstructor: {
- m_current->entry->setCustomConstructor(*m_current->value.customFunction);
- delete m_current->value.customFunction;
- }
- break;
- case StackElement::CustomMetaDestructor: {
- m_current->entry->setCustomDestructor(*m_current->value.customFunction);
- delete m_current->value.customFunction;
- }
- break;
- case StackElement::EnumTypeEntry:
- m_current->entry->setDocModification(m_contextStack.top()->docModifications);
- m_contextStack.top()->docModifications = DocModificationList();
- m_currentEnum = nullptr;
- break;
- case StackElement::Template:
- m_database->addTemplate(m_current->value.templateEntry);
- break;
- case StackElement::TemplateInstanceEnum:
- switch (m_current->parent->type) {
- case StackElement::InjectCode:
- if (m_current->parent->parent->type == StackElement::Root) {
- CodeSnipList snips = m_current->parent->entry->codeSnips();
- CodeSnip snip = snips.takeLast();
- snip.addTemplateInstance(m_current->value.templateInstance);
- snips.append(snip);
- m_current->parent->entry->setCodeSnips(snips);
- break;
- }
- Q_FALLTHROUGH();
- case StackElement::NativeToTarget:
- case StackElement::AddConversion:
- m_contextStack.top()->codeSnips.last().addTemplateInstance(m_current->value.templateInstance);
- break;
- case StackElement::Template:
- m_current->parent->value.templateEntry->addTemplateInstance(m_current->value.templateInstance);
- break;
- case StackElement::CustomMetaConstructor:
- case StackElement::CustomMetaDestructor:
- m_current->parent->value.customFunction->addTemplateInstance(m_current->value.templateInstance);
- break;
- case StackElement::ConversionRule:
- m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.last().addTemplateInstance(m_current->value.templateInstance);
- break;
- case StackElement::InjectCodeInFunction:
- m_contextStack.top()->functionMods.last().snips.last().addTemplateInstance(m_current->value.templateInstance);
- break;
- default:
- break; // nada
- };
- break;
- default:
- break;
- }
-
- switch (m_current->type) {
- case StackElement::Root:
- case StackElement::NamespaceTypeEntry:
- case StackElement::InterfaceTypeEntry:
- case StackElement::ObjectTypeEntry:
- case StackElement::ValueTypeEntry:
- case StackElement::PrimitiveTypeEntry:
- case StackElement::TypedefTypeEntry:
- delete m_contextStack.pop();
- break;
- default:
- break;
- }
-
- StackElement *child = m_current;
- m_current = m_current->parent;
- delete(child);
-
- return true;
-}
-
-template <class String> // QString/QStringRef
-bool Handler::characters(const String &ch)
-{
- if (m_currentDroppedEntry || m_ignoreDepth)
- return true;
-
- if (m_current->type == StackElement::Template) {
- m_current->value.templateEntry->addCode(ch);
- return true;
- }
-
- if (m_current->type == StackElement::CustomMetaConstructor || m_current->type == StackElement::CustomMetaDestructor) {
- m_current->value.customFunction->addCode(ch);
- return true;
- }
-
- if (m_current->type == StackElement::ConversionRule
- && m_current->parent->type == StackElement::ModifyArgument) {
- m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.last().addCode(ch);
- return true;
- }
-
- if (m_current->type == StackElement::NativeToTarget || m_current->type == StackElement::AddConversion) {
- m_contextStack.top()->codeSnips.last().addCode(ch);
- return true;
- }
-
- if (m_current->parent) {
- if ((m_current->type & StackElement::CodeSnipMask)) {
- CodeSnipList snips;
- switch (m_current->parent->type) {
- case StackElement::Root:
- snips = m_current->parent->entry->codeSnips();
- snips.last().addCode(ch);
- m_current->parent->entry->setCodeSnips(snips);
- break;
- case StackElement::ModifyFunction:
- case StackElement::AddFunction:
- m_contextStack.top()->functionMods.last().snips.last().addCode(ch);
- m_contextStack.top()->functionMods.last().modifiers |= FunctionModification::CodeInjection;
- break;
- case StackElement::NamespaceTypeEntry:
- case StackElement::ObjectTypeEntry:
- case StackElement::ValueTypeEntry:
- case StackElement::InterfaceTypeEntry:
- m_contextStack.top()->codeSnips.last().addCode(ch);
- break;
- default:
- Q_ASSERT(false);
- };
- return true;
- }
- }
-
- if (m_current->type & StackElement::DocumentationMask)
- m_contextStack.top()->docModifications.last().setCode(ch);
-
- return true;
-}
-
-bool Handler::importFileElement(const QXmlStreamAttributes &atts)
-{
- const QString fileName = atts.value(nameAttribute()).toString();
- if (fileName.isEmpty()) {
- m_error = QLatin1String("Required attribute 'name' missing for include-file tag.");
- return false;
- }
-
- QFile file(fileName);
- if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- file.setFileName(QLatin1String(":/trolltech/generator/") + fileName);
- if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- m_error = QString::fromLatin1("Could not open file: '%1'").arg(QDir::toNativeSeparators(fileName));
- return false;
- }
- }
-
- const QStringRef quoteFrom = atts.value(quoteAfterLineAttribute());
- bool foundFromOk = quoteFrom.isEmpty();
- bool from = quoteFrom.isEmpty();
-
- const QStringRef quoteTo = atts.value(quoteBeforeLineAttribute());
- bool foundToOk = quoteTo.isEmpty();
- bool to = true;
-
- QTextStream in(&file);
- while (!in.atEnd()) {
- QString line = in.readLine();
- if (from && to && line.contains(quoteTo)) {
- to = false;
- foundToOk = true;
- break;
- }
- if (from && to)
- characters(line + QLatin1Char('\n'));
- if (!from && line.contains(quoteFrom)) {
- from = true;
- foundFromOk = true;
- }
- }
- if (!foundFromOk || !foundToOk) {
- QString fromError = QStringLiteral("Could not find quote-after-line='%1' in file '%2'.")
- .arg(quoteFrom.toString(), fileName);
- QString toError = QStringLiteral("Could not find quote-before-line='%1' in file '%2'.")
- .arg(quoteTo.toString(), fileName);
-
- if (!foundToOk)
- m_error = toError;
- if (!foundFromOk)
- m_error = fromError;
- if (!foundFromOk && !foundToOk)
- m_error = fromError + QLatin1Char(' ') + toError;
- return false;
- }
-
- return true;
-}
-
-static bool convertBoolean(QStringView value, const QString &attributeName, bool defaultValue)
-{
-#ifdef QTBUG_69389_FIXED
- if (value.compare(trueAttributeValue(), Qt::CaseInsensitive) == 0
- || value.compare(yesAttributeValue(), Qt::CaseInsensitive) == 0) {
- return true;
- }
- if (value.compare(falseAttributeValue(), Qt::CaseInsensitive) == 0
- || value.compare(noAttributeValue(), Qt::CaseInsensitive) == 0) {
- return false;
- }
-#else
- if (QtPrivate::compareStrings(value, trueAttributeValue(), Qt::CaseInsensitive) == 0
- || QtPrivate::compareStrings(value, yesAttributeValue(), Qt::CaseInsensitive) == 0) {
- return true;
- }
- if (QtPrivate::compareStrings(value, falseAttributeValue(), Qt::CaseInsensitive) == 0
- || QtPrivate::compareStrings(value, noAttributeValue(), Qt::CaseInsensitive) == 0) {
- return false;
- }
-#endif
- const QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.")
- .arg(value)
- .arg(attributeName,
- defaultValue ? yesAttributeValue() : noAttributeValue());
-
- qCWarning(lcShiboken).noquote().nospace() << warn;
- return defaultValue;
-}
-
-static bool convertRemovalAttribute(QStringView remove, Modification& mod, QString& errorMsg)
-{
- if (remove.isEmpty())
- return true;
-#ifdef QTBUG_69389_FIXED
- if (remove.compare(QStringViewLiteral("all"), Qt::CaseInsensitive) == 0) {
-#else
- if (QtPrivate::compareStrings(remove, QStringViewLiteral("all"), Qt::CaseInsensitive) == 0) {
-#endif
- mod.removal = TypeSystem::All;
- return true;
- }
-#ifdef QTBUG_69389_FIXED
- if (remove.compare(QStringViewLiteral("target"), Qt::CaseInsensitive) == 0) {
-#else
- if (QtPrivate::compareStrings(remove, QStringViewLiteral("target"), Qt::CaseInsensitive) == 0) {
-#endif
- mod.removal = TypeSystem::TargetLangAndNativeCode;
- return true;
- }
- errorMsg = QString::fromLatin1("Bad removal type '%1'").arg(remove);
- return false;
-}
-
-static void getNamePrefixRecursive(StackElement* element, QStringList& names)
-{
- if (!element->parent || !element->parent->entry)
- return;
- getNamePrefixRecursive(element->parent, names);
- names << element->parent->entry->name();
-}
-
-static QString getNamePrefix(StackElement* element)
-{
- QStringList names;
- getNamePrefixRecursive(element, names);
- return names.join(QLatin1Char('.'));
-}
-
-// Returns empty string if there's no error.
-static QString checkSignatureError(const QString& signature, const QString& tag)
-{
- QString funcName = signature.left(signature.indexOf(QLatin1Char('('))).trimmed();
- static const QRegularExpression whiteSpace(QStringLiteral("\\s"));
- Q_ASSERT(whiteSpace.isValid());
- if (!funcName.startsWith(QLatin1String("operator ")) && funcName.contains(whiteSpace)) {
- return QString::fromLatin1("Error in <%1> tag signature attribute '%2'.\n"
- "White spaces aren't allowed in function names, "
- "and return types should not be part of the signature.")
- .arg(tag, signature);
- }
- return QString();
-}
-
-void Handler::applyCommonAttributes(TypeEntry *type, QXmlStreamAttributes *attributes) const
-{
- type->setCodeGeneration(m_generate);
- const int revisionIndex =
- indexOfAttribute(*attributes, QStringViewLiteral("revision"));
- if (revisionIndex != -1)
- type->setRevision(attributes->takeAt(revisionIndex).value().toInt());
-}
-
-FlagsTypeEntry *
- Handler::parseFlagsEntry(const QXmlStreamReader &,
- EnumTypeEntry *enumEntry,
- const QString &name, QString flagName,
- const QVersionNumber &since,
- QXmlStreamAttributes *attributes)
-
-{
- FlagsTypeEntry *ftype = new FlagsTypeEntry(QLatin1String("QFlags<") + name + QLatin1Char('>'), since);
- ftype->setOriginator(enumEntry);
- ftype->setTargetLangPackage(enumEntry->targetLangPackage());
- // Try to get the guess the qualified flag name
- const int lastSepPos = name.lastIndexOf(colonColon());
- if (lastSepPos >= 0 && !flagName.contains(colonColon()))
- flagName.prepend(name.left(lastSepPos + 2));
-
- ftype->setOriginalName(flagName);
- applyCommonAttributes(ftype, attributes);
- QString n = ftype->originalName();
-
- QStringList lst = n.split(colonColon());
- const QString &targetLangQualifier = enumEntry->targetLangQualifier();
- if (QStringList(lst.mid(0, lst.size() - 1)).join(colonColon()) != targetLangQualifier) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("enum %1 and flags %2 differ in qualifiers")
- .arg(targetLangQualifier, lst.constFirst());
- }
-
- ftype->setFlagsName(lst.constLast());
- enumEntry->setFlags(ftype);
-
- m_database->addFlagsType(ftype);
- m_database->addType(ftype);
-
- const int revisionIndex =
- indexOfAttribute(*attributes, QStringViewLiteral("flags-revision"));
- ftype->setRevision(revisionIndex != -1
- ? attributes->takeAt(revisionIndex).value().toInt()
- : enumEntry->revision());
- return ftype;
-}
-
-SmartPointerTypeEntry *
- Handler::parseSmartPointerEntry(const QXmlStreamReader &,
- const QString &name, const QVersionNumber &since,
- QXmlStreamAttributes *attributes)
-{
- QString smartPointerType;
- QString getter;
- QString refCountMethodName;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == QLatin1String("type")) {
- smartPointerType = attributes->takeAt(i).value().toString();
- } else if (name == QLatin1String("getter")) {
- getter = attributes->takeAt(i).value().toString();
- } else if (name == QLatin1String("ref-count-method")) {
- refCountMethodName = attributes->takeAt(i).value().toString();
- }
- }
-
- if (smartPointerType.isEmpty()) {
- m_error = QLatin1String("No type specified for the smart pointer. Currently supported types: 'shared',");
- return nullptr;
- }
- if (smartPointerType != QLatin1String("shared")) {
- m_error = QLatin1String("Currently only the 'shared' type is supported.");
- return nullptr;
- }
-
- if (getter.isEmpty()) {
- m_error = QLatin1String("No function getter name specified for getting the raw pointer held by the smart pointer.");
- return nullptr;
- }
-
- QString signature = getter + QLatin1String("()");
- signature = TypeDatabase::normalizedSignature(signature);
- if (signature.isEmpty()) {
- m_error = QLatin1String("No signature for the smart pointer getter found.");
- return nullptr;
- }
-
- QString errorString = checkSignatureError(signature,
- QLatin1String("smart-pointer-type"));
- if (!errorString.isEmpty()) {
- m_error = errorString;
- return nullptr;
- }
-
- auto *type = new SmartPointerTypeEntry(name, getter, smartPointerType, refCountMethodName, since);
- applyCommonAttributes(type, attributes);
- return type;
-}
-
-PrimitiveTypeEntry *
- Handler::parsePrimitiveTypeEntry(const QXmlStreamReader &reader,
- const QString &name, const QVersionNumber &since,
- QXmlStreamAttributes *attributes)
-{
- auto *type = new PrimitiveTypeEntry(name, since);
- applyCommonAttributes(type, attributes);
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == QLatin1String("target-lang-name")) {
- type->setTargetLangName(attributes->takeAt(i).value().toString());
- } else if (name == QLatin1String("target-lang-api-name")) {
- type->setTargetLangApiName(attributes->takeAt(i).value().toString());
- } else if (name == preferredConversionAttribute()) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- } else if (name == preferredTargetLangTypeAttribute()) {
- const bool v = convertBoolean(attributes->takeAt(i).value(),
- preferredTargetLangTypeAttribute(), true);
- type->setPreferredTargetLangType(v);
- } else if (name == QLatin1String("default-constructor")) {
- type->setDefaultConstructor(attributes->takeAt(i).value().toString());
- }
- }
-
- if (type->targetLangName().isEmpty())
- type->setTargetLangName(type->name());
- if (type->targetLangApiName().isEmpty())
- type->setTargetLangApiName(type->name());
- type->setTargetLangPackage(m_defaultPackage);
- return type;
-}
-
-ContainerTypeEntry *
- Handler::parseContainerTypeEntry(const QXmlStreamReader &,
- const QString &name, const QVersionNumber &since,
- QXmlStreamAttributes *attributes)
-{
- const int typeIndex = indexOfAttribute(*attributes, QStringViewLiteral("type"));
- if (typeIndex == -1) {
- m_error = QLatin1String("no 'type' attribute specified");
- return nullptr;
- }
- const QStringRef typeName = attributes->takeAt(typeIndex).value();
- ContainerTypeEntry::Type containerType = containerTypeFromAttribute(typeName);
- if (containerType == ContainerTypeEntry::NoContainer) {
- m_error = QLatin1String("there is no container of type ") + typeName.toString();
- return nullptr;
- }
- auto *type = new ContainerTypeEntry(name, containerType, since);
- applyCommonAttributes(type, attributes);
- return type;
-}
-
-EnumTypeEntry *
- Handler::parseEnumTypeEntry(const QXmlStreamReader &reader,
- const QString &fullName, const QVersionNumber &since,
- QXmlStreamAttributes *attributes)
-{
- QString scope;
- QString name = fullName;
- const int sep = fullName.lastIndexOf(colonColon());
- if (sep != -1) {
- scope = fullName.left(sep);
- name = fullName.right(fullName.size() - sep - 2);
- }
- auto *entry = new EnumTypeEntry(scope, name, since);
- applyCommonAttributes(entry, attributes);
- entry->setTargetLangPackage(m_defaultPackage);
-
- QString flagNames;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == QLatin1String("upper-bound")) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- } else if (name == QLatin1String("lower-bound")) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- } else if (name == forceIntegerAttribute()) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- } else if (name == extensibleAttribute()) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- } else if (name == flagsAttribute()) {
- flagNames = attributes->takeAt(i).value().toString();
- }
- }
-
- // put in the flags parallel...
- if (!flagNames.isEmpty()) {
- const QStringList &flagNameList = flagNames.split(QLatin1Char(','));
- for (const QString &flagName : flagNameList)
- parseFlagsEntry(reader, entry, fullName, flagName.trimmed(), since, attributes);
- }
- return entry;
-}
-
-ObjectTypeEntry *
- Handler::parseInterfaceTypeEntry(const QXmlStreamReader &,
- const QString &name, const QVersionNumber &since,
- QXmlStreamAttributes *attributes)
-{
- auto *otype = new ObjectTypeEntry(name, since);
- applyCommonAttributes(otype, attributes);
- QString targetLangName = name;
- bool generate = true;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == QLatin1String("target-lang-name")) {
- targetLangName = attributes->takeAt(i).value().toString();
- } else if (name == generateAttribute()) {
- generate = convertBoolean(attributes->takeAt(i).value(),
- generateAttribute(), true);
- }
- }
-
- InterfaceTypeEntry *itype =
- new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(targetLangName), since);
-
- if (generate)
- itype->setCodeGeneration(m_generate);
- else
- itype->setCodeGeneration(TypeEntry::GenerateForSubclass);
-
- otype->setDesignatedInterface(itype);
- itype->setOrigin(otype);
- return otype;
-}
-
-NamespaceTypeEntry *
- Handler::parseNamespaceTypeEntry(const QXmlStreamReader &reader,
- const QString &name, const QVersionNumber &since,
- QXmlStreamAttributes *attributes)
-{
- QScopedPointer<NamespaceTypeEntry> result(new NamespaceTypeEntry(name, since));
- applyCommonAttributes(result.data(), attributes);
- applyComplexTypeAttributes(reader, result.data(), attributes);
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef attributeName = attributes->at(i).qualifiedName();
- if (attributeName == QLatin1String("files")) {
- const QString pattern = attributes->takeAt(i).value().toString();
- QRegularExpression re(pattern);
- if (!re.isValid()) {
- m_error = msgInvalidRegularExpression(pattern, re.errorString());
- return nullptr;
- }
- result->setFilePattern(re);
- } else if (attributeName == QLatin1String("extends")) {
- const auto extendsPackageName = attributes->takeAt(i).value();
- auto allEntries = TypeDatabase::instance()->findNamespaceTypes(name);
- auto extendsIt = std::find_if(allEntries.cbegin(), allEntries.cend(),
- [extendsPackageName] (const NamespaceTypeEntry *e) {
- return e->targetLangPackage() == extendsPackageName;
- });
- if (extendsIt == allEntries.cend()) {
- m_error = msgCannotFindNamespaceToExtend(name, extendsPackageName);
- return nullptr;
- }
- result->setExtends(*extendsIt);
- }
- }
-
- if (result->extends() && !result->hasPattern()) {
- m_error = msgExtendingNamespaceRequiresPattern(name);
- return nullptr;
- }
-
- return result.take();
-}
-
-ValueTypeEntry *
- Handler::parseValueTypeEntry(const QXmlStreamReader &,
- const QString &name, const QVersionNumber &since,
- QXmlStreamAttributes *attributes)
-{
- auto *typeEntry = new ValueTypeEntry(name, since);
- applyCommonAttributes(typeEntry, attributes);
- const int defaultCtIndex =
- indexOfAttribute(*attributes, QStringViewLiteral("default-constructor"));
- if (defaultCtIndex != -1)
- typeEntry->setDefaultConstructor(attributes->takeAt(defaultCtIndex).value().toString());
- return typeEntry;
-}
-
-FunctionTypeEntry *
- Handler::parseFunctionTypeEntry(const QXmlStreamReader &,
- const QString &name, const QVersionNumber &since,
- QXmlStreamAttributes *attributes)
-{
- const int signatureIndex = indexOfAttribute(*attributes, signatureAttribute());
- if (signatureIndex == -1) {
- m_error = msgMissingAttribute(signatureAttribute());
- return nullptr;
- }
- const QString signature =
- TypeDatabase::normalizedSignature(attributes->takeAt(signatureIndex).value().toString());
-
- TypeEntry *existingType = m_database->findType(name);
-
- if (!existingType) {
- auto *result = new FunctionTypeEntry(name, signature, since);
- applyCommonAttributes(result, attributes);
- return result;
- }
-
- if (existingType->type() != TypeEntry::FunctionType) {
- m_error = QStringLiteral("%1 expected to be a function, but isn't! Maybe it was already declared as a class or something else.")
- .arg(name);
- return nullptr;
- }
-
- auto *result = reinterpret_cast<FunctionTypeEntry *>(existingType);
- result->addSignature(signature);
- return result;
-}
-
-TypedefEntry *
- Handler::parseTypedefEntry(const QXmlStreamReader &, const QString &name,
- const QVersionNumber &since,
- QXmlStreamAttributes *attributes)
-{
- if (m_current && m_current->type != StackElement::Root
- && m_current->type != StackElement::NamespaceTypeEntry) {
- m_error = QLatin1String("typedef entries must be nested in namespaces or type system.");
- return nullptr;
- }
- const int sourceIndex = indexOfAttribute(*attributes, sourceAttribute());
- if (sourceIndex == -1) {
- m_error = msgMissingAttribute(sourceAttribute());
- return nullptr;
- }
- const QString sourceType = attributes->takeAt(sourceIndex).value().toString();
- auto result = new TypedefEntry(name, sourceType, since);
- applyCommonAttributes(result, attributes);
- return result;
-}
-
-void Handler::applyComplexTypeAttributes(const QXmlStreamReader &reader,
- ComplexTypeEntry *ctype,
- QXmlStreamAttributes *attributes) const
-{
- bool generate = true;
- ctype->setCopyable(ComplexTypeEntry::Unknown);
- auto exceptionHandling = m_exceptionHandling;
- auto allowThread = m_allowThread;
-
- QString package = m_defaultPackage;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == streamAttribute()) {
- ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute(), false));
- } else if (name == generateAttribute()) {
- generate = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true);
- } else if (name ==packageAttribute()) {
- package = attributes->takeAt(i).value().toString();
- } else if (name == defaultSuperclassAttribute()) {
- ctype->setDefaultSuperclass(attributes->takeAt(i).value().toString());
- } else if (name == genericClassAttribute()) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- const bool v = convertBoolean(attributes->takeAt(i).value(), genericClassAttribute(), false);
- ctype->setGenericClass(v);
- } else if (name == QLatin1String("target-lang-name")) {
- ctype->setTargetLangName(attributes->takeAt(i).value().toString());
- } else if (name == QLatin1String("polymorphic-base")) {
- ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString());
- } else if (name == QLatin1String("polymorphic-id-expression")) {
- ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString());
- } else if (name == copyableAttribute()) {
- const bool v = convertBoolean(attributes->takeAt(i).value(), copyableAttribute(), false);
- ctype->setCopyable(v ? ComplexTypeEntry::CopyableSet : ComplexTypeEntry::NonCopyableSet);
- } else if (name == exceptionHandlingAttribute()) {
- const auto attribute = attributes->takeAt(i);
- const auto v = exceptionHandlingFromAttribute(attribute.value());
- if (v != TypeSystem::ExceptionHandling::Unspecified) {
- exceptionHandling = v;
- } else {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgInvalidAttributeValue(attribute)));
- }
- } else if (name == allowThreadAttribute()) {
- const auto attribute = attributes->takeAt(i);
- const auto v = allowThreadFromAttribute(attribute.value());
- if (v != TypeSystem::AllowThread::Unspecified) {
- allowThread = v;
- } else {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgInvalidAttributeValue(attribute)));
- }
- } else if (name == QLatin1String("held-type")) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- } else if (name == QLatin1String("hash-function")) {
- ctype->setHashFunction(attributes->takeAt(i).value().toString());
- } else if (name == forceAbstractAttribute()) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- } else if (name == deprecatedAttribute()) {
- if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute(), false))
- ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
- } else if (name == deleteInMainThreadAttribute()) {
- if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute(), false))
- ctype->setDeleteInMainThread(true);
- } else if (name == QLatin1String("target-type")) {
- ctype->setTargetType(attributes->takeAt(i).value().toString());
- }
- }
-
- if (exceptionHandling != TypeSystem::ExceptionHandling::Unspecified)
- ctype->setExceptionHandling(exceptionHandling);
- if (allowThread != TypeSystem::AllowThread::Unspecified)
- ctype->setAllowThread(allowThread);
-
- // The generator code relies on container's package being empty.
- if (ctype->type() != TypeEntry::ContainerType)
- ctype->setTargetLangPackage(package);
-
- if (InterfaceTypeEntry *di = ctype->designatedInterface())
- di->setTargetLangPackage(package);
-
- if (generate)
- ctype->setCodeGeneration(m_generate);
- else
- ctype->setCodeGeneration(TypeEntry::GenerateForSubclass);
-}
-
-bool Handler::parseRenameFunction(const QXmlStreamReader &,
- QString *name, QXmlStreamAttributes *attributes)
-{
- QString signature;
- QString rename;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == signatureAttribute()) {
- // Do not remove as it is needed for the type entry later on
- signature = attributes->at(i).value().toString();
- } else if (name == renameAttribute()) {
- rename = attributes->takeAt(i).value().toString();
- }
- }
-
- if (signature.isEmpty()) {
- m_error = msgMissingAttribute(signatureAttribute());
- return false;
- }
-
- *name = signature.left(signature.indexOf(QLatin1Char('('))).trimmed();
-
- QString errorString = checkSignatureError(signature, QLatin1String("function"));
- if (!errorString.isEmpty()) {
- m_error = errorString;
- return false;
- }
-
- if (!rename.isEmpty()) {
- static const QRegularExpression functionNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$"));
- Q_ASSERT(functionNameRegExp.isValid());
- if (!functionNameRegExp.match(rename).hasMatch()) {
- m_error = QLatin1String("can not rename '") + signature + QLatin1String("', '")
- + rename + QLatin1String("' is not a valid function name");
- return false;
- }
- FunctionModification mod;
- if (!mod.setSignature(signature, &m_error))
- return false;
- mod.renamedToName = rename;
- mod.modifiers |= Modification::Rename;
- m_contextStack.top()->functionMods << mod;
- }
- return true;
-}
-
-bool Handler::parseInjectDocumentation(const QXmlStreamReader &,
- QXmlStreamAttributes *attributes)
-{
- const int validParent = StackElement::TypeEntryMask
- | StackElement::ModifyFunction
- | StackElement::ModifyField;
- if (!m_current->parent || (m_current->parent->type & validParent) == 0) {
- m_error = QLatin1String("inject-documentation must be inside modify-function, "
- "modify-field or other tags that creates a type");
- return false;
- }
-
- TypeSystem::DocModificationMode mode = TypeSystem::DocModificationReplace;
- TypeSystem::Language lang = TypeSystem::NativeCode;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == QLatin1String("mode")) {
- const QStringRef modeName = attributes->takeAt(i).value();
- mode = docModificationFromAttribute(modeName);
- if (mode == TypeSystem::DocModificationInvalid) {
- m_error = QLatin1String("Unknown documentation injection mode: ") + modeName;
- return false;
- }
- } else if (name == formatAttribute()) {
- const QStringRef format = attributes->takeAt(i).value();
- lang = languageFromAttribute(format);
- if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(format);
- return false;
- }
- }
- }
-
- QString signature = m_current->type & StackElement::TypeEntryMask
- ? QString() : m_currentSignature;
- DocModification mod(mode, signature);
- mod.setFormat(lang);
- m_contextStack.top()->docModifications << mod;
- return true;
-}
-
-bool Handler::parseModifyDocumentation(const QXmlStreamReader &,
- QXmlStreamAttributes *attributes)
-{
- const int validParent = StackElement::TypeEntryMask
- | StackElement::ModifyFunction
- | StackElement::ModifyField;
- if (!m_current->parent || (m_current->parent->type & validParent) == 0) {
- m_error = QLatin1String("modify-documentation must be inside modify-function, "
- "modify-field or other tags that creates a type");
- return false;
- }
-
- const int xpathIndex = indexOfAttribute(*attributes, xPathAttribute());
- if (xpathIndex == -1) {
- m_error = msgMissingAttribute(xPathAttribute());
- return false;
- }
-
- const QString xpath = attributes->takeAt(xpathIndex).value().toString();
- QString signature = (m_current->type & StackElement::TypeEntryMask) ? QString() : m_currentSignature;
- m_contextStack.top()->docModifications
- << DocModification(xpath, signature);
- return true;
-}
-
-// m_exceptionHandling
-TypeSystemTypeEntry *Handler::parseRootElement(const QXmlStreamReader &,
- const QVersionNumber &since,
- QXmlStreamAttributes *attributes)
-{
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == packageAttribute()) {
- m_defaultPackage = attributes->takeAt(i).value().toString();
- } else if (name == defaultSuperclassAttribute()) {
- m_defaultSuperclass = attributes->takeAt(i).value().toString();
- } else if (name == exceptionHandlingAttribute()) {
- const auto attribute = attributes->takeAt(i);
- const auto v = exceptionHandlingFromAttribute(attribute.value());
- if (v != TypeSystem::ExceptionHandling::Unspecified) {
- m_exceptionHandling = v;
- } else {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgInvalidAttributeValue(attribute)));
- }
- } else if (name == allowThreadAttribute()) {
- const auto attribute = attributes->takeAt(i);
- const auto v = allowThreadFromAttribute(attribute.value());
- if (v != TypeSystem::AllowThread::Unspecified) {
- m_allowThread = v;
- } else {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgInvalidAttributeValue(attribute)));
- }
- }
- }
-
- auto *moduleEntry =
- const_cast<TypeSystemTypeEntry *>(m_database->findTypeSystemType(m_defaultPackage));
- const bool add = moduleEntry == nullptr;
- if (add)
- moduleEntry = new TypeSystemTypeEntry(m_defaultPackage, since);
- moduleEntry->setCodeGeneration(m_generate);
-
- if ((m_generate == TypeEntry::GenerateForSubclass ||
- m_generate == TypeEntry::GenerateNothing) && !m_defaultPackage.isEmpty())
- TypeDatabase::instance()->addRequiredTargetImport(m_defaultPackage);
-
- if (add)
- m_database->addTypeSystemType(moduleEntry);
- return moduleEntry;
-}
-
-bool Handler::loadTypesystem(const QXmlStreamReader &,
- QXmlStreamAttributes *attributes)
-{
- QString typeSystemName;
- bool generateChild = true;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == nameAttribute())
- typeSystemName = attributes->takeAt(i).value().toString();
- else if (name == generateAttribute())
- generateChild = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true);
- }
- if (typeSystemName.isEmpty()) {
- m_error = QLatin1String("No typesystem name specified");
- return false;
- }
- const bool result =
- m_database->parseFile(typeSystemName, m_currentPath, generateChild
- && m_generate == TypeEntry::GenerateAll);
- if (!result)
- m_error = QStringLiteral("Failed to parse: '%1'").arg(typeSystemName);
- return result;
-}
-
-bool Handler::parseRejectEnumValue(const QXmlStreamReader &,
- QXmlStreamAttributes *attributes)
-{
- if (!m_currentEnum) {
- m_error = QLatin1String("<reject-enum-value> node must be used inside a <enum-type> node");
- return false;
- }
- const int nameIndex = indexOfAttribute(*attributes, nameAttribute());
- if (nameIndex == -1) {
- m_error = msgMissingAttribute(nameAttribute());
- return false;
- }
- m_currentEnum->addEnumValueRejection(attributes->takeAt(nameIndex).value().toString());
- return true;
-}
-
-bool Handler::parseReplaceArgumentType(const QXmlStreamReader &,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("Type replacement can only be specified for argument modifications");
- return false;
- }
- const int modifiedTypeIndex = indexOfAttribute(*attributes, modifiedTypeAttribute());
- if (modifiedTypeIndex == -1) {
- m_error = QLatin1String("Type replacement requires 'modified-type' attribute");
- return false;
- }
- m_contextStack.top()->functionMods.last().argument_mods.last().modified_type =
- attributes->takeAt(modifiedTypeIndex).value().toString();
- return true;
-}
-
-bool Handler::parseCustomConversion(const QXmlStreamReader &,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::ModifyArgument
- && topElement.type != StackElement::ValueTypeEntry
- && topElement.type != StackElement::PrimitiveTypeEntry
- && topElement.type != StackElement::ContainerTypeEntry) {
- m_error = QLatin1String("Conversion rules can only be specified for argument modification, "
- "value-type, primitive-type or container-type conversion.");
- return false;
- }
-
- QString sourceFile;
- QString snippetLabel;
- TypeSystem::Language lang = TypeSystem::NativeCode;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == classAttribute()) {
- const QStringRef languageAttribute = attributes->takeAt(i).value();
- lang = languageFromAttribute(languageAttribute);
- if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(languageAttribute);
- return false;
- }
- } else if (name == QLatin1String("file")) {
- sourceFile = attributes->takeAt(i).value().toString();
- } else if (name == snippetAttribute()) {
- snippetLabel = attributes->takeAt(i).value().toString();
- }
- }
-
- if (topElement.type == StackElement::ModifyArgument) {
- CodeSnip snip;
- snip.language = lang;
- m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.append(snip);
- return true;
- }
-
- if (topElement.entry->hasConversionRule() || topElement.entry->hasCustomConversion()) {
- m_error = QLatin1String("Types can have only one conversion rule");
- return false;
- }
-
- // The old conversion rule tag that uses a file containing the conversion
- // will be kept temporarily for compatibility reasons.
- if (!sourceFile.isEmpty()) {
- if (m_generate != TypeEntry::GenerateForSubclass
- && m_generate != TypeEntry::GenerateNothing) {
-
- const char* conversionFlag = NATIVE_CONVERSION_RULE_FLAG;
- if (lang == TypeSystem::TargetLangCode)
- conversionFlag = TARGET_CONVERSION_RULE_FLAG;
-
- QFile conversionSource(sourceFile);
- if (conversionSource.open(QIODevice::ReadOnly | QIODevice::Text)) {
- const QString conversionRule =
- extractSnippet(QString::fromUtf8(conversionSource.readAll()), snippetLabel);
- topElement.entry->setConversionRule(QLatin1String(conversionFlag) + conversionRule);
- } else {
- qCWarning(lcShiboken).noquote().nospace()
- << "File containing conversion code for "
- << topElement.entry->name() << " type does not exist or is not readable: "
- << sourceFile;
- }
- }
- }
-
- auto *customConversion = new CustomConversion(m_current->entry);
- customConversionsForReview.append(customConversion);
- return true;
-}
-
-bool Handler::parseNativeToTarget(const QXmlStreamReader &,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::ConversionRule) {
- m_error = QLatin1String("Native to Target conversion code can only be specified for custom conversion rules.");
- return false;
- }
- CodeSnip snip;
- if (!readFileSnippet(attributes, &snip))
- return false;
- m_contextStack.top()->codeSnips.append(snip);
- return true;
-}
-
-bool Handler::parseAddConversion(const QXmlStreamReader &,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::TargetToNative) {
- m_error = QLatin1String("Target to Native conversions can only be added inside 'target-to-native' tags.");
- return false;
- }
- QString sourceTypeName;
- QString typeCheck;
- CodeSnip snip;
- if (!readFileSnippet(attributes, &snip))
- return false;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == QLatin1String("type"))
- sourceTypeName = attributes->takeAt(i).value().toString();
- else if (name == QLatin1String("check"))
- typeCheck = attributes->takeAt(i).value().toString();
- }
- if (sourceTypeName.isEmpty()) {
- m_error = QLatin1String("Target to Native conversions must specify the input type with the 'type' attribute.");
- return false;
- }
- m_current->entry->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck);
- m_contextStack.top()->codeSnips.append(snip);
- return true;
-}
-
-static bool parseIndex(const QString &index, int *result, QString *errorMessage)
-{
- bool ok = false;
- *result = index.toInt(&ok);
- if (!ok)
- *errorMessage = QStringLiteral("Cannot convert '%1' to integer").arg(index);
- return ok;
-}
-
-static bool parseArgumentIndex(const QString &index, int *result, QString *errorMessage)
-{
- if (index == QLatin1String("return")) {
- *result = 0;
- return true;
- }
- if (index == QLatin1String("this")) {
- *result = -1;
- return true;
- }
- return parseIndex(index, result, errorMessage);
-}
-
-bool Handler::parseModifyArgument(const QXmlStreamReader &,
- const StackElement &topElement, QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::ModifyFunction
- && topElement.type != StackElement::AddFunction) {
- m_error = QString::fromLatin1("argument modification requires function"
- " modification as parent, was %1")
- .arg(topElement.type, 0, 16);
- return false;
- }
-
- QString index;
- QString replaceValue;
- bool resetAfterUse = false;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == indexAttribute()) {
- index = attributes->takeAt(i).value().toString();
- } else if (name == QLatin1String("replace-value")) {
- replaceValue = attributes->takeAt(i).value().toString();
- } else if (name == invalidateAfterUseAttribute()) {
- resetAfterUse = convertBoolean(attributes->takeAt(i).value(),
- invalidateAfterUseAttribute(), false);
- }
- }
-
- if (index.isEmpty()) {
- m_error = msgMissingAttribute(indexAttribute());
- return false;
- }
-
- int idx;
- if (!parseArgumentIndex(index, &idx, &m_error))
- return false;
-
- if (!replaceValue.isEmpty() && idx) {
- m_error = QLatin1String("replace-value is only supported for return values (index=0).");
- return false;
- }
-
- ArgumentModification argumentModification = ArgumentModification(idx);
- argumentModification.replace_value = replaceValue;
- argumentModification.resetAfterUse = resetAfterUse;
- m_contextStack.top()->functionMods.last().argument_mods.append(argumentModification);
- return true;
-}
-
-bool Handler::parseNoNullPointer(const QXmlStreamReader &reader,
- const StackElement &topElement, QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("no-null-pointer requires argument modification as parent");
- return false;
- }
-
- ArgumentModification &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods.last();
- lastArgMod.noNullPointers = true;
-
- const int defaultValueIndex =
- indexOfAttribute(*attributes, QStringViewLiteral("default-value"));
- if (defaultValueIndex != -1) {
- const QXmlStreamAttribute attribute = attributes->takeAt(defaultValueIndex);
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, attribute)));
- }
- return true;
-}
-
-bool Handler::parseDefineOwnership(const QXmlStreamReader &,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("define-ownership requires argument modification as parent");
- return false;
- }
-
- TypeSystem::Language lang = TypeSystem::TargetLangCode;
- QString ownership;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == classAttribute()) {
- const QStringRef className = attributes->takeAt(i).value();
- lang = languageFromAttribute(className);
- if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(className);
- return false;
- }
- } else if (name == ownershipAttribute()) {
- ownership = attributes->takeAt(i).value().toString();
- }
- }
- const TypeSystem::Ownership owner = ownershipFromFromAttribute(ownership);
- if (owner == TypeSystem::InvalidOwnership) {
- m_error = QStringLiteral("unsupported owner attribute: '%1'").arg(ownership);
- return false;
- }
- m_contextStack.top()->functionMods.last().argument_mods.last().ownerships[lang] = owner;
- return true;
-}
-
-bool Handler::parseArgumentMap(const QXmlStreamReader &,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (!(topElement.type & StackElement::CodeSnipMask)) {
- m_error = QLatin1String("Argument maps requires code injection as parent");
- return false;
- }
-
- int pos = 1;
- QString metaName;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == indexAttribute()) {
- if (!parseIndex(attributes->takeAt(i).value().toString(), &pos, &m_error))
- return false;
- if (pos <= 0) {
- m_error = QStringLiteral("Argument position %1 must be a positive number").arg(pos);
- return false;
- }
- } else if (name == QLatin1String("meta-name")) {
- metaName = attributes->takeAt(i).value().toString();
- }
- }
-
- if (metaName.isEmpty())
- qCWarning(lcShiboken) << "Empty meta name in argument map";
-
- if (topElement.type == StackElement::InjectCodeInFunction) {
- m_contextStack.top()->functionMods.last().snips.last().argumentMap[pos] = metaName;
- } else {
- qCWarning(lcShiboken) << "Argument maps are only useful for injection of code "
- "into functions.";
- }
- return true;
-}
-
-bool Handler::parseRemoval(const QXmlStreamReader &,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::ModifyFunction) {
- m_error = QLatin1String("Function modification parent required");
- return false;
- }
-
- TypeSystem::Language lang = TypeSystem::All;
- const int classIndex = indexOfAttribute(*attributes, classAttribute());
- if (classIndex != -1) {
- const QStringRef value = attributes->takeAt(classIndex).value();
- lang = languageFromAttribute(value);
- if (lang == TypeSystem::TargetLangCode) // "target" means TargetLangAndNativeCode here
- lang = TypeSystem::TargetLangAndNativeCode;
- if (lang != TypeSystem::TargetLangAndNativeCode && lang != TypeSystem::All) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(value);
- return false;
- }
- }
- m_contextStack.top()->functionMods.last().removal = lang;
- return true;
-}
-
-bool Handler::parseRename(const QXmlStreamReader &reader,
- StackElement::ElementType type,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::ModifyField
- && topElement.type != StackElement::ModifyFunction
- && topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("Function, field or argument modification parent required");
- return false;
- }
-
- Modification *mod = nullptr;
- if (topElement.type == StackElement::ModifyFunction)
- mod = &m_contextStack.top()->functionMods.last();
- else if (topElement.type == StackElement::ModifyField)
- mod = &m_contextStack.top()->fieldMods.last();
-
- Modification::Modifiers modifierFlag = Modification::Rename;
- if (type == StackElement::Rename) {
- const int toIndex = indexOfAttribute(*attributes, toAttribute());
- if (toIndex == -1) {
- m_error = msgMissingAttribute(toAttribute());
- return false;
- }
- const QString renamed_to = attributes->takeAt(toIndex).value().toString();
- if (topElement.type == StackElement::ModifyFunction)
- mod->setRenamedTo(renamed_to);
- else if (topElement.type == StackElement::ModifyField)
- mod->setRenamedTo(renamed_to);
- else
- m_contextStack.top()->functionMods.last().argument_mods.last().renamed_to = renamed_to;
- } else {
- const int modifierIndex = indexOfAttribute(*attributes, modifierAttribute());
- if (modifierIndex == -1) {
- m_error = msgMissingAttribute(modifierAttribute());
- return false;
- }
- const QStringRef modifier = attributes->takeAt(modifierIndex).value();
- modifierFlag = modifierFromAttribute(modifier);
- if (modifierFlag == Modification::InvalidModifier) {
- m_error = QStringLiteral("Unknown access modifier: '%1'").arg(modifier);
- return false;
- }
- if (modifierFlag == Modification::Friendly) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeValueWarning(reader, modifierAttribute(), modifier)));
- }
- }
-
- if (mod)
- mod->modifiers |= modifierFlag;
- return true;
-}
-
-bool Handler::parseModifyField(const QXmlStreamReader &reader,
- QXmlStreamAttributes *attributes)
-{
- FieldModification fm;
- fm.modifiers = FieldModification::Readable | FieldModification::Writable;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == nameAttribute()) {
- fm.name = attributes->takeAt(i).value().toString();
- } else if (name == removeAttribute()) {
- if (!convertRemovalAttribute(attributes->takeAt(i).value(), fm, m_error))
- return false;
- } else if (name == readAttribute()) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- if (!convertBoolean(attributes->takeAt(i).value(), readAttribute(), true))
- fm.modifiers &= ~FieldModification::Readable;
- } else if (name == writeAttribute()) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- if (!convertBoolean(attributes->takeAt(i).value(), writeAttribute(), true))
- fm.modifiers &= ~FieldModification::Writable;
- }
- }
- if (fm.name.isEmpty()) {
- m_error = msgMissingAttribute(nameAttribute());
- return false;
- }
- m_contextStack.top()->fieldMods << fm;
- return true;
-}
-
-bool Handler::parseAddFunction(const QXmlStreamReader &,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (!(topElement.type & (StackElement::ComplexTypeEntryMask | StackElement::Root))) {
- m_error = QString::fromLatin1("Add function requires a complex type or a root tag as parent"
- ", was=%1").arg(topElement.type, 0, 16);
- return false;
- }
- QString originalSignature;
- QString returnType = QLatin1String("void");
- bool staticFunction = false;
- QString access;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == QLatin1String("signature")) {
- originalSignature = attributes->takeAt(i).value().toString();
- } else if (name == QLatin1String("return-type")) {
- returnType = attributes->takeAt(i).value().toString();
- } else if (name == staticAttribute()) {
- staticFunction = convertBoolean(attributes->takeAt(i).value(),
- staticAttribute(), false);
- } else if (name == accessAttribute()) {
- access = attributes->takeAt(i).value().toString();
- }
- }
-
- QString signature = TypeDatabase::normalizedSignature(originalSignature);
- if (signature.isEmpty()) {
- m_error = QLatin1String("No signature for the added function");
- return false;
- }
-
- QString errorString = checkSignatureError(signature, QLatin1String("add-function"));
- if (!errorString.isEmpty()) {
- m_error = errorString;
- return false;
- }
-
- AddedFunctionPtr func(new AddedFunction(signature, returnType));
- func->setStatic(staticFunction);
- if (!signature.contains(QLatin1Char('(')))
- signature += QLatin1String("()");
- m_currentSignature = signature;
-
- if (!access.isEmpty()) {
- const AddedFunction::Access a = addedFunctionAccessFromAttribute(access);
- if (a == AddedFunction::InvalidAccess) {
- m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
- return false;
- }
- func->setAccess(a);
- }
-
- m_contextStack.top()->addedFunctions << func;
- m_contextStack.top()->addedFunctionModificationIndex =
- m_contextStack.top()->functionMods.size();
-
- FunctionModification mod;
- if (!mod.setSignature(m_currentSignature, &m_error))
- return false;
- mod.setOriginalSignature(originalSignature);
- m_contextStack.top()->functionMods << mod;
- return true;
-}
-
-bool Handler::parseModifyFunction(const QXmlStreamReader &reader,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
- m_error = QString::fromLatin1("Modify function requires complex type as parent"
- ", was=%1").arg(topElement.type, 0, 16);
- return false;
- }
-
- QString originalSignature;
- QString access;
- QString removal;
- QString rename;
- QString association;
- bool deprecated = false;
- bool isThread = false;
- TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
- TypeSystem::AllowThread allowThread = TypeSystem::AllowThread::Unspecified;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == QLatin1String("signature")) {
- originalSignature = attributes->takeAt(i).value().toString();
- } else if (name == accessAttribute()) {
- access = attributes->takeAt(i).value().toString();
- } else if (name == renameAttribute()) {
- rename = attributes->takeAt(i).value().toString();
- } else if (name == QLatin1String("associated-to")) {
- association = attributes->takeAt(i).value().toString();
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- } else if (name == removeAttribute()) {
- removal = attributes->takeAt(i).value().toString();
- } else if (name == deprecatedAttribute()) {
- deprecated = convertBoolean(attributes->takeAt(i).value(),
- deprecatedAttribute(), false);
- } else if (name == threadAttribute()) {
- isThread = convertBoolean(attributes->takeAt(i).value(),
- threadAttribute(), false);
- } else if (name == allowThreadAttribute()) {
- const QXmlStreamAttribute attribute = attributes->takeAt(i);
- allowThread = allowThreadFromAttribute(attribute.value());
- if (allowThread == TypeSystem::AllowThread::Unspecified) {
- m_error = msgInvalidAttributeValue(attribute);
- return false;
- }
- } else if (name == exceptionHandlingAttribute()) {
- const auto attribute = attributes->takeAt(i);
- exceptionHandling = exceptionHandlingFromAttribute(attribute.value());
- if (exceptionHandling == TypeSystem::ExceptionHandling::Unspecified) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgInvalidAttributeValue(attribute)));
- }
- } else if (name == virtualSlotAttribute()) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
- }
- }
-
- const QString signature = TypeDatabase::normalizedSignature(originalSignature);
- if (signature.isEmpty()) {
- m_error = QLatin1String("No signature for modified function");
- return false;
- }
-
- QString errorString = checkSignatureError(signature, QLatin1String("modify-function"));
- if (!errorString.isEmpty()) {
- m_error = errorString;
- return false;
- }
-
- FunctionModification mod;
- if (!mod.setSignature(signature, &m_error))
- return false;
- mod.setOriginalSignature(originalSignature);
- mod.setExceptionHandling(exceptionHandling);
- m_currentSignature = signature;
-
- if (!access.isEmpty()) {
- const Modification::Modifiers m = modifierFromAttribute(access);
- if ((m & (Modification::AccessModifierMask | Modification::FinalMask)) == 0) {
- m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
- return false;
- }
- if (m == Modification::Final || m == Modification::NonFinal) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeValueWarning(reader,
- accessAttribute(), access)));
- }
- mod.modifiers |= m;
- }
-
- if (deprecated)
- mod.modifiers |= Modification::Deprecated;
-
- if (!removal.isEmpty() && !convertRemovalAttribute(removal, mod, m_error))
- return false;
-
- if (!rename.isEmpty()) {
- mod.renamedToName = rename;
- mod.modifiers |= Modification::Rename;
- }
-
- if (!association.isEmpty())
- mod.association = association;
-
- mod.setIsThread(isThread);
- if (allowThread != TypeSystem::AllowThread::Unspecified)
- mod.setAllowThread(allowThread);
-
- m_contextStack.top()->functionMods << mod;
- return true;
-}
-
-bool Handler::parseReplaceDefaultExpression(const QXmlStreamReader &,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (!(topElement.type & StackElement::ModifyArgument)) {
- m_error = QLatin1String("Replace default expression only allowed as child of argument modification");
- return false;
- }
- const int withIndex = indexOfAttribute(*attributes, QStringViewLiteral("with"));
- if (withIndex == -1 || attributes->at(withIndex).value().isEmpty()) {
- m_error = QLatin1String("Default expression replaced with empty string. Use remove-default-expression instead.");
- return false;
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().replacedDefaultExpression =
- attributes->takeAt(withIndex).value().toString();
- return true;
-}
-
-CustomFunction *
- Handler::parseCustomMetaConstructor(const QXmlStreamReader &,
- StackElement::ElementType type,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- QString functionName = topElement.entry->name().toLower()
- + (type == StackElement::CustomMetaConstructor
- ? QLatin1String("_create") : QLatin1String("_delete"));
- QString paramName = QLatin1String("copy");
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == nameAttribute())
- functionName = attributes->takeAt(i).value().toString();
- else if (name == QLatin1String("param-name"))
- paramName = attributes->takeAt(i).value().toString();
- }
- auto *func = new CustomFunction(functionName);
- func->paramName = paramName;
- return func;
-}
-
-bool Handler::parseReferenceCount(const QXmlStreamReader &reader,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("reference-count must be child of modify-argument");
- return false;
- }
-
- ReferenceCount rc;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == actionAttribute()) {
- const QXmlStreamAttribute attribute = attributes->takeAt(i);
- rc.action = referenceCountFromAttribute(attribute.value());
- switch (rc.action) {
- case ReferenceCount::Invalid:
- m_error = QLatin1String("unrecognized value '") + attribute.value()
- + QLatin1String("' for action attribute.");
- return false;
- case ReferenceCount::AddAll:
- case ReferenceCount::Ignore:
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeValueWarning(reader, attribute)));
- break;
- default:
- break;
- }
- } else if (name == QLatin1String("variable-name")) {
- rc.varName = attributes->takeAt(i).value().toString();
- }
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().referenceCounts.append(rc);
- return true;
-}
-
-bool Handler::parseParentOwner(const QXmlStreamReader &,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("parent-policy must be child of modify-argument");
- return false;
- }
- ArgumentOwner ao;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == indexAttribute()) {
- const QString index = attributes->takeAt(i).value().toString();
- if (!parseArgumentIndex(index, &ao.index, &m_error))
- return false;
- } else if (name == actionAttribute()) {
- const QStringRef action = attributes->takeAt(i).value();
- ao.action = argumentOwnerActionFromAttribute(action);
- if (ao.action == ArgumentOwner::Invalid) {
- m_error = QLatin1String("Invalid parent actionr '") + action + QLatin1String("'.");
- return false;
- }
- }
- }
- m_contextStack.top()->functionMods.last().argument_mods.last().owner = ao;
- return true;
-}
-
-bool Handler::readFileSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip)
-{
- QString fileName;
- QString snippetLabel;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == QLatin1String("file")) {
- fileName = attributes->takeAt(i).value().toString();
- } else if (name == snippetAttribute()) {
- snippetLabel = attributes->takeAt(i).value().toString();
- }
- }
- if (fileName.isEmpty())
- return true;
- const QString resolved = m_database->modifiedTypesystemFilepath(fileName, m_currentPath);
- if (!QFile::exists(resolved)) {
- m_error = QLatin1String("File for inject code not exist: ")
- + QDir::toNativeSeparators(fileName);
- return false;
- }
- QFile codeFile(resolved);
- if (!codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) {
- m_error = msgCannotOpenForReading(codeFile);
- return false;
- }
- QString source = fileName;
- if (!snippetLabel.isEmpty())
- source += QLatin1String(" (") + snippetLabel + QLatin1Char(')');
- QString content;
- QTextStream str(&content);
- str << "// ========================================================================\n"
- "// START of custom code block [file: "
- << source << "]\n"
- << extractSnippet(QString::fromUtf8(codeFile.readAll()), snippetLabel)
- << "\n// END of custom code block [file: " << source
- << "]\n// ========================================================================\n";
- snip->addCode(content);
- return true;
-}
-
-bool Handler::parseInjectCode(const QXmlStreamReader &,
- const StackElement &topElement,
- StackElement* element, QXmlStreamAttributes *attributes)
-{
- if (!(topElement.type & StackElement::ComplexTypeEntryMask)
- && (topElement.type != StackElement::AddFunction)
- && (topElement.type != StackElement::ModifyFunction)
- && (topElement.type != StackElement::Root)) {
- m_error = QLatin1String("wrong parent type for code injection");
- return false;
- }
-
- TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionBeginning;
- TypeSystem::Language lang = TypeSystem::TargetLangCode;
- CodeSnip snip;
- if (!readFileSnippet(attributes, &snip))
- return false;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == classAttribute()) {
- const QStringRef className = attributes->takeAt(i).value();
- lang = languageFromAttribute(className);
- if (lang == TypeSystem::NoLanguage) {
- m_error = QStringLiteral("Invalid class specifier: '%1'").arg(className);
- return false;
- }
- } else if (name == positionAttribute()) {
- const QStringRef value = attributes->takeAt(i).value();
- position = codeSnipPositionFromAttribute(value);
- if (position == TypeSystem::CodeSnipPositionInvalid) {
- m_error = QStringLiteral("Invalid position: '%1'").arg(value);
- return false;
- }
- }
- }
-
- snip.position = position;
- snip.language = lang;
-
- if (snip.language == TypeSystem::Interface
- && topElement.type != StackElement::InterfaceTypeEntry) {
- m_error = QLatin1String("Interface code injections must be direct child of an interface type entry");
- return false;
- }
-
- if (topElement.type == StackElement::ModifyFunction
- || topElement.type == StackElement::AddFunction) {
- if (snip.language == TypeSystem::ShellDeclaration) {
- m_error = QLatin1String("no function implementation in shell declaration in which to inject code");
- return false;
- }
-
- FunctionModification &mod = m_contextStack.top()->functionMods.last();
- mod.snips << snip;
- if (!snip.code().isEmpty())
- mod.modifiers |= FunctionModification::CodeInjection;
- element->type = StackElement::InjectCodeInFunction;
- } else if (topElement.type == StackElement::Root) {
- element->entry->addCodeSnip(snip);
- } else if (topElement.type != StackElement::Root) {
- m_contextStack.top()->codeSnips << snip;
- }
- return true;
-}
-
-bool Handler::parseInclude(const QXmlStreamReader &,
- const StackElement &topElement,
- TypeEntry *entry, QXmlStreamAttributes *attributes)
-{
- QString fileName;
- QString location;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == QLatin1String("file-name"))
- fileName = attributes->takeAt(i).value().toString();
- else if (name == locationAttribute())
- location = attributes->takeAt(i).value().toString();
- }
- const Include::IncludeType loc = locationFromAttribute(location);
- if (loc == Include::InvalidInclude) {
- m_error = QStringLiteral("Location not recognized: '%1'").arg(location);
- return false;
- }
-
- Include inc(loc, fileName);
- if (topElement.type
- & (StackElement::ComplexTypeEntryMask | StackElement::PrimitiveTypeEntry)) {
- entry->setInclude(inc);
- } else if (topElement.type == StackElement::ExtraIncludes) {
- entry->addExtraInclude(inc);
- } else {
- m_error = QLatin1String("Only supported parent tags are primitive-type, complex types or extra-includes");
- return false;
- }
- if (InterfaceTypeEntry *di = entry->designatedInterface()) {
- di->setInclude(entry->include());
- di->setExtraIncludes(entry->extraIncludes());
- }
- return true;
-}
-
-TemplateInstance *
- Handler::parseTemplateInstanceEnum(const QXmlStreamReader &,
- const StackElement &topElement,
- QXmlStreamAttributes *attributes)
-{
- if (!(topElement.type & StackElement::CodeSnipMask) &&
- (topElement.type != StackElement::Template) &&
- (topElement.type != StackElement::CustomMetaConstructor) &&
- (topElement.type != StackElement::CustomMetaDestructor) &&
- (topElement.type != StackElement::NativeToTarget) &&
- (topElement.type != StackElement::AddConversion) &&
- (topElement.type != StackElement::ConversionRule)) {
- m_error = QLatin1String("Can only insert templates into code snippets, templates, custom-constructors, "\
- "custom-destructors, conversion-rule, native-to-target or add-conversion tags.");
- return nullptr;
- }
- const int nameIndex = indexOfAttribute(*attributes, nameAttribute());
- if (nameIndex == -1) {
- m_error = msgMissingAttribute(nameAttribute());
- return nullptr;
- }
- return new TemplateInstance(attributes->takeAt(nameIndex).value().toString());
-}
-
-bool Handler::parseReplace(const QXmlStreamReader &,
- const StackElement &topElement,
- StackElement *element, QXmlStreamAttributes *attributes)
-{
- if (topElement.type != StackElement::TemplateInstanceEnum) {
- m_error = QLatin1String("Can only insert replace rules into insert-template.");
- return false;
- }
- QString from;
- QString to;
- for (int i = attributes->size() - 1; i >= 0; --i) {
- const QStringRef name = attributes->at(i).qualifiedName();
- if (name == QLatin1String("from"))
- from = attributes->takeAt(i).value().toString();
- else if (name == toAttribute())
- to = attributes->takeAt(i).value().toString();
- }
- element->parent->value.templateInstance->addReplaceRule(from, to);
- return true;
-}
-
-bool Handler::startElement(const QXmlStreamReader &reader)
-{
- if (m_ignoreDepth) {
- ++m_ignoreDepth;
- return true;
- }
-
- const QStringRef tagName = reader.name();
- QXmlStreamAttributes attributes = reader.attributes();
-
- QVersionNumber since(0, 0);
- int index = indexOfAttribute(attributes, sinceAttribute());
- if (index != -1) {
- const QStringRef sinceSpec = attributes.takeAt(index).value();
- since = QVersionNumber::fromString(sinceSpec.toString());
- if (since.isNull()) {
- m_error = msgInvalidVersion(sinceSpec, m_defaultPackage);
- return false;
- }
- }
-
- if (!m_defaultPackage.isEmpty() && since > QVersionNumber(0, 0)) {
- TypeDatabase* td = TypeDatabase::instance();
- if (!td->checkApiVersion(m_defaultPackage, since)) {
- ++m_ignoreDepth;
- return true;
- }
- }
-
- if (tagName.compare(QLatin1String("import-file"), Qt::CaseInsensitive) == 0)
- return importFileElement(attributes);
-
- const StackElement::ElementType elementType = elementFromTag(tagName);
- if (elementType == StackElement::None) {
- m_error = QStringLiteral("Unknown tag name: '%1'").arg(tagName);
- return false;
- }
-
- if (m_currentDroppedEntry) {
- ++m_currentDroppedEntryDepth;
- return true;
- }
-
- auto *element = new StackElement(m_current);
- element->type = elementType;
-
- if (element->type == StackElement::Root && m_generate == TypeEntry::GenerateAll)
- customConversionsForReview.clear();
-
- if (element->type == StackElement::CustomMetaConstructor
- || element->type == StackElement::CustomMetaDestructor) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedElementWarning(reader, tagName)));
- }
-
- switch (element->type) {
- case StackElement::Root:
- case StackElement::NamespaceTypeEntry:
- case StackElement::InterfaceTypeEntry:
- case StackElement::ObjectTypeEntry:
- case StackElement::ValueTypeEntry:
- case StackElement::PrimitiveTypeEntry:
- case StackElement::TypedefTypeEntry:
- m_contextStack.push(new StackElementContext());
- break;
- default:
- break;
- }
-
- if (element->type & StackElement::TypeEntryMask) {
- QString name;
- if (element->type != StackElement::FunctionTypeEntry) {
- const int nameIndex = indexOfAttribute(attributes, nameAttribute());
- if (nameIndex != -1) {
- name = attributes.takeAt(nameIndex).value().toString();
- } else if (element->type != StackElement::EnumTypeEntry) { // anonymous enum?
- m_error = msgMissingAttribute(nameAttribute());
- return false;
- }
- }
-
- if (m_database->hasDroppedTypeEntries()) {
- QString identifier = getNamePrefix(element) + QLatin1Char('.');
- identifier += element->type == StackElement::FunctionTypeEntry
- ? attributes.value(signatureAttribute()).toString()
- : name;
- if (m_database->shouldDropTypeEntry(identifier)) {
- m_currentDroppedEntry = element;
- m_currentDroppedEntryDepth = 1;
- if (ReportHandler::isDebug(ReportHandler::SparseDebug)) {
- qCDebug(lcShiboken)
- << QStringLiteral("Type system entry '%1' was intentionally dropped from generation.").arg(identifier);
- }
- return true;
- }
- }
-
- // The top level tag 'function' has only the 'signature' tag
- // and we should extract the 'name' value from it.
- if (element->type == StackElement::FunctionTypeEntry
- && !parseRenameFunction(reader, &name, &attributes)) {
- return false;
- }
-
- // We need to be able to have duplicate primitive type entries,
- // or it's not possible to cover all primitive target language
- // types (which we need to do in order to support fake meta objects)
- if (element->type != StackElement::PrimitiveTypeEntry
- && element->type != StackElement::FunctionTypeEntry) {
- TypeEntry *tmp = m_database->findType(name);
- if (tmp && !tmp->isNamespace())
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("Duplicate type entry: '%1'").arg(name);
- }
-
- if (element->type == StackElement::EnumTypeEntry) {
- const int enumIdentifiedByIndex = indexOfAttribute(attributes, enumIdentifiedByValueAttribute());
- const QString identifiedByValue = enumIdentifiedByIndex != -1
- ? attributes.takeAt(enumIdentifiedByIndex).value().toString() : QString();
- if (name.isEmpty()) {
- name = identifiedByValue;
- } else if (!identifiedByValue.isEmpty()) {
- m_error = QLatin1String("can't specify both 'name' and 'identified-by-value' attributes");
- return false;
- }
- }
-
- // Fix type entry name using nesting information.
- if (element->type & StackElement::TypeEntryMask
- && element->parent && element->parent->type != StackElement::Root) {
- name = element->parent->entry->name() + colonColon() + name;
- }
-
-
- if (name.isEmpty()) {
- m_error = QLatin1String("no 'name' attribute specified");
- return false;
- }
-
- switch (element->type) {
- case StackElement::CustomTypeEntry:
- element->entry = new TypeEntry(name, TypeEntry::CustomType, since);
- break;
- case StackElement::PrimitiveTypeEntry:
- element->entry = parsePrimitiveTypeEntry(reader, name, since, &attributes);
- if (Q_UNLIKELY(!element->entry))
- return false;
- break;
- case StackElement::ContainerTypeEntry:
- if (ContainerTypeEntry *ce = parseContainerTypeEntry(reader, name, since, &attributes)) {
- applyComplexTypeAttributes(reader, ce, &attributes);
- element->entry = ce;
- } else {
- return false;
- }
- break;
-
- case StackElement::SmartPointerTypeEntry:
- if (SmartPointerTypeEntry *se = parseSmartPointerEntry(reader, name, since, &attributes)) {
- applyComplexTypeAttributes(reader, se, &attributes);
- element->entry = se;
- } else {
- return false;
- }
- break;
- case StackElement::EnumTypeEntry:
- m_currentEnum = parseEnumTypeEntry(reader, name, since, &attributes);
- if (Q_UNLIKELY(!m_currentEnum))
- return false;
- element->entry = m_currentEnum;
- break;
-
- case StackElement::InterfaceTypeEntry:
- if (ObjectTypeEntry *oe = parseInterfaceTypeEntry(reader, name, since, &attributes)) {
- applyComplexTypeAttributes(reader, oe, &attributes);
- element->entry = oe;
- } else {
- return false;
- }
- break;
- case StackElement::ValueTypeEntry:
- if (ValueTypeEntry *ve = parseValueTypeEntry(reader, name, since, &attributes)) {
- applyComplexTypeAttributes(reader, ve, &attributes);
- element->entry = ve;
- } else {
- return false;
- }
- break;
- case StackElement::NamespaceTypeEntry:
- if (auto entry = parseNamespaceTypeEntry(reader, name, since, &attributes))
- element->entry = entry;
- else
- return false;
- break;
- case StackElement::ObjectTypeEntry:
- element->entry = new ObjectTypeEntry(name, since);
- applyCommonAttributes(element->entry, &attributes);
- applyComplexTypeAttributes(reader, static_cast<ComplexTypeEntry *>(element->entry), &attributes);
- break;
- case StackElement::FunctionTypeEntry:
- element->entry = parseFunctionTypeEntry(reader, name, since, &attributes);
- if (Q_UNLIKELY(!element->entry))
- return false;
- break;
- case StackElement::TypedefTypeEntry:
- if (TypedefEntry *te = parseTypedefEntry(reader, name, since, &attributes)) {
- applyComplexTypeAttributes(reader, te, &attributes);
- element->entry = te;
- } else {
- return false;
- }
- break;
- default:
- Q_ASSERT(false);
- };
-
- if (element->entry) {
- if (!m_database->addType(element->entry, &m_error))
- return false;
- } else {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("Type: %1 was rejected by typesystem").arg(name);
- }
-
- } else if (element->type == StackElement::InjectDocumentation) {
- if (!parseInjectDocumentation(reader, &attributes))
- return false;
- } else if (element->type == StackElement::ModifyDocumentation) {
- if (!parseModifyDocumentation(reader, &attributes))
- return false;
- } else if (element->type != StackElement::None) {
- bool topLevel = element->type == StackElement::Root
- || element->type == StackElement::SuppressedWarning
- || element->type == StackElement::Rejection
- || element->type == StackElement::LoadTypesystem
- || element->type == StackElement::InjectCode
- || element->type == StackElement::ExtraIncludes
- || element->type == StackElement::ConversionRule
- || element->type == StackElement::AddFunction
- || element->type == StackElement::Template;
-
- if (!topLevel && m_current->type == StackElement::Root) {
- m_error = QStringLiteral("Tag requires parent: '%1'").arg(tagName);
- return false;
- }
-
- StackElement topElement = !m_current ? StackElement(nullptr) : *m_current;
- element->entry = topElement.entry;
-
- switch (element->type) {
- case StackElement::Root:
- element->entry = parseRootElement(reader, since, &attributes);
- element->type = StackElement::Root;
- break;
- case StackElement::LoadTypesystem:
- if (!loadTypesystem(reader, &attributes))
- return false;
- break;
- case StackElement::RejectEnumValue:
- if (!parseRejectEnumValue(reader, &attributes))
- return false;
- break;
- case StackElement::ReplaceType:
- if (!parseReplaceArgumentType(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::ConversionRule:
- if (!Handler::parseCustomConversion(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::NativeToTarget:
- if (!parseNativeToTarget(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::TargetToNative: {
- if (topElement.type != StackElement::ConversionRule) {
- m_error = QLatin1String("Target to Native conversions can only be specified for custom conversion rules.");
- return false;
- }
- const int replaceIndex = indexOfAttribute(attributes, replaceAttribute());
- const bool replace = replaceIndex == -1
- || convertBoolean(attributes.takeAt(replaceIndex).value(),
- replaceAttribute(), true);
- m_current->entry->customConversion()->setReplaceOriginalTargetToNativeConversions(replace);
- }
- break;
- case StackElement::AddConversion:
- if (!parseAddConversion(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::ModifyArgument:
- if (!parseModifyArgument(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::NoNullPointers:
- if (!parseNoNullPointer(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::DefineOwnership:
- if (!parseDefineOwnership(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::SuppressedWarning: {
- const int textIndex = indexOfAttribute(attributes, textAttribute());
- if (textIndex == -1) {
- qCWarning(lcShiboken) << "Suppressed warning with no text specified";
- } else {
- const QString suppressedWarning =
- attributes.takeAt(textIndex).value().toString();
- if (!m_database->addSuppressedWarning(suppressedWarning, &m_error))
- return false;
- }
- }
- break;
- case StackElement::ArgumentMap:
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedElementWarning(reader, tagName)));
- if (!parseArgumentMap(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::Removal:
- if (!parseRemoval(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::Rename:
- case StackElement::Access:
- if (!parseRename(reader, element->type, topElement, &attributes))
- return false;
- break;
- case StackElement::RemoveArgument:
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("Removing argument requires argument modification as parent");
- return false;
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().removed = true;
- break;
-
- case StackElement::ModifyField:
- if (!parseModifyField(reader, &attributes))
- return false;
- break;
- case StackElement::AddFunction:
- if (!parseAddFunction(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::ModifyFunction:
- if (!parseModifyFunction(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::ReplaceDefaultExpression:
- if (!parseReplaceDefaultExpression(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::RemoveDefaultExpression:
- m_contextStack.top()->functionMods.last().argument_mods.last().removedDefaultExpression = true;
- break;
- case StackElement::CustomMetaConstructor:
- case StackElement::CustomMetaDestructor:
- element->value.customFunction =
- parseCustomMetaConstructor(reader, element->type, topElement, &attributes);
- break;
- case StackElement::ReferenceCount:
- if (!parseReferenceCount(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::ParentOwner:
- if (!parseParentOwner(reader, topElement, &attributes))
- return false;
- break;
- case StackElement::Array:
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("array must be child of modify-argument");
- return false;
- }
- m_contextStack.top()->functionMods.last().argument_mods.last().array = true;
- break;
- case StackElement::InjectCode:
- if (!parseInjectCode(reader, topElement, element, &attributes))
- return false;
- break;
- case StackElement::Include:
- if (!parseInclude(reader, topElement, element->entry, &attributes))
- return false;
- break;
- case StackElement::Rejection:
- if (!addRejection(m_database, &attributes, &m_error))
- return false;
- break;
- case StackElement::Template: {
- const int nameIndex = indexOfAttribute(attributes, nameAttribute());
- if (nameIndex == -1) {
- m_error = msgMissingAttribute(nameAttribute());
- return false;
- }
- element->value.templateEntry =
- new TemplateEntry(attributes.takeAt(nameIndex).value().toString());
- }
- break;
- case StackElement::TemplateInstanceEnum:
- element->value.templateInstance =
- parseTemplateInstanceEnum(reader, topElement, &attributes);
- if (!element->value.templateInstance)
- return false;
- break;
- case StackElement::Replace:
- if (!parseReplace(reader, topElement, element, &attributes))
- return false;
- break;
- default:
- break; // nada
- };
- }
-
- if (!attributes.isEmpty()) {
- const QString message = msgUnusedAttributes(tagName, attributes);
- qCWarning(lcShiboken, "%s", qPrintable(msgReaderWarning(reader, message)));
- }
-
- m_current = element;
- return true;
-}
-
PrimitiveTypeEntry::PrimitiveTypeEntry(const QString &name, const QVersionNumber &vr) :
TypeEntry(name, PrimitiveType, vr),
m_preferredTargetLangType(true)
diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.cpp b/sources/shiboken2/ApiExtractor/typesystemparser.cpp
new file mode 100644
index 00000000..57ceb357
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/typesystemparser.cpp
@@ -0,0 +1,2974 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "typesystemparser.h"
+#include "typedatabase.h"
+#include "messages.h"
+#include "reporthandler.h"
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QSet>
+#include <QtCore/QStringView>
+#include <QtCore/QStringAlgorithms>
+#include <QtCore/QXmlStreamAttributes>
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QXmlStreamEntityResolver>
+
+#include <algorithm>
+
+const char *TARGET_CONVERSION_RULE_FLAG = "0";
+const char *NATIVE_CONVERSION_RULE_FLAG = "1";
+
+static inline QString allowThreadAttribute() { return QStringLiteral("allow-thread"); }
+static inline QString colonColon() { return QStringLiteral("::"); }
+static inline QString copyableAttribute() { return QStringLiteral("copyable"); }
+static inline QString accessAttribute() { return QStringLiteral("access"); }
+static inline QString actionAttribute() { return QStringLiteral("action"); }
+static inline QString quoteAfterLineAttribute() { return QStringLiteral("quote-after-line"); }
+static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote-before-line"); }
+static inline QString textAttribute() { return QStringLiteral("text"); }
+static inline QString nameAttribute() { return QStringLiteral("name"); }
+static inline QString sinceAttribute() { return QStringLiteral("since"); }
+static inline QString defaultSuperclassAttribute() { return QStringLiteral("default-superclass"); }
+static inline QString deleteInMainThreadAttribute() { return QStringLiteral("delete-in-main-thread"); }
+static inline QString deprecatedAttribute() { return QStringLiteral("deprecated"); }
+static inline QString exceptionHandlingAttribute() { return QStringLiteral("exception-handling"); }
+static inline QString extensibleAttribute() { return QStringLiteral("extensible"); }
+static inline QString flagsAttribute() { return QStringLiteral("flags"); }
+static inline QString forceAbstractAttribute() { return QStringLiteral("force-abstract"); }
+static inline QString forceIntegerAttribute() { return QStringLiteral("force-integer"); }
+static inline QString formatAttribute() { return QStringLiteral("format"); }
+static inline QString classAttribute() { return QStringLiteral("class"); }
+static inline QString generateAttribute() { return QStringLiteral("generate"); }
+static inline QString genericClassAttribute() { return QStringLiteral("generic-class"); }
+static inline QString indexAttribute() { return QStringLiteral("index"); }
+static inline QString invalidateAfterUseAttribute() { return QStringLiteral("invalidate-after-use"); }
+static inline QString locationAttribute() { return QStringLiteral("location"); }
+static inline QString modifiedTypeAttribute() { return QStringLiteral("modified-type"); }
+static inline QString modifierAttribute() { return QStringLiteral("modifier"); }
+static inline QString ownershipAttribute() { return QStringLiteral("owner"); }
+static inline QString packageAttribute() { return QStringLiteral("package"); }
+static inline QString positionAttribute() { return QStringLiteral("position"); }
+static inline QString preferredConversionAttribute() { return QStringLiteral("preferred-conversion"); }
+static inline QString preferredTargetLangTypeAttribute() { return QStringLiteral("preferred-target-lang-type"); }
+static inline QString removeAttribute() { return QStringLiteral("remove"); }
+static inline QString renameAttribute() { return QStringLiteral("rename"); }
+static inline QString readAttribute() { return QStringLiteral("read"); }
+static inline QString writeAttribute() { return QStringLiteral("write"); }
+static inline QString replaceAttribute() { return QStringLiteral("replace"); }
+static inline QString toAttribute() { return QStringLiteral("to"); }
+static inline QString signatureAttribute() { return QStringLiteral("signature"); }
+static inline QString snippetAttribute() { return QStringLiteral("snippet"); }
+static inline QString staticAttribute() { return QStringLiteral("static"); }
+static inline QString threadAttribute() { return QStringLiteral("thread"); }
+static inline QString sourceAttribute() { return QStringLiteral("source"); }
+static inline QString streamAttribute() { return QStringLiteral("stream"); }
+static inline QString xPathAttribute() { return QStringLiteral("xpath"); }
+static inline QString virtualSlotAttribute() { return QStringLiteral("virtual-slot"); }
+static inline QString enumIdentifiedByValueAttribute() { return QStringLiteral("identified-by-value"); }
+
+static inline QString noAttributeValue() { return QStringLiteral("no"); }
+static inline QString yesAttributeValue() { return QStringLiteral("yes"); }
+static inline QString trueAttributeValue() { return QStringLiteral("true"); }
+static inline QString falseAttributeValue() { return QStringLiteral("false"); }
+
+static QVector<CustomConversion *> customConversionsForReview;
+
+// Set a regular expression for rejection from text. By legacy, those are fixed
+// strings, except for '*' meaning 'match all'. Enclosing in "^..$"
+// indicates regular expression.
+static bool setRejectionRegularExpression(const QString &patternIn,
+ QRegularExpression *re,
+ QString *errorMessage)
+{
+ QString pattern;
+ if (patternIn.startsWith(QLatin1Char('^')) && patternIn.endsWith(QLatin1Char('$')))
+ pattern = patternIn;
+ else if (patternIn == QLatin1String("*"))
+ pattern = QStringLiteral("^.*$");
+ else
+ pattern = QLatin1Char('^') + QRegularExpression::escape(patternIn) + QLatin1Char('$');
+ re->setPattern(pattern);
+ if (!re->isValid()) {
+ *errorMessage = msgInvalidRegularExpression(patternIn, re->errorString());
+ return false;
+ }
+ return true;
+}
+
+// Extract a snippet from a file within annotation "// @snippet label".
+static QString extractSnippet(const QString &code, const QString &snippetLabel)
+{
+ if (snippetLabel.isEmpty())
+ return code;
+ const QString pattern = QStringLiteral(R"(^\s*//\s*@snippet\s+)")
+ + QRegularExpression::escape(snippetLabel)
+ + QStringLiteral(R"(\s*$)");
+ const QRegularExpression snippetRe(pattern);
+ Q_ASSERT(snippetRe.isValid());
+
+ bool useLine = false;
+ QString result;
+ const auto lines = code.splitRef(QLatin1Char('\n'));
+ for (const QStringRef &line : lines) {
+ if (snippetRe.match(line).hasMatch()) {
+ useLine = !useLine;
+ if (!useLine)
+ break; // End of snippet reached
+ } else if (useLine)
+ result += line.toString() + QLatin1Char('\n');
+ }
+ return result;
+}
+
+template <class EnumType, Qt::CaseSensitivity cs = Qt::CaseInsensitive>
+struct EnumLookup
+{
+ QStringView name;
+ EnumType value;
+};
+
+template <class EnumType, Qt::CaseSensitivity cs>
+bool operator==(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2)
+{
+ return e1.name.compare(e2.name, cs) == 0;
+}
+
+template <class EnumType, Qt::CaseSensitivity cs>
+bool operator<(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2)
+{
+ return e1.name.compare(e2.name, cs) < 0;
+}
+
+// Helper macros to define lookup functions that take a QStringView needle
+// and an optional default return value.
+#define ENUM_LOOKUP_BEGIN(EnumType, caseSensitivity, functionName, defaultReturnValue) \
+static EnumType functionName(QStringView needle, EnumType defaultValue = defaultReturnValue) \
+{ \
+ typedef EnumLookup<EnumType, caseSensitivity> HaystackEntry; \
+ static const HaystackEntry haystack[] =
+
+#define ENUM_LOOKUP_LINEAR_SEARCH() \
+ const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \
+ const auto it = std::find(haystack, end, HaystackEntry{needle, defaultValue}); \
+ return it != end ? it->value : defaultValue; \
+}
+
+#define ENUM_LOOKUP_BINARY_SEARCH() \
+ const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \
+ const HaystackEntry needleEntry{needle, defaultValue}; \
+ const auto lb = std::lower_bound(haystack, end, needleEntry); \
+ return lb != end && *lb == needleEntry ? lb->value : defaultValue; \
+}
+
+ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive,
+ allowThreadFromAttribute, TypeSystem::AllowThread::Unspecified)
+ {
+ {QStringViewLiteral("yes"), TypeSystem::AllowThread::Allow},
+ {QStringViewLiteral("true"), TypeSystem::AllowThread::Allow},
+ {QStringViewLiteral("auto"), TypeSystem::AllowThread::Auto},
+ {QStringViewLiteral("no"), TypeSystem::AllowThread::Disallow},
+ {QStringViewLiteral("false"), TypeSystem::AllowThread::Disallow},
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive,
+ languageFromAttribute, TypeSystem::NoLanguage)
+ {
+ {QStringViewLiteral("all"), TypeSystem::All}, // sorted!
+ {QStringViewLiteral("constructors"), TypeSystem::Constructors},
+ {QStringViewLiteral("destructor-function"), TypeSystem::DestructorFunction},
+ {QStringViewLiteral("interface"), TypeSystem::Interface},
+ {QStringViewLiteral("library-initializer"), TypeSystem::PackageInitializer},
+ {QStringViewLiteral("native"), TypeSystem::NativeCode}, // em algum lugar do cpp
+ {QStringViewLiteral("shell"), TypeSystem::ShellCode}, // coloca no header, mas antes da declaracao da classe
+ {QStringViewLiteral("shell-declaration"), TypeSystem::ShellDeclaration},
+ {QStringViewLiteral("target"), TypeSystem::TargetLangCode} // em algum lugar do cpp
+ };
+ENUM_LOOKUP_BINARY_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive,
+ ownershipFromFromAttribute, TypeSystem::InvalidOwnership)
+ {
+ {QStringViewLiteral("target"), TypeSystem::TargetLangOwnership},
+ {QStringViewLiteral("c++"), TypeSystem::CppOwnership},
+ {QStringViewLiteral("default"), TypeSystem::DefaultOwnership}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive,
+ addedFunctionAccessFromAttribute, AddedFunction::InvalidAccess)
+ {
+ {QStringViewLiteral("public"), AddedFunction::Public},
+ {QStringViewLiteral("protected"), AddedFunction::Protected},
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(Modification::Modifiers, Qt::CaseSensitive,
+ modifierFromAttribute, Modification::InvalidModifier)
+ {
+ {QStringViewLiteral("private"), Modification::Private},
+ {QStringViewLiteral("public"), Modification::Public},
+ {QStringViewLiteral("protected"), Modification::Protected},
+ {QStringViewLiteral("friendly"), Modification::Friendly},
+ {QStringViewLiteral("rename"), Modification::Rename},
+ {QStringViewLiteral("final"), Modification::Final},
+ {QStringViewLiteral("non-final"), Modification::NonFinal}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive,
+ referenceCountFromAttribute, ReferenceCount::Invalid)
+ {
+ {QStringViewLiteral("add"), ReferenceCount::Add},
+ {QStringViewLiteral("add-all"), ReferenceCount::AddAll},
+ {QStringViewLiteral("remove"), ReferenceCount::Remove},
+ {QStringViewLiteral("set"), ReferenceCount::Set},
+ {QStringViewLiteral("ignore"), ReferenceCount::Ignore}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive,
+ argumentOwnerActionFromAttribute, ArgumentOwner::Invalid)
+ {
+ {QStringViewLiteral("add"), ArgumentOwner::Add},
+ {QStringViewLiteral("remove"), ArgumentOwner::Remove}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeSystem::CodeSnipPosition, Qt::CaseInsensitive,
+ codeSnipPositionFromAttribute, TypeSystem::CodeSnipPositionInvalid)
+ {
+ {QStringViewLiteral("beginning"), TypeSystem::CodeSnipPositionBeginning},
+ {QStringViewLiteral("end"), TypeSystem::CodeSnipPositionEnd},
+ {QStringViewLiteral("declaration"), TypeSystem::CodeSnipPositionDeclaration},
+ {QStringViewLiteral("prototype-initialization"), TypeSystem::CodeSnipPositionPrototypeInitialization},
+ {QStringViewLiteral("constructor-initialization"), TypeSystem::CodeSnipPositionConstructorInitialization},
+ {QStringViewLiteral("constructor"), TypeSystem::CodeSnipPositionConstructor}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive,
+ locationFromAttribute, Include::InvalidInclude)
+ {
+ {QStringViewLiteral("global"), Include::IncludePath},
+ {QStringViewLiteral("local"), Include::LocalPath},
+ {QStringViewLiteral("target"), Include::TargetLangImport}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive,
+ docModificationFromAttribute, TypeSystem::DocModificationInvalid)
+ {
+ {QStringViewLiteral("append"), TypeSystem::DocModificationAppend},
+ {QStringViewLiteral("prepend"), TypeSystem::DocModificationPrepend},
+ {QStringViewLiteral("replace"), TypeSystem::DocModificationReplace}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(ContainerTypeEntry::Type, Qt::CaseSensitive,
+ containerTypeFromAttribute, ContainerTypeEntry::NoContainer)
+ {
+ {QStringViewLiteral("list"), ContainerTypeEntry::ListContainer},
+ {QStringViewLiteral("string-list"), ContainerTypeEntry::StringListContainer},
+ {QStringViewLiteral("linked-list"), ContainerTypeEntry::LinkedListContainer},
+ {QStringViewLiteral("vector"), ContainerTypeEntry::VectorContainer},
+ {QStringViewLiteral("stack"), ContainerTypeEntry::StackContainer},
+ {QStringViewLiteral("queue"), ContainerTypeEntry::QueueContainer},
+ {QStringViewLiteral("set"), ContainerTypeEntry::SetContainer},
+ {QStringViewLiteral("map"), ContainerTypeEntry::MapContainer},
+ {QStringViewLiteral("multi-map"), ContainerTypeEntry::MultiMapContainer},
+ {QStringViewLiteral("hash"), ContainerTypeEntry::HashContainer},
+ {QStringViewLiteral("multi-hash"), ContainerTypeEntry::MultiHashContainer},
+ {QStringViewLiteral("pair"), ContainerTypeEntry::PairContainer}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive,
+ typeRejectionFromAttribute, TypeRejection::Invalid)
+ {
+ {QStringViewLiteral("class"), TypeRejection::ExcludeClass},
+ {QStringViewLiteral("function-name"), TypeRejection::Function},
+ {QStringViewLiteral("field-name"), TypeRejection::Field},
+ {QStringViewLiteral("enum-name"), TypeRejection::Enum },
+ {QStringViewLiteral("argument-type"), TypeRejection::ArgumentType},
+ {QStringViewLiteral("return-type"), TypeRejection::ReturnType}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive,
+ exceptionHandlingFromAttribute, TypeSystem::ExceptionHandling::Unspecified)
+{
+ {QStringViewLiteral("no"), TypeSystem::ExceptionHandling::Off},
+ {QStringViewLiteral("false"), TypeSystem::ExceptionHandling::Off},
+ {QStringViewLiteral("auto-off"), TypeSystem::ExceptionHandling::AutoDefaultToOff},
+ {QStringViewLiteral("auto-on"), TypeSystem::ExceptionHandling::AutoDefaultToOn},
+ {QStringViewLiteral("yes"), TypeSystem::ExceptionHandling::On},
+ {QStringViewLiteral("true"), TypeSystem::ExceptionHandling::On},
+};
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive,
+ elementFromTag, StackElement::None)
+ {
+ {QStringViewLiteral("access"), StackElement::Access}, // sorted!
+ {QStringViewLiteral("add-conversion"), StackElement::AddConversion},
+ {QStringViewLiteral("add-function"), StackElement::AddFunction},
+ {QStringViewLiteral("argument-map"), StackElement::ArgumentMap},
+ {QStringViewLiteral("array"), StackElement::Array},
+ {QStringViewLiteral("container-type"), StackElement::ContainerTypeEntry},
+ {QStringViewLiteral("conversion-rule"), StackElement::ConversionRule},
+ {QStringViewLiteral("custom-constructor"), StackElement::CustomMetaConstructor},
+ {QStringViewLiteral("custom-destructor"), StackElement::CustomMetaDestructor},
+ {QStringViewLiteral("custom-type"), StackElement::CustomTypeEntry},
+ {QStringViewLiteral("define-ownership"), StackElement::DefineOwnership},
+ {QStringViewLiteral("enum-type"), StackElement::EnumTypeEntry},
+ {QStringViewLiteral("extra-includes"), StackElement::ExtraIncludes},
+ {QStringViewLiteral("function"), StackElement::FunctionTypeEntry},
+ {QStringViewLiteral("include"), StackElement::Include},
+ {QStringViewLiteral("inject-code"), StackElement::InjectCode},
+ {QStringViewLiteral("inject-documentation"), StackElement::InjectDocumentation},
+ {QStringViewLiteral("insert-template"), StackElement::TemplateInstanceEnum},
+ {QStringViewLiteral("interface-type"), StackElement::InterfaceTypeEntry},
+ {QStringViewLiteral("load-typesystem"), StackElement::LoadTypesystem},
+ {QStringViewLiteral("modify-argument"), StackElement::ModifyArgument},
+ {QStringViewLiteral("modify-documentation"), StackElement::ModifyDocumentation},
+ {QStringViewLiteral("modify-field"), StackElement::ModifyField},
+ {QStringViewLiteral("modify-function"), StackElement::ModifyFunction},
+ {QStringViewLiteral("namespace-type"), StackElement::NamespaceTypeEntry},
+ {QStringViewLiteral("native-to-target"), StackElement::NativeToTarget},
+ {QStringViewLiteral("no-null-pointer"), StackElement::NoNullPointers},
+ {QStringViewLiteral("object-type"), StackElement::ObjectTypeEntry},
+ {QStringViewLiteral("parent"), StackElement::ParentOwner},
+ {QStringViewLiteral("primitive-type"), StackElement::PrimitiveTypeEntry},
+ {QStringViewLiteral("reference-count"), StackElement::ReferenceCount},
+ {QStringViewLiteral("reject-enum-value"), StackElement::RejectEnumValue},
+ {QStringViewLiteral("rejection"), StackElement::Rejection},
+ {QStringViewLiteral("remove"), StackElement::Removal},
+ {QStringViewLiteral("remove-argument"), StackElement::RemoveArgument},
+ {QStringViewLiteral("remove-default-expression"), StackElement::RemoveDefaultExpression},
+ {QStringViewLiteral("rename"), StackElement::Rename},
+ {QStringViewLiteral("replace"), StackElement::Replace},
+ {QStringViewLiteral("replace-default-expression"), StackElement::ReplaceDefaultExpression},
+ {QStringViewLiteral("replace-type"), StackElement::ReplaceType},
+ {QStringViewLiteral("smart-pointer-type"), StackElement::SmartPointerTypeEntry},
+ {QStringViewLiteral("suppress-warning"), StackElement::SuppressedWarning},
+ {QStringViewLiteral("target-to-native"), StackElement::TargetToNative},
+ {QStringViewLiteral("template"), StackElement::Template},
+ {QStringViewLiteral("typedef-type"), StackElement::TypedefTypeEntry},
+ {QStringViewLiteral("typesystem"), StackElement::Root},
+ {QStringViewLiteral("value-type"), StackElement::ValueTypeEntry},
+ };
+ENUM_LOOKUP_BINARY_SEARCH()
+
+static int indexOfAttribute(const QXmlStreamAttributes &atts,
+ QStringView name)
+{
+ for (int i = 0, size = atts.size(); i < size; ++i) {
+ if (atts.at(i).qualifiedName() == name)
+ return i;
+ }
+ return -1;
+}
+
+static QString msgMissingAttribute(const QString &a)
+{
+ return QLatin1String("Required attribute '") + a
+ + QLatin1String("' missing.");
+}
+
+QTextStream &operator<<(QTextStream &str, const QXmlStreamAttribute &attribute)
+{
+ str << attribute.qualifiedName() << "=\"" << attribute.value() << '"';
+ return str;
+}
+
+static QString msgInvalidAttributeValue(const QXmlStreamAttribute &attribute)
+{
+ QString result;
+ QTextStream(&result) << "Invalid attribute value:" << attribute;
+ return result;
+}
+
+static QString msgUnusedAttributes(const QStringRef &tag, const QXmlStreamAttributes &attributes)
+{
+ QString result;
+ QTextStream str(&result);
+ str << attributes.size() << " attributes(s) unused on <" << tag << ">: ";
+ for (int i = 0, size = attributes.size(); i < size; ++i) {
+ if (i)
+ str << ", ";
+ str << attributes.at(i);
+ }
+ return result;
+}
+
+// QXmlStreamEntityResolver::resolveEntity(publicId, systemId) is not
+// implemented; resolve via undeclared entities instead.
+class TypeSystemEntityResolver : public QXmlStreamEntityResolver
+{
+public:
+ explicit TypeSystemEntityResolver(const QString &currentPath) :
+ m_currentPath(currentPath) {}
+
+ QString resolveUndeclaredEntity(const QString &name) override;
+
+private:
+ QString readFile(const QString &entityName, QString *errorMessage) const;
+
+ const QString m_currentPath;
+ QHash<QString, QString> m_cache;
+};
+
+QString TypeSystemEntityResolver::readFile(const QString &entityName, QString *errorMessage) const
+{
+ QString fileName = entityName;
+ if (!fileName.contains(QLatin1Char('.')))
+ fileName += QLatin1String(".xml");
+ QString path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath);
+ if (!QFileInfo::exists(path)) // PySide2-specific hack
+ fileName.prepend(QLatin1String("typesystem_"));
+ path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath);
+ if (!QFileInfo::exists(path)) {
+ *errorMessage = QLatin1String("Unable to resolve: ") + entityName;
+ return QString();
+ }
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ *errorMessage = msgCannotOpenForReading(file);
+ return QString();
+ }
+ QString result = QString::fromUtf8(file.readAll()).trimmed();
+ // Remove license header comments on which QXmlStreamReader chokes
+ if (result.startsWith(QLatin1String("<!--"))) {
+ const int commentEnd = result.indexOf(QLatin1String("-->"));
+ if (commentEnd != -1) {
+ result.remove(0, commentEnd + 3);
+ result = result.trimmed();
+ }
+ }
+ return result;
+}
+
+QString TypeSystemEntityResolver::resolveUndeclaredEntity(const QString &name)
+{
+ auto it = m_cache.find(name);
+ if (it == m_cache.end()) {
+ QString errorMessage;
+ it = m_cache.insert(name, readFile(name, &errorMessage));
+ if (it.value().isEmpty()) { // The parser will fail and display the line number.
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgCannotResolveEntity(name, errorMessage)));
+ }
+ }
+ return it.value();
+}
+
+TypeSystemParser::TypeSystemParser(TypeDatabase *database, bool generate) :
+ m_database(database),
+ m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
+{
+}
+
+TypeSystemParser::~TypeSystemParser() = default;
+
+static QString readerFileName(const QXmlStreamReader &reader)
+{
+ const auto *file = qobject_cast<const QFile *>(reader.device());
+ return file != nullptr ? file->fileName() : QString();
+}
+
+static QString msgReaderMessage(const QXmlStreamReader &reader,
+ const char *type,
+ const QString &what)
+{
+ QString message;
+ QTextStream str(&message);
+ str << type << ": ";
+ const QString fileName = readerFileName(reader);
+ if (fileName.isEmpty())
+ str << "<stdin>:";
+ else
+ str << QDir::toNativeSeparators(fileName) << ':';
+ str << reader.lineNumber() << ':' << reader.columnNumber()
+ << ": " << what;
+ return message;
+}
+
+static QString msgReaderWarning(const QXmlStreamReader &reader, const QString &what)
+{
+ return msgReaderMessage(reader, "Warning", what);
+}
+
+static QString msgReaderError(const QXmlStreamReader &reader, const QString &what)
+{
+ return msgReaderMessage(reader, "Error", what);
+}
+
+static QString msgUnimplementedElementWarning(const QXmlStreamReader &reader,
+ const QStringRef &name)
+{
+ const QString message = QLatin1String("The element \"") +
+ name + QLatin1String("\" is not implemented.");
+ return msgReaderMessage(reader, "Warning", message);
+}
+
+static QString msgUnimplementedAttributeWarning(const QXmlStreamReader &reader,
+ const QStringRef &name)
+{
+ const QString message = QLatin1String("The attribute \"") +
+ name + QLatin1String("\" is not implemented.");
+ return msgReaderMessage(reader, "Warning", message);
+}
+
+static inline QString msgUnimplementedAttributeWarning(const QXmlStreamReader &reader,
+ const QXmlStreamAttribute &attribute)
+{
+ return msgUnimplementedAttributeWarning(reader, attribute.qualifiedName());
+}
+
+static QString
+ msgUnimplementedAttributeValueWarning(const QXmlStreamReader &reader,
+ QStringView name, QStringView value)
+{
+ QString message;
+ QTextStream(&message) << "The value \"" << value
+ << "\" of the attribute \"" << name << "\" is not implemented.";
+ return msgReaderMessage(reader, "Warning", message);
+}
+
+static inline
+ QString msgUnimplementedAttributeValueWarning(const QXmlStreamReader &reader,
+ const QXmlStreamAttribute &attribute)
+{
+ return msgUnimplementedAttributeValueWarning(reader,
+ attribute.qualifiedName(),
+ attribute.value());
+}
+
+static QString msgInvalidVersion(const QStringRef &version, const QString &package = QString())
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Invalid version \"" << version << '"';
+ if (!package.isEmpty())
+ str << "\" specified for package " << package;
+ str << '.';
+ return result;
+}
+
+static bool addRejection(TypeDatabase *database, QXmlStreamAttributes *attributes,
+ QString *errorMessage)
+{
+ const int classIndex = indexOfAttribute(*attributes, classAttribute());
+ if (classIndex == -1) {
+ *errorMessage = msgMissingAttribute(classAttribute());
+ return false;
+ }
+
+ TypeRejection rejection;
+ const QString className = attributes->takeAt(classIndex).value().toString();
+ if (!setRejectionRegularExpression(className, &rejection.className, errorMessage))
+ return false;
+
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ const TypeRejection::MatchType type = typeRejectionFromAttribute(name);
+ switch (type) {
+ case TypeRejection::Function:
+ case TypeRejection::Field:
+ case TypeRejection::Enum:
+ case TypeRejection::ArgumentType:
+ case TypeRejection::ReturnType: {
+ const QString pattern = attributes->takeAt(i).value().toString();
+ if (!setRejectionRegularExpression(pattern, &rejection.pattern, errorMessage))
+ return false;
+ rejection.matchType = type;
+ database->addRejection(rejection);
+ return true;
+ }
+ default:
+ break;
+ }
+ }
+
+ // Special case: When all fields except class are empty, completely exclude class
+ if (className == QLatin1String("*")) {
+ *errorMessage = QLatin1String("bad reject entry, neither 'class', 'function-name'"
+ " nor 'field' specified");
+ return false;
+ }
+ rejection.matchType = TypeRejection::ExcludeClass;
+ database->addRejection(rejection);
+ return true;
+}
+
+bool TypeSystemParser::parse(QXmlStreamReader &reader)
+{
+ m_error.clear();
+ m_currentPath.clear();
+ const QString fileName = readerFileName(reader);
+ if (!fileName.isEmpty())
+ m_currentPath = QFileInfo(fileName).absolutePath();
+ m_entityResolver.reset(new TypeSystemEntityResolver(m_currentPath));
+ reader.setEntityResolver(m_entityResolver.data());
+
+ while (!reader.atEnd()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::NoToken:
+ case QXmlStreamReader::Invalid:
+ m_error = msgReaderError(reader, reader.errorString());
+ return false;
+ case QXmlStreamReader::StartElement:
+ if (!startElement(reader)) {
+ m_error = msgReaderError(reader, m_error);
+ return false;
+ }
+
+ break;
+ case QXmlStreamReader::EndElement:
+ if (!endElement(reader.name())) {
+ m_error = msgReaderError(reader, m_error);
+ return false;
+ }
+ break;
+ case QXmlStreamReader::Characters:
+ if (!characters(reader.text())) {
+ m_error = msgReaderError(reader, m_error);
+ return false;
+ }
+ break;
+ case QXmlStreamReader::StartDocument:
+ case QXmlStreamReader::EndDocument:
+ case QXmlStreamReader::Comment:
+ case QXmlStreamReader::DTD:
+ case QXmlStreamReader::EntityReference:
+ case QXmlStreamReader::ProcessingInstruction:
+ break;
+ }
+ }
+ return true;
+}
+
+bool TypeSystemParser::endElement(const QStringRef &localName)
+{
+ if (m_ignoreDepth) {
+ --m_ignoreDepth;
+ return true;
+ }
+
+ if (m_currentDroppedEntry) {
+ if (m_currentDroppedEntryDepth == 1) {
+ m_current = m_currentDroppedEntry->parent;
+ delete m_currentDroppedEntry;
+ m_currentDroppedEntry = nullptr;
+ m_currentDroppedEntryDepth = 0;
+ } else {
+ --m_currentDroppedEntryDepth;
+ }
+ return true;
+ }
+
+ if (!localName.compare(QLatin1String("import-file"), Qt::CaseInsensitive))
+ return true;
+
+ if (!m_current)
+ return true;
+
+ switch (m_current->type) {
+ case StackElement::Root:
+ if (m_generate == TypeEntry::GenerateAll) {
+ TypeDatabase::instance()->addGlobalUserFunctions(m_contextStack.top()->addedFunctions);
+ TypeDatabase::instance()->addGlobalUserFunctionModifications(m_contextStack.top()->functionMods);
+ for (CustomConversion *customConversion : qAsConst(customConversionsForReview)) {
+ const CustomConversion::TargetToNativeConversions &toNatives = customConversion->targetToNativeConversions();
+ for (CustomConversion::TargetToNativeConversion *toNative : toNatives)
+ toNative->setSourceType(m_database->findType(toNative->sourceTypeName()));
+ }
+ }
+ break;
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ case StackElement::NamespaceTypeEntry: {
+ auto *centry = static_cast<ComplexTypeEntry *>(m_current->entry);
+ centry->setAddedFunctions(m_contextStack.top()->addedFunctions);
+ centry->setFunctionModifications(m_contextStack.top()->functionMods);
+ centry->setFieldModifications(m_contextStack.top()->fieldMods);
+ centry->setCodeSnips(m_contextStack.top()->codeSnips);
+ centry->setDocModification(m_contextStack.top()->docModifications);
+
+ if (centry->designatedInterface()) {
+ centry->designatedInterface()->setCodeSnips(m_contextStack.top()->codeSnips);
+ centry->designatedInterface()->setFunctionModifications(m_contextStack.top()->functionMods);
+ }
+ }
+ break;
+ case StackElement::AddFunction: {
+ // Leaving add-function: Assign all modifications to the added function
+ StackElementContext *top = m_contextStack.top();
+ const int modIndex = top->addedFunctionModificationIndex;
+ top->addedFunctionModificationIndex = -1;
+ Q_ASSERT(modIndex >= 0);
+ Q_ASSERT(!top->addedFunctions.isEmpty());
+ while (modIndex < top->functionMods.size())
+ top->addedFunctions.last()->modifications.append(top->functionMods.takeAt(modIndex));
+ }
+ break;
+ case StackElement::NativeToTarget:
+ case StackElement::AddConversion: {
+ CustomConversion* customConversion = static_cast<TypeEntry*>(m_current->entry)->customConversion();
+ if (!customConversion) {
+ m_error = QLatin1String("CustomConversion object is missing.");
+ return false;
+ }
+
+ QString code = m_contextStack.top()->codeSnips.takeLast().code();
+ if (m_current->type == StackElement::AddConversion) {
+ if (customConversion->targetToNativeConversions().isEmpty()) {
+ m_error = QLatin1String("CustomConversion's target to native conversions missing.");
+ return false;
+ }
+ customConversion->targetToNativeConversions().last()->setConversion(code);
+ } else {
+ customConversion->setNativeToTargetConversion(code);
+ }
+ }
+ break;
+ case StackElement::CustomMetaConstructor: {
+ m_current->entry->setCustomConstructor(*m_current->value.customFunction);
+ delete m_current->value.customFunction;
+ }
+ break;
+ case StackElement::CustomMetaDestructor: {
+ m_current->entry->setCustomDestructor(*m_current->value.customFunction);
+ delete m_current->value.customFunction;
+ }
+ break;
+ case StackElement::EnumTypeEntry:
+ m_current->entry->setDocModification(m_contextStack.top()->docModifications);
+ m_contextStack.top()->docModifications = DocModificationList();
+ m_currentEnum = nullptr;
+ break;
+ case StackElement::Template:
+ m_database->addTemplate(m_current->value.templateEntry);
+ break;
+ case StackElement::TemplateInstanceEnum:
+ switch (m_current->parent->type) {
+ case StackElement::InjectCode:
+ if (m_current->parent->parent->type == StackElement::Root) {
+ CodeSnipList snips = m_current->parent->entry->codeSnips();
+ CodeSnip snip = snips.takeLast();
+ snip.addTemplateInstance(m_current->value.templateInstance);
+ snips.append(snip);
+ m_current->parent->entry->setCodeSnips(snips);
+ break;
+ }
+ Q_FALLTHROUGH();
+ case StackElement::NativeToTarget:
+ case StackElement::AddConversion:
+ m_contextStack.top()->codeSnips.last().addTemplateInstance(m_current->value.templateInstance);
+ break;
+ case StackElement::Template:
+ m_current->parent->value.templateEntry->addTemplateInstance(m_current->value.templateInstance);
+ break;
+ case StackElement::CustomMetaConstructor:
+ case StackElement::CustomMetaDestructor:
+ m_current->parent->value.customFunction->addTemplateInstance(m_current->value.templateInstance);
+ break;
+ case StackElement::ConversionRule:
+ m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.last().addTemplateInstance(m_current->value.templateInstance);
+ break;
+ case StackElement::InjectCodeInFunction:
+ m_contextStack.top()->functionMods.last().snips.last().addTemplateInstance(m_current->value.templateInstance);
+ break;
+ default:
+ break; // nada
+ };
+ break;
+ default:
+ break;
+ }
+
+ switch (m_current->type) {
+ case StackElement::Root:
+ case StackElement::NamespaceTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::PrimitiveTypeEntry:
+ case StackElement::TypedefTypeEntry:
+ delete m_contextStack.pop();
+ break;
+ default:
+ break;
+ }
+
+ StackElement *child = m_current;
+ m_current = m_current->parent;
+ delete(child);
+
+ return true;
+}
+
+template <class String> // QString/QStringRef
+bool TypeSystemParser::characters(const String &ch)
+{
+ if (m_currentDroppedEntry || m_ignoreDepth)
+ return true;
+
+ if (m_current->type == StackElement::Template) {
+ m_current->value.templateEntry->addCode(ch);
+ return true;
+ }
+
+ if (m_current->type == StackElement::CustomMetaConstructor || m_current->type == StackElement::CustomMetaDestructor) {
+ m_current->value.customFunction->addCode(ch);
+ return true;
+ }
+
+ if (m_current->type == StackElement::ConversionRule
+ && m_current->parent->type == StackElement::ModifyArgument) {
+ m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.last().addCode(ch);
+ return true;
+ }
+
+ if (m_current->type == StackElement::NativeToTarget || m_current->type == StackElement::AddConversion) {
+ m_contextStack.top()->codeSnips.last().addCode(ch);
+ return true;
+ }
+
+ if (m_current->parent) {
+ if ((m_current->type & StackElement::CodeSnipMask)) {
+ CodeSnipList snips;
+ switch (m_current->parent->type) {
+ case StackElement::Root:
+ snips = m_current->parent->entry->codeSnips();
+ snips.last().addCode(ch);
+ m_current->parent->entry->setCodeSnips(snips);
+ break;
+ case StackElement::ModifyFunction:
+ case StackElement::AddFunction:
+ m_contextStack.top()->functionMods.last().snips.last().addCode(ch);
+ m_contextStack.top()->functionMods.last().modifiers |= FunctionModification::CodeInjection;
+ break;
+ case StackElement::NamespaceTypeEntry:
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ m_contextStack.top()->codeSnips.last().addCode(ch);
+ break;
+ default:
+ Q_ASSERT(false);
+ };
+ return true;
+ }
+ }
+
+ if (m_current->type & StackElement::DocumentationMask)
+ m_contextStack.top()->docModifications.last().setCode(ch);
+
+ return true;
+}
+
+bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts)
+{
+ const QString fileName = atts.value(nameAttribute()).toString();
+ if (fileName.isEmpty()) {
+ m_error = QLatin1String("Required attribute 'name' missing for include-file tag.");
+ return false;
+ }
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ file.setFileName(QLatin1String(":/trolltech/generator/") + fileName);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ m_error = QString::fromLatin1("Could not open file: '%1'").arg(QDir::toNativeSeparators(fileName));
+ return false;
+ }
+ }
+
+ const QStringRef quoteFrom = atts.value(quoteAfterLineAttribute());
+ bool foundFromOk = quoteFrom.isEmpty();
+ bool from = quoteFrom.isEmpty();
+
+ const QStringRef quoteTo = atts.value(quoteBeforeLineAttribute());
+ bool foundToOk = quoteTo.isEmpty();
+ bool to = true;
+
+ QTextStream in(&file);
+ while (!in.atEnd()) {
+ QString line = in.readLine();
+ if (from && to && line.contains(quoteTo)) {
+ to = false;
+ foundToOk = true;
+ break;
+ }
+ if (from && to)
+ characters(line + QLatin1Char('\n'));
+ if (!from && line.contains(quoteFrom)) {
+ from = true;
+ foundFromOk = true;
+ }
+ }
+ if (!foundFromOk || !foundToOk) {
+ QString fromError = QStringLiteral("Could not find quote-after-line='%1' in file '%2'.")
+ .arg(quoteFrom.toString(), fileName);
+ QString toError = QStringLiteral("Could not find quote-before-line='%1' in file '%2'.")
+ .arg(quoteTo.toString(), fileName);
+
+ if (!foundToOk)
+ m_error = toError;
+ if (!foundFromOk)
+ m_error = fromError;
+ if (!foundFromOk && !foundToOk)
+ m_error = fromError + QLatin1Char(' ') + toError;
+ return false;
+ }
+
+ return true;
+}
+
+static bool convertBoolean(QStringView value, const QString &attributeName, bool defaultValue)
+{
+#ifdef QTBUG_69389_FIXED
+ if (value.compare(trueAttributeValue(), Qt::CaseInsensitive) == 0
+ || value.compare(yesAttributeValue(), Qt::CaseInsensitive) == 0) {
+ return true;
+ }
+ if (value.compare(falseAttributeValue(), Qt::CaseInsensitive) == 0
+ || value.compare(noAttributeValue(), Qt::CaseInsensitive) == 0) {
+ return false;
+ }
+#else
+ if (QtPrivate::compareStrings(value, trueAttributeValue(), Qt::CaseInsensitive) == 0
+ || QtPrivate::compareStrings(value, yesAttributeValue(), Qt::CaseInsensitive) == 0) {
+ return true;
+ }
+ if (QtPrivate::compareStrings(value, falseAttributeValue(), Qt::CaseInsensitive) == 0
+ || QtPrivate::compareStrings(value, noAttributeValue(), Qt::CaseInsensitive) == 0) {
+ return false;
+ }
+#endif
+ const QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.")
+ .arg(value)
+ .arg(attributeName,
+ defaultValue ? yesAttributeValue() : noAttributeValue());
+
+ qCWarning(lcShiboken).noquote().nospace() << warn;
+ return defaultValue;
+}
+
+static bool convertRemovalAttribute(QStringView remove, Modification& mod, QString& errorMsg)
+{
+ if (remove.isEmpty())
+ return true;
+#ifdef QTBUG_69389_FIXED
+ if (remove.compare(QStringViewLiteral("all"), Qt::CaseInsensitive) == 0) {
+#else
+ if (QtPrivate::compareStrings(remove, QStringViewLiteral("all"), Qt::CaseInsensitive) == 0) {
+#endif
+ mod.removal = TypeSystem::All;
+ return true;
+ }
+#ifdef QTBUG_69389_FIXED
+ if (remove.compare(QStringViewLiteral("target"), Qt::CaseInsensitive) == 0) {
+#else
+ if (QtPrivate::compareStrings(remove, QStringViewLiteral("target"), Qt::CaseInsensitive) == 0) {
+#endif
+ mod.removal = TypeSystem::TargetLangAndNativeCode;
+ return true;
+ }
+ errorMsg = QString::fromLatin1("Bad removal type '%1'").arg(remove);
+ return false;
+}
+
+static void getNamePrefixRecursive(StackElement* element, QStringList& names)
+{
+ if (!element->parent || !element->parent->entry)
+ return;
+ getNamePrefixRecursive(element->parent, names);
+ names << element->parent->entry->name();
+}
+
+static QString getNamePrefix(StackElement* element)
+{
+ QStringList names;
+ getNamePrefixRecursive(element, names);
+ return names.join(QLatin1Char('.'));
+}
+
+// Returns empty string if there's no error.
+static QString checkSignatureError(const QString& signature, const QString& tag)
+{
+ QString funcName = signature.left(signature.indexOf(QLatin1Char('('))).trimmed();
+ static const QRegularExpression whiteSpace(QStringLiteral("\\s"));
+ Q_ASSERT(whiteSpace.isValid());
+ if (!funcName.startsWith(QLatin1String("operator ")) && funcName.contains(whiteSpace)) {
+ return QString::fromLatin1("Error in <%1> tag signature attribute '%2'.\n"
+ "White spaces aren't allowed in function names, "
+ "and return types should not be part of the signature.")
+ .arg(tag, signature);
+ }
+ return QString();
+}
+
+void TypeSystemParser::applyCommonAttributes(TypeEntry *type, QXmlStreamAttributes *attributes) const
+{
+ type->setCodeGeneration(m_generate);
+ const int revisionIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("revision"));
+ if (revisionIndex != -1)
+ type->setRevision(attributes->takeAt(revisionIndex).value().toInt());
+}
+
+FlagsTypeEntry *
+ TypeSystemParser::parseFlagsEntry(const QXmlStreamReader &,
+ EnumTypeEntry *enumEntry,
+ const QString &name, QString flagName,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+
+{
+ FlagsTypeEntry *ftype = new FlagsTypeEntry(QLatin1String("QFlags<") + name + QLatin1Char('>'), since);
+ ftype->setOriginator(enumEntry);
+ ftype->setTargetLangPackage(enumEntry->targetLangPackage());
+ // Try to get the guess the qualified flag name
+ const int lastSepPos = name.lastIndexOf(colonColon());
+ if (lastSepPos >= 0 && !flagName.contains(colonColon()))
+ flagName.prepend(name.left(lastSepPos + 2));
+
+ ftype->setOriginalName(flagName);
+ applyCommonAttributes(ftype, attributes);
+ QString n = ftype->originalName();
+
+ QStringList lst = n.split(colonColon());
+ const QString &targetLangQualifier = enumEntry->targetLangQualifier();
+ if (QStringList(lst.mid(0, lst.size() - 1)).join(colonColon()) != targetLangQualifier) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("enum %1 and flags %2 differ in qualifiers")
+ .arg(targetLangQualifier, lst.constFirst());
+ }
+
+ ftype->setFlagsName(lst.constLast());
+ enumEntry->setFlags(ftype);
+
+ m_database->addFlagsType(ftype);
+ m_database->addType(ftype);
+
+ const int revisionIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("flags-revision"));
+ ftype->setRevision(revisionIndex != -1
+ ? attributes->takeAt(revisionIndex).value().toInt()
+ : enumEntry->revision());
+ return ftype;
+}
+
+SmartPointerTypeEntry *
+ TypeSystemParser::parseSmartPointerEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ QString smartPointerType;
+ QString getter;
+ QString refCountMethodName;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("type")) {
+ smartPointerType = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("getter")) {
+ getter = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("ref-count-method")) {
+ refCountMethodName = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (smartPointerType.isEmpty()) {
+ m_error = QLatin1String("No type specified for the smart pointer. Currently supported types: 'shared',");
+ return nullptr;
+ }
+ if (smartPointerType != QLatin1String("shared")) {
+ m_error = QLatin1String("Currently only the 'shared' type is supported.");
+ return nullptr;
+ }
+
+ if (getter.isEmpty()) {
+ m_error = QLatin1String("No function getter name specified for getting the raw pointer held by the smart pointer.");
+ return nullptr;
+ }
+
+ QString signature = getter + QLatin1String("()");
+ signature = TypeDatabase::normalizedSignature(signature);
+ if (signature.isEmpty()) {
+ m_error = QLatin1String("No signature for the smart pointer getter found.");
+ return nullptr;
+ }
+
+ QString errorString = checkSignatureError(signature,
+ QLatin1String("smart-pointer-type"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return nullptr;
+ }
+
+ auto *type = new SmartPointerTypeEntry(name, getter, smartPointerType, refCountMethodName, since);
+ applyCommonAttributes(type, attributes);
+ return type;
+}
+
+PrimitiveTypeEntry *
+ TypeSystemParser::parsePrimitiveTypeEntry(const QXmlStreamReader &reader,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ auto *type = new PrimitiveTypeEntry(name, since);
+ applyCommonAttributes(type, attributes);
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("target-lang-name")) {
+ type->setTargetLangName(attributes->takeAt(i).value().toString());
+ } else if (name == QLatin1String("target-lang-api-name")) {
+ type->setTargetLangApiName(attributes->takeAt(i).value().toString());
+ } else if (name == preferredConversionAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == preferredTargetLangTypeAttribute()) {
+ const bool v = convertBoolean(attributes->takeAt(i).value(),
+ preferredTargetLangTypeAttribute(), true);
+ type->setPreferredTargetLangType(v);
+ } else if (name == QLatin1String("default-constructor")) {
+ type->setDefaultConstructor(attributes->takeAt(i).value().toString());
+ }
+ }
+
+ if (type->targetLangName().isEmpty())
+ type->setTargetLangName(type->name());
+ if (type->targetLangApiName().isEmpty())
+ type->setTargetLangApiName(type->name());
+ type->setTargetLangPackage(m_defaultPackage);
+ return type;
+}
+
+ContainerTypeEntry *
+ TypeSystemParser::parseContainerTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ const int typeIndex = indexOfAttribute(*attributes, QStringViewLiteral("type"));
+ if (typeIndex == -1) {
+ m_error = QLatin1String("no 'type' attribute specified");
+ return nullptr;
+ }
+ const QStringRef typeName = attributes->takeAt(typeIndex).value();
+ ContainerTypeEntry::Type containerType = containerTypeFromAttribute(typeName);
+ if (containerType == ContainerTypeEntry::NoContainer) {
+ m_error = QLatin1String("there is no container of type ") + typeName.toString();
+ return nullptr;
+ }
+ auto *type = new ContainerTypeEntry(name, containerType, since);
+ applyCommonAttributes(type, attributes);
+ return type;
+}
+
+EnumTypeEntry *
+ TypeSystemParser::parseEnumTypeEntry(const QXmlStreamReader &reader,
+ const QString &fullName, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ QString scope;
+ QString name = fullName;
+ const int sep = fullName.lastIndexOf(colonColon());
+ if (sep != -1) {
+ scope = fullName.left(sep);
+ name = fullName.right(fullName.size() - sep - 2);
+ }
+ auto *entry = new EnumTypeEntry(scope, name, since);
+ applyCommonAttributes(entry, attributes);
+ entry->setTargetLangPackage(m_defaultPackage);
+
+ QString flagNames;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("upper-bound")) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == QLatin1String("lower-bound")) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == forceIntegerAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == extensibleAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == flagsAttribute()) {
+ flagNames = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ // put in the flags parallel...
+ if (!flagNames.isEmpty()) {
+ const QStringList &flagNameList = flagNames.split(QLatin1Char(','));
+ for (const QString &flagName : flagNameList)
+ parseFlagsEntry(reader, entry, fullName, flagName.trimmed(), since, attributes);
+ }
+ return entry;
+}
+
+ObjectTypeEntry *
+ TypeSystemParser::parseInterfaceTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ auto *otype = new ObjectTypeEntry(name, since);
+ applyCommonAttributes(otype, attributes);
+ QString targetLangName = name;
+ bool generate = true;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("target-lang-name")) {
+ targetLangName = attributes->takeAt(i).value().toString();
+ } else if (name == generateAttribute()) {
+ generate = convertBoolean(attributes->takeAt(i).value(),
+ generateAttribute(), true);
+ }
+ }
+
+ InterfaceTypeEntry *itype =
+ new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(targetLangName), since);
+
+ if (generate)
+ itype->setCodeGeneration(m_generate);
+ else
+ itype->setCodeGeneration(TypeEntry::GenerateForSubclass);
+
+ otype->setDesignatedInterface(itype);
+ itype->setOrigin(otype);
+ return otype;
+}
+
+NamespaceTypeEntry *
+ TypeSystemParser::parseNamespaceTypeEntry(const QXmlStreamReader &reader,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ QScopedPointer<NamespaceTypeEntry> result(new NamespaceTypeEntry(name, since));
+ applyCommonAttributes(result.data(), attributes);
+ applyComplexTypeAttributes(reader, result.data(), attributes);
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef attributeName = attributes->at(i).qualifiedName();
+ if (attributeName == QLatin1String("files")) {
+ const QString pattern = attributes->takeAt(i).value().toString();
+ QRegularExpression re(pattern);
+ if (!re.isValid()) {
+ m_error = msgInvalidRegularExpression(pattern, re.errorString());
+ return nullptr;
+ }
+ result->setFilePattern(re);
+ } else if (attributeName == QLatin1String("extends")) {
+ const auto extendsPackageName = attributes->takeAt(i).value();
+ auto allEntries = TypeDatabase::instance()->findNamespaceTypes(name);
+ auto extendsIt = std::find_if(allEntries.cbegin(), allEntries.cend(),
+ [extendsPackageName] (const NamespaceTypeEntry *e) {
+ return e->targetLangPackage() == extendsPackageName;
+ });
+ if (extendsIt == allEntries.cend()) {
+ m_error = msgCannotFindNamespaceToExtend(name, extendsPackageName);
+ return nullptr;
+ }
+ result->setExtends(*extendsIt);
+ }
+ }
+
+ if (result->extends() && !result->hasPattern()) {
+ m_error = msgExtendingNamespaceRequiresPattern(name);
+ return nullptr;
+ }
+
+ return result.take();
+}
+
+ValueTypeEntry *
+ TypeSystemParser::parseValueTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ auto *typeEntry = new ValueTypeEntry(name, since);
+ applyCommonAttributes(typeEntry, attributes);
+ const int defaultCtIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("default-constructor"));
+ if (defaultCtIndex != -1)
+ typeEntry->setDefaultConstructor(attributes->takeAt(defaultCtIndex).value().toString());
+ return typeEntry;
+}
+
+FunctionTypeEntry *
+ TypeSystemParser::parseFunctionTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ const int signatureIndex = indexOfAttribute(*attributes, signatureAttribute());
+ if (signatureIndex == -1) {
+ m_error = msgMissingAttribute(signatureAttribute());
+ return nullptr;
+ }
+ const QString signature =
+ TypeDatabase::normalizedSignature(attributes->takeAt(signatureIndex).value().toString());
+
+ TypeEntry *existingType = m_database->findType(name);
+
+ if (!existingType) {
+ auto *result = new FunctionTypeEntry(name, signature, since);
+ applyCommonAttributes(result, attributes);
+ return result;
+ }
+
+ if (existingType->type() != TypeEntry::FunctionType) {
+ m_error = QStringLiteral("%1 expected to be a function, but isn't! Maybe it was already declared as a class or something else.")
+ .arg(name);
+ return nullptr;
+ }
+
+ auto *result = reinterpret_cast<FunctionTypeEntry *>(existingType);
+ result->addSignature(signature);
+ return result;
+}
+
+TypedefEntry *
+ TypeSystemParser::parseTypedefEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (m_current && m_current->type != StackElement::Root
+ && m_current->type != StackElement::NamespaceTypeEntry) {
+ m_error = QLatin1String("typedef entries must be nested in namespaces or type system.");
+ return nullptr;
+ }
+ const int sourceIndex = indexOfAttribute(*attributes, sourceAttribute());
+ if (sourceIndex == -1) {
+ m_error = msgMissingAttribute(sourceAttribute());
+ return nullptr;
+ }
+ const QString sourceType = attributes->takeAt(sourceIndex).value().toString();
+ auto result = new TypedefEntry(name, sourceType, since);
+ applyCommonAttributes(result, attributes);
+ return result;
+}
+
+void TypeSystemParser::applyComplexTypeAttributes(const QXmlStreamReader &reader,
+ ComplexTypeEntry *ctype,
+ QXmlStreamAttributes *attributes) const
+{
+ bool generate = true;
+ ctype->setCopyable(ComplexTypeEntry::Unknown);
+ auto exceptionHandling = m_exceptionHandling;
+ auto allowThread = m_allowThread;
+
+ QString package = m_defaultPackage;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == streamAttribute()) {
+ ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute(), false));
+ } else if (name == generateAttribute()) {
+ generate = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true);
+ } else if (name ==packageAttribute()) {
+ package = attributes->takeAt(i).value().toString();
+ } else if (name == defaultSuperclassAttribute()) {
+ ctype->setDefaultSuperclass(attributes->takeAt(i).value().toString());
+ } else if (name == genericClassAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ const bool v = convertBoolean(attributes->takeAt(i).value(), genericClassAttribute(), false);
+ ctype->setGenericClass(v);
+ } else if (name == QLatin1String("target-lang-name")) {
+ ctype->setTargetLangName(attributes->takeAt(i).value().toString());
+ } else if (name == QLatin1String("polymorphic-base")) {
+ ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString());
+ } else if (name == QLatin1String("polymorphic-id-expression")) {
+ ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString());
+ } else if (name == copyableAttribute()) {
+ const bool v = convertBoolean(attributes->takeAt(i).value(), copyableAttribute(), false);
+ ctype->setCopyable(v ? ComplexTypeEntry::CopyableSet : ComplexTypeEntry::NonCopyableSet);
+ } else if (name == exceptionHandlingAttribute()) {
+ const auto attribute = attributes->takeAt(i);
+ const auto v = exceptionHandlingFromAttribute(attribute.value());
+ if (v != TypeSystem::ExceptionHandling::Unspecified) {
+ exceptionHandling = v;
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == allowThreadAttribute()) {
+ const auto attribute = attributes->takeAt(i);
+ const auto v = allowThreadFromAttribute(attribute.value());
+ if (v != TypeSystem::AllowThread::Unspecified) {
+ allowThread = v;
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == QLatin1String("held-type")) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == QLatin1String("hash-function")) {
+ ctype->setHashFunction(attributes->takeAt(i).value().toString());
+ } else if (name == forceAbstractAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == deprecatedAttribute()) {
+ if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute(), false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
+ } else if (name == deleteInMainThreadAttribute()) {
+ if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute(), false))
+ ctype->setDeleteInMainThread(true);
+ } else if (name == QLatin1String("target-type")) {
+ ctype->setTargetType(attributes->takeAt(i).value().toString());
+ }
+ }
+
+ if (exceptionHandling != TypeSystem::ExceptionHandling::Unspecified)
+ ctype->setExceptionHandling(exceptionHandling);
+ if (allowThread != TypeSystem::AllowThread::Unspecified)
+ ctype->setAllowThread(allowThread);
+
+ // The generator code relies on container's package being empty.
+ if (ctype->type() != TypeEntry::ContainerType)
+ ctype->setTargetLangPackage(package);
+
+ if (InterfaceTypeEntry *di = ctype->designatedInterface())
+ di->setTargetLangPackage(package);
+
+ if (generate)
+ ctype->setCodeGeneration(m_generate);
+ else
+ ctype->setCodeGeneration(TypeEntry::GenerateForSubclass);
+}
+
+bool TypeSystemParser::parseRenameFunction(const QXmlStreamReader &,
+ QString *name, QXmlStreamAttributes *attributes)
+{
+ QString signature;
+ QString rename;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == signatureAttribute()) {
+ // Do not remove as it is needed for the type entry later on
+ signature = attributes->at(i).value().toString();
+ } else if (name == renameAttribute()) {
+ rename = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (signature.isEmpty()) {
+ m_error = msgMissingAttribute(signatureAttribute());
+ return false;
+ }
+
+ *name = signature.left(signature.indexOf(QLatin1Char('('))).trimmed();
+
+ QString errorString = checkSignatureError(signature, QLatin1String("function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ if (!rename.isEmpty()) {
+ static const QRegularExpression functionNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$"));
+ Q_ASSERT(functionNameRegExp.isValid());
+ if (!functionNameRegExp.match(rename).hasMatch()) {
+ m_error = QLatin1String("can not rename '") + signature + QLatin1String("', '")
+ + rename + QLatin1String("' is not a valid function name");
+ return false;
+ }
+ FunctionModification mod;
+ if (!mod.setSignature(signature, &m_error))
+ return false;
+ mod.renamedToName = rename;
+ mod.modifiers |= Modification::Rename;
+ m_contextStack.top()->functionMods << mod;
+ }
+ return true;
+}
+
+bool TypeSystemParser::parseInjectDocumentation(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ const int validParent = StackElement::TypeEntryMask
+ | StackElement::ModifyFunction
+ | StackElement::ModifyField;
+ if (!m_current->parent || (m_current->parent->type & validParent) == 0) {
+ m_error = QLatin1String("inject-documentation must be inside modify-function, "
+ "modify-field or other tags that creates a type");
+ return false;
+ }
+
+ TypeSystem::DocModificationMode mode = TypeSystem::DocModificationReplace;
+ TypeSystem::Language lang = TypeSystem::NativeCode;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("mode")) {
+ const QStringRef modeName = attributes->takeAt(i).value();
+ mode = docModificationFromAttribute(modeName);
+ if (mode == TypeSystem::DocModificationInvalid) {
+ m_error = QLatin1String("Unknown documentation injection mode: ") + modeName;
+ return false;
+ }
+ } else if (name == formatAttribute()) {
+ const QStringRef format = attributes->takeAt(i).value();
+ lang = languageFromAttribute(format);
+ if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(format);
+ return false;
+ }
+ }
+ }
+
+ QString signature = m_current->type & StackElement::TypeEntryMask
+ ? QString() : m_currentSignature;
+ DocModification mod(mode, signature);
+ mod.setFormat(lang);
+ m_contextStack.top()->docModifications << mod;
+ return true;
+}
+
+bool TypeSystemParser::parseModifyDocumentation(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ const int validParent = StackElement::TypeEntryMask
+ | StackElement::ModifyFunction
+ | StackElement::ModifyField;
+ if (!m_current->parent || (m_current->parent->type & validParent) == 0) {
+ m_error = QLatin1String("modify-documentation must be inside modify-function, "
+ "modify-field or other tags that creates a type");
+ return false;
+ }
+
+ const int xpathIndex = indexOfAttribute(*attributes, xPathAttribute());
+ if (xpathIndex == -1) {
+ m_error = msgMissingAttribute(xPathAttribute());
+ return false;
+ }
+
+ const QString xpath = attributes->takeAt(xpathIndex).value().toString();
+ QString signature = (m_current->type & StackElement::TypeEntryMask) ? QString() : m_currentSignature;
+ m_contextStack.top()->docModifications
+ << DocModification(xpath, signature);
+ return true;
+}
+
+// m_exceptionHandling
+TypeSystemTypeEntry *TypeSystemParser::parseRootElement(const QXmlStreamReader &,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == packageAttribute()) {
+ m_defaultPackage = attributes->takeAt(i).value().toString();
+ } else if (name == defaultSuperclassAttribute()) {
+ m_defaultSuperclass = attributes->takeAt(i).value().toString();
+ } else if (name == exceptionHandlingAttribute()) {
+ const auto attribute = attributes->takeAt(i);
+ const auto v = exceptionHandlingFromAttribute(attribute.value());
+ if (v != TypeSystem::ExceptionHandling::Unspecified) {
+ m_exceptionHandling = v;
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == allowThreadAttribute()) {
+ const auto attribute = attributes->takeAt(i);
+ const auto v = allowThreadFromAttribute(attribute.value());
+ if (v != TypeSystem::AllowThread::Unspecified) {
+ m_allowThread = v;
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ }
+ }
+
+ auto *moduleEntry =
+ const_cast<TypeSystemTypeEntry *>(m_database->findTypeSystemType(m_defaultPackage));
+ const bool add = moduleEntry == nullptr;
+ if (add)
+ moduleEntry = new TypeSystemTypeEntry(m_defaultPackage, since);
+ moduleEntry->setCodeGeneration(m_generate);
+
+ if ((m_generate == TypeEntry::GenerateForSubclass ||
+ m_generate == TypeEntry::GenerateNothing) && !m_defaultPackage.isEmpty())
+ TypeDatabase::instance()->addRequiredTargetImport(m_defaultPackage);
+
+ if (add)
+ m_database->addTypeSystemType(moduleEntry);
+ return moduleEntry;
+}
+
+bool TypeSystemParser::loadTypesystem(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ QString typeSystemName;
+ bool generateChild = true;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute())
+ typeSystemName = attributes->takeAt(i).value().toString();
+ else if (name == generateAttribute())
+ generateChild = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true);
+ }
+ if (typeSystemName.isEmpty()) {
+ m_error = QLatin1String("No typesystem name specified");
+ return false;
+ }
+ const bool result =
+ m_database->parseFile(typeSystemName, m_currentPath, generateChild
+ && m_generate == TypeEntry::GenerateAll);
+ if (!result)
+ m_error = QStringLiteral("Failed to parse: '%1'").arg(typeSystemName);
+ return result;
+}
+
+bool TypeSystemParser::parseRejectEnumValue(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ if (!m_currentEnum) {
+ m_error = QLatin1String("<reject-enum-value> node must be used inside a <enum-type> node");
+ return false;
+ }
+ const int nameIndex = indexOfAttribute(*attributes, nameAttribute());
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute());
+ return false;
+ }
+ m_currentEnum->addEnumValueRejection(attributes->takeAt(nameIndex).value().toString());
+ return true;
+}
+
+bool TypeSystemParser::parseReplaceArgumentType(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("Type replacement can only be specified for argument modifications");
+ return false;
+ }
+ const int modifiedTypeIndex = indexOfAttribute(*attributes, modifiedTypeAttribute());
+ if (modifiedTypeIndex == -1) {
+ m_error = QLatin1String("Type replacement requires 'modified-type' attribute");
+ return false;
+ }
+ m_contextStack.top()->functionMods.last().argument_mods.last().modified_type =
+ attributes->takeAt(modifiedTypeIndex).value().toString();
+ return true;
+}
+
+bool TypeSystemParser::parseCustomConversion(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument
+ && topElement.type != StackElement::ValueTypeEntry
+ && topElement.type != StackElement::PrimitiveTypeEntry
+ && topElement.type != StackElement::ContainerTypeEntry) {
+ m_error = QLatin1String("Conversion rules can only be specified for argument modification, "
+ "value-type, primitive-type or container-type conversion.");
+ return false;
+ }
+
+ QString sourceFile;
+ QString snippetLabel;
+ TypeSystem::Language lang = TypeSystem::NativeCode;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == classAttribute()) {
+ const QStringRef languageAttribute = attributes->takeAt(i).value();
+ lang = languageFromAttribute(languageAttribute);
+ if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(languageAttribute);
+ return false;
+ }
+ } else if (name == QLatin1String("file")) {
+ sourceFile = attributes->takeAt(i).value().toString();
+ } else if (name == snippetAttribute()) {
+ snippetLabel = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (topElement.type == StackElement::ModifyArgument) {
+ CodeSnip snip;
+ snip.language = lang;
+ m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.append(snip);
+ return true;
+ }
+
+ if (topElement.entry->hasConversionRule() || topElement.entry->hasCustomConversion()) {
+ m_error = QLatin1String("Types can have only one conversion rule");
+ return false;
+ }
+
+ // The old conversion rule tag that uses a file containing the conversion
+ // will be kept temporarily for compatibility reasons.
+ if (!sourceFile.isEmpty()) {
+ if (m_generate != TypeEntry::GenerateForSubclass
+ && m_generate != TypeEntry::GenerateNothing) {
+
+ const char* conversionFlag = NATIVE_CONVERSION_RULE_FLAG;
+ if (lang == TypeSystem::TargetLangCode)
+ conversionFlag = TARGET_CONVERSION_RULE_FLAG;
+
+ QFile conversionSource(sourceFile);
+ if (conversionSource.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ const QString conversionRule =
+ extractSnippet(QString::fromUtf8(conversionSource.readAll()), snippetLabel);
+ topElement.entry->setConversionRule(QLatin1String(conversionFlag) + conversionRule);
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "File containing conversion code for "
+ << topElement.entry->name() << " type does not exist or is not readable: "
+ << sourceFile;
+ }
+ }
+ }
+
+ auto *customConversion = new CustomConversion(m_current->entry);
+ customConversionsForReview.append(customConversion);
+ return true;
+}
+
+bool TypeSystemParser::parseNativeToTarget(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ConversionRule) {
+ m_error = QLatin1String("Native to Target conversion code can only be specified for custom conversion rules.");
+ return false;
+ }
+ CodeSnip snip;
+ if (!readFileSnippet(attributes, &snip))
+ return false;
+ m_contextStack.top()->codeSnips.append(snip);
+ return true;
+}
+
+bool TypeSystemParser::parseAddConversion(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::TargetToNative) {
+ m_error = QLatin1String("Target to Native conversions can only be added inside 'target-to-native' tags.");
+ return false;
+ }
+ QString sourceTypeName;
+ QString typeCheck;
+ CodeSnip snip;
+ if (!readFileSnippet(attributes, &snip))
+ return false;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("type"))
+ sourceTypeName = attributes->takeAt(i).value().toString();
+ else if (name == QLatin1String("check"))
+ typeCheck = attributes->takeAt(i).value().toString();
+ }
+ if (sourceTypeName.isEmpty()) {
+ m_error = QLatin1String("Target to Native conversions must specify the input type with the 'type' attribute.");
+ return false;
+ }
+ m_current->entry->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck);
+ m_contextStack.top()->codeSnips.append(snip);
+ return true;
+}
+
+static bool parseIndex(const QString &index, int *result, QString *errorMessage)
+{
+ bool ok = false;
+ *result = index.toInt(&ok);
+ if (!ok)
+ *errorMessage = QStringLiteral("Cannot convert '%1' to integer").arg(index);
+ return ok;
+}
+
+static bool parseArgumentIndex(const QString &index, int *result, QString *errorMessage)
+{
+ if (index == QLatin1String("return")) {
+ *result = 0;
+ return true;
+ }
+ if (index == QLatin1String("this")) {
+ *result = -1;
+ return true;
+ }
+ return parseIndex(index, result, errorMessage);
+}
+
+bool TypeSystemParser::parseModifyArgument(const QXmlStreamReader &,
+ const StackElement &topElement, QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyFunction
+ && topElement.type != StackElement::AddFunction) {
+ m_error = QString::fromLatin1("argument modification requires function"
+ " modification as parent, was %1")
+ .arg(topElement.type, 0, 16);
+ return false;
+ }
+
+ QString index;
+ QString replaceValue;
+ bool resetAfterUse = false;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == indexAttribute()) {
+ index = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("replace-value")) {
+ replaceValue = attributes->takeAt(i).value().toString();
+ } else if (name == invalidateAfterUseAttribute()) {
+ resetAfterUse = convertBoolean(attributes->takeAt(i).value(),
+ invalidateAfterUseAttribute(), false);
+ }
+ }
+
+ if (index.isEmpty()) {
+ m_error = msgMissingAttribute(indexAttribute());
+ return false;
+ }
+
+ int idx;
+ if (!parseArgumentIndex(index, &idx, &m_error))
+ return false;
+
+ if (!replaceValue.isEmpty() && idx) {
+ m_error = QLatin1String("replace-value is only supported for return values (index=0).");
+ return false;
+ }
+
+ ArgumentModification argumentModification = ArgumentModification(idx);
+ argumentModification.replace_value = replaceValue;
+ argumentModification.resetAfterUse = resetAfterUse;
+ m_contextStack.top()->functionMods.last().argument_mods.append(argumentModification);
+ return true;
+}
+
+bool TypeSystemParser::parseNoNullPointer(const QXmlStreamReader &reader,
+ const StackElement &topElement, QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("no-null-pointer requires argument modification as parent");
+ return false;
+ }
+
+ ArgumentModification &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods.last();
+ lastArgMod.noNullPointers = true;
+
+ const int defaultValueIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("default-value"));
+ if (defaultValueIndex != -1) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(defaultValueIndex);
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, attribute)));
+ }
+ return true;
+}
+
+bool TypeSystemParser::parseDefineOwnership(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("define-ownership requires argument modification as parent");
+ return false;
+ }
+
+ TypeSystem::Language lang = TypeSystem::TargetLangCode;
+ QString ownership;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == classAttribute()) {
+ const QStringRef className = attributes->takeAt(i).value();
+ lang = languageFromAttribute(className);
+ if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(className);
+ return false;
+ }
+ } else if (name == ownershipAttribute()) {
+ ownership = attributes->takeAt(i).value().toString();
+ }
+ }
+ const TypeSystem::Ownership owner = ownershipFromFromAttribute(ownership);
+ if (owner == TypeSystem::InvalidOwnership) {
+ m_error = QStringLiteral("unsupported owner attribute: '%1'").arg(ownership);
+ return false;
+ }
+ m_contextStack.top()->functionMods.last().argument_mods.last().ownerships[lang] = owner;
+ return true;
+}
+
+bool TypeSystemParser::parseArgumentMap(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::CodeSnipMask)) {
+ m_error = QLatin1String("Argument maps requires code injection as parent");
+ return false;
+ }
+
+ int pos = 1;
+ QString metaName;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == indexAttribute()) {
+ if (!parseIndex(attributes->takeAt(i).value().toString(), &pos, &m_error))
+ return false;
+ if (pos <= 0) {
+ m_error = QStringLiteral("Argument position %1 must be a positive number").arg(pos);
+ return false;
+ }
+ } else if (name == QLatin1String("meta-name")) {
+ metaName = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (metaName.isEmpty())
+ qCWarning(lcShiboken) << "Empty meta name in argument map";
+
+ if (topElement.type == StackElement::InjectCodeInFunction) {
+ m_contextStack.top()->functionMods.last().snips.last().argumentMap[pos] = metaName;
+ } else {
+ qCWarning(lcShiboken) << "Argument maps are only useful for injection of code "
+ "into functions.";
+ }
+ return true;
+}
+
+bool TypeSystemParser::parseRemoval(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyFunction) {
+ m_error = QLatin1String("Function modification parent required");
+ return false;
+ }
+
+ TypeSystem::Language lang = TypeSystem::All;
+ const int classIndex = indexOfAttribute(*attributes, classAttribute());
+ if (classIndex != -1) {
+ const QStringRef value = attributes->takeAt(classIndex).value();
+ lang = languageFromAttribute(value);
+ if (lang == TypeSystem::TargetLangCode) // "target" means TargetLangAndNativeCode here
+ lang = TypeSystem::TargetLangAndNativeCode;
+ if (lang != TypeSystem::TargetLangAndNativeCode && lang != TypeSystem::All) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(value);
+ return false;
+ }
+ }
+ m_contextStack.top()->functionMods.last().removal = lang;
+ return true;
+}
+
+bool TypeSystemParser::parseRename(const QXmlStreamReader &reader,
+ StackElement::ElementType type,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyField
+ && topElement.type != StackElement::ModifyFunction
+ && topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("Function, field or argument modification parent required");
+ return false;
+ }
+
+ Modification *mod = nullptr;
+ if (topElement.type == StackElement::ModifyFunction)
+ mod = &m_contextStack.top()->functionMods.last();
+ else if (topElement.type == StackElement::ModifyField)
+ mod = &m_contextStack.top()->fieldMods.last();
+
+ Modification::Modifiers modifierFlag = Modification::Rename;
+ if (type == StackElement::Rename) {
+ const int toIndex = indexOfAttribute(*attributes, toAttribute());
+ if (toIndex == -1) {
+ m_error = msgMissingAttribute(toAttribute());
+ return false;
+ }
+ const QString renamed_to = attributes->takeAt(toIndex).value().toString();
+ if (topElement.type == StackElement::ModifyFunction)
+ mod->setRenamedTo(renamed_to);
+ else if (topElement.type == StackElement::ModifyField)
+ mod->setRenamedTo(renamed_to);
+ else
+ m_contextStack.top()->functionMods.last().argument_mods.last().renamed_to = renamed_to;
+ } else {
+ const int modifierIndex = indexOfAttribute(*attributes, modifierAttribute());
+ if (modifierIndex == -1) {
+ m_error = msgMissingAttribute(modifierAttribute());
+ return false;
+ }
+ const QStringRef modifier = attributes->takeAt(modifierIndex).value();
+ modifierFlag = modifierFromAttribute(modifier);
+ if (modifierFlag == Modification::InvalidModifier) {
+ m_error = QStringLiteral("Unknown access modifier: '%1'").arg(modifier);
+ return false;
+ }
+ if (modifierFlag == Modification::Friendly) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeValueWarning(reader, modifierAttribute(), modifier)));
+ }
+ }
+
+ if (mod)
+ mod->modifiers |= modifierFlag;
+ return true;
+}
+
+bool TypeSystemParser::parseModifyField(const QXmlStreamReader &reader,
+ QXmlStreamAttributes *attributes)
+{
+ FieldModification fm;
+ fm.modifiers = FieldModification::Readable | FieldModification::Writable;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute()) {
+ fm.name = attributes->takeAt(i).value().toString();
+ } else if (name == removeAttribute()) {
+ if (!convertRemovalAttribute(attributes->takeAt(i).value(), fm, m_error))
+ return false;
+ } else if (name == readAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ if (!convertBoolean(attributes->takeAt(i).value(), readAttribute(), true))
+ fm.modifiers &= ~FieldModification::Readable;
+ } else if (name == writeAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ if (!convertBoolean(attributes->takeAt(i).value(), writeAttribute(), true))
+ fm.modifiers &= ~FieldModification::Writable;
+ }
+ }
+ if (fm.name.isEmpty()) {
+ m_error = msgMissingAttribute(nameAttribute());
+ return false;
+ }
+ m_contextStack.top()->fieldMods << fm;
+ return true;
+}
+
+bool TypeSystemParser::parseAddFunction(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & (StackElement::ComplexTypeEntryMask | StackElement::Root))) {
+ m_error = QString::fromLatin1("Add function requires a complex type or a root tag as parent"
+ ", was=%1").arg(topElement.type, 0, 16);
+ return false;
+ }
+ QString originalSignature;
+ QString returnType = QLatin1String("void");
+ bool staticFunction = false;
+ QString access;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("signature")) {
+ originalSignature = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("return-type")) {
+ returnType = attributes->takeAt(i).value().toString();
+ } else if (name == staticAttribute()) {
+ staticFunction = convertBoolean(attributes->takeAt(i).value(),
+ staticAttribute(), false);
+ } else if (name == accessAttribute()) {
+ access = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ QString signature = TypeDatabase::normalizedSignature(originalSignature);
+ if (signature.isEmpty()) {
+ m_error = QLatin1String("No signature for the added function");
+ return false;
+ }
+
+ QString errorString = checkSignatureError(signature, QLatin1String("add-function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ AddedFunctionPtr func(new AddedFunction(signature, returnType));
+ func->setStatic(staticFunction);
+ if (!signature.contains(QLatin1Char('(')))
+ signature += QLatin1String("()");
+ m_currentSignature = signature;
+
+ if (!access.isEmpty()) {
+ const AddedFunction::Access a = addedFunctionAccessFromAttribute(access);
+ if (a == AddedFunction::InvalidAccess) {
+ m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
+ return false;
+ }
+ func->setAccess(a);
+ }
+
+ m_contextStack.top()->addedFunctions << func;
+ m_contextStack.top()->addedFunctionModificationIndex =
+ m_contextStack.top()->functionMods.size();
+
+ FunctionModification mod;
+ if (!mod.setSignature(m_currentSignature, &m_error))
+ return false;
+ mod.setOriginalSignature(originalSignature);
+ m_contextStack.top()->functionMods << mod;
+ return true;
+}
+
+bool TypeSystemParser::parseModifyFunction(const QXmlStreamReader &reader,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
+ m_error = QString::fromLatin1("Modify function requires complex type as parent"
+ ", was=%1").arg(topElement.type, 0, 16);
+ return false;
+ }
+
+ QString originalSignature;
+ QString access;
+ QString removal;
+ QString rename;
+ QString association;
+ bool deprecated = false;
+ bool isThread = false;
+ TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
+ TypeSystem::AllowThread allowThread = TypeSystem::AllowThread::Unspecified;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("signature")) {
+ originalSignature = attributes->takeAt(i).value().toString();
+ } else if (name == accessAttribute()) {
+ access = attributes->takeAt(i).value().toString();
+ } else if (name == renameAttribute()) {
+ rename = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("associated-to")) {
+ association = attributes->takeAt(i).value().toString();
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == removeAttribute()) {
+ removal = attributes->takeAt(i).value().toString();
+ } else if (name == deprecatedAttribute()) {
+ deprecated = convertBoolean(attributes->takeAt(i).value(),
+ deprecatedAttribute(), false);
+ } else if (name == threadAttribute()) {
+ isThread = convertBoolean(attributes->takeAt(i).value(),
+ threadAttribute(), false);
+ } else if (name == allowThreadAttribute()) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(i);
+ allowThread = allowThreadFromAttribute(attribute.value());
+ if (allowThread == TypeSystem::AllowThread::Unspecified) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ } else if (name == exceptionHandlingAttribute()) {
+ const auto attribute = attributes->takeAt(i);
+ exceptionHandling = exceptionHandlingFromAttribute(attribute.value());
+ if (exceptionHandling == TypeSystem::ExceptionHandling::Unspecified) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == virtualSlotAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ }
+ }
+
+ const QString signature = TypeDatabase::normalizedSignature(originalSignature);
+ if (signature.isEmpty()) {
+ m_error = QLatin1String("No signature for modified function");
+ return false;
+ }
+
+ QString errorString = checkSignatureError(signature, QLatin1String("modify-function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ FunctionModification mod;
+ if (!mod.setSignature(signature, &m_error))
+ return false;
+ mod.setOriginalSignature(originalSignature);
+ mod.setExceptionHandling(exceptionHandling);
+ m_currentSignature = signature;
+
+ if (!access.isEmpty()) {
+ const Modification::Modifiers m = modifierFromAttribute(access);
+ if ((m & (Modification::AccessModifierMask | Modification::FinalMask)) == 0) {
+ m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
+ return false;
+ }
+ if (m == Modification::Final || m == Modification::NonFinal) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeValueWarning(reader,
+ accessAttribute(), access)));
+ }
+ mod.modifiers |= m;
+ }
+
+ if (deprecated)
+ mod.modifiers |= Modification::Deprecated;
+
+ if (!removal.isEmpty() && !convertRemovalAttribute(removal, mod, m_error))
+ return false;
+
+ if (!rename.isEmpty()) {
+ mod.renamedToName = rename;
+ mod.modifiers |= Modification::Rename;
+ }
+
+ if (!association.isEmpty())
+ mod.association = association;
+
+ mod.setIsThread(isThread);
+ if (allowThread != TypeSystem::AllowThread::Unspecified)
+ mod.setAllowThread(allowThread);
+
+ m_contextStack.top()->functionMods << mod;
+ return true;
+}
+
+bool TypeSystemParser::parseReplaceDefaultExpression(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::ModifyArgument)) {
+ m_error = QLatin1String("Replace default expression only allowed as child of argument modification");
+ return false;
+ }
+ const int withIndex = indexOfAttribute(*attributes, QStringViewLiteral("with"));
+ if (withIndex == -1 || attributes->at(withIndex).value().isEmpty()) {
+ m_error = QLatin1String("Default expression replaced with empty string. Use remove-default-expression instead.");
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().replacedDefaultExpression =
+ attributes->takeAt(withIndex).value().toString();
+ return true;
+}
+
+CustomFunction *
+ TypeSystemParser::parseCustomMetaConstructor(const QXmlStreamReader &,
+ StackElement::ElementType type,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ QString functionName = topElement.entry->name().toLower()
+ + (type == StackElement::CustomMetaConstructor
+ ? QLatin1String("_create") : QLatin1String("_delete"));
+ QString paramName = QLatin1String("copy");
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute())
+ functionName = attributes->takeAt(i).value().toString();
+ else if (name == QLatin1String("param-name"))
+ paramName = attributes->takeAt(i).value().toString();
+ }
+ auto *func = new CustomFunction(functionName);
+ func->paramName = paramName;
+ return func;
+}
+
+bool TypeSystemParser::parseReferenceCount(const QXmlStreamReader &reader,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("reference-count must be child of modify-argument");
+ return false;
+ }
+
+ ReferenceCount rc;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == actionAttribute()) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(i);
+ rc.action = referenceCountFromAttribute(attribute.value());
+ switch (rc.action) {
+ case ReferenceCount::Invalid:
+ m_error = QLatin1String("unrecognized value '") + attribute.value()
+ + QLatin1String("' for action attribute.");
+ return false;
+ case ReferenceCount::AddAll:
+ case ReferenceCount::Ignore:
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeValueWarning(reader, attribute)));
+ break;
+ default:
+ break;
+ }
+ } else if (name == QLatin1String("variable-name")) {
+ rc.varName = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().referenceCounts.append(rc);
+ return true;
+}
+
+bool TypeSystemParser::parseParentOwner(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("parent-policy must be child of modify-argument");
+ return false;
+ }
+ ArgumentOwner ao;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == indexAttribute()) {
+ const QString index = attributes->takeAt(i).value().toString();
+ if (!parseArgumentIndex(index, &ao.index, &m_error))
+ return false;
+ } else if (name == actionAttribute()) {
+ const QStringRef action = attributes->takeAt(i).value();
+ ao.action = argumentOwnerActionFromAttribute(action);
+ if (ao.action == ArgumentOwner::Invalid) {
+ m_error = QLatin1String("Invalid parent actionr '") + action + QLatin1String("'.");
+ return false;
+ }
+ }
+ }
+ m_contextStack.top()->functionMods.last().argument_mods.last().owner = ao;
+ return true;
+}
+
+bool TypeSystemParser::readFileSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip)
+{
+ QString fileName;
+ QString snippetLabel;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("file")) {
+ fileName = attributes->takeAt(i).value().toString();
+ } else if (name == snippetAttribute()) {
+ snippetLabel = attributes->takeAt(i).value().toString();
+ }
+ }
+ if (fileName.isEmpty())
+ return true;
+ const QString resolved = m_database->modifiedTypesystemFilepath(fileName, m_currentPath);
+ if (!QFile::exists(resolved)) {
+ m_error = QLatin1String("File for inject code not exist: ")
+ + QDir::toNativeSeparators(fileName);
+ return false;
+ }
+ QFile codeFile(resolved);
+ if (!codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) {
+ m_error = msgCannotOpenForReading(codeFile);
+ return false;
+ }
+ QString source = fileName;
+ if (!snippetLabel.isEmpty())
+ source += QLatin1String(" (") + snippetLabel + QLatin1Char(')');
+ QString content;
+ QTextStream str(&content);
+ str << "// ========================================================================\n"
+ "// START of custom code block [file: "
+ << source << "]\n"
+ << extractSnippet(QString::fromUtf8(codeFile.readAll()), snippetLabel)
+ << "\n// END of custom code block [file: " << source
+ << "]\n// ========================================================================\n";
+ snip->addCode(content);
+ return true;
+}
+
+bool TypeSystemParser::parseInjectCode(const QXmlStreamReader &,
+ const StackElement &topElement,
+ StackElement* element, QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::ComplexTypeEntryMask)
+ && (topElement.type != StackElement::AddFunction)
+ && (topElement.type != StackElement::ModifyFunction)
+ && (topElement.type != StackElement::Root)) {
+ m_error = QLatin1String("wrong parent type for code injection");
+ return false;
+ }
+
+ TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionBeginning;
+ TypeSystem::Language lang = TypeSystem::TargetLangCode;
+ CodeSnip snip;
+ if (!readFileSnippet(attributes, &snip))
+ return false;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == classAttribute()) {
+ const QStringRef className = attributes->takeAt(i).value();
+ lang = languageFromAttribute(className);
+ if (lang == TypeSystem::NoLanguage) {
+ m_error = QStringLiteral("Invalid class specifier: '%1'").arg(className);
+ return false;
+ }
+ } else if (name == positionAttribute()) {
+ const QStringRef value = attributes->takeAt(i).value();
+ position = codeSnipPositionFromAttribute(value);
+ if (position == TypeSystem::CodeSnipPositionInvalid) {
+ m_error = QStringLiteral("Invalid position: '%1'").arg(value);
+ return false;
+ }
+ }
+ }
+
+ snip.position = position;
+ snip.language = lang;
+
+ if (snip.language == TypeSystem::Interface
+ && topElement.type != StackElement::InterfaceTypeEntry) {
+ m_error = QLatin1String("Interface code injections must be direct child of an interface type entry");
+ return false;
+ }
+
+ if (topElement.type == StackElement::ModifyFunction
+ || topElement.type == StackElement::AddFunction) {
+ if (snip.language == TypeSystem::ShellDeclaration) {
+ m_error = QLatin1String("no function implementation in shell declaration in which to inject code");
+ return false;
+ }
+
+ FunctionModification &mod = m_contextStack.top()->functionMods.last();
+ mod.snips << snip;
+ if (!snip.code().isEmpty())
+ mod.modifiers |= FunctionModification::CodeInjection;
+ element->type = StackElement::InjectCodeInFunction;
+ } else if (topElement.type == StackElement::Root) {
+ element->entry->addCodeSnip(snip);
+ } else if (topElement.type != StackElement::Root) {
+ m_contextStack.top()->codeSnips << snip;
+ }
+ return true;
+}
+
+bool TypeSystemParser::parseInclude(const QXmlStreamReader &,
+ const StackElement &topElement,
+ TypeEntry *entry, QXmlStreamAttributes *attributes)
+{
+ QString fileName;
+ QString location;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("file-name"))
+ fileName = attributes->takeAt(i).value().toString();
+ else if (name == locationAttribute())
+ location = attributes->takeAt(i).value().toString();
+ }
+ const Include::IncludeType loc = locationFromAttribute(location);
+ if (loc == Include::InvalidInclude) {
+ m_error = QStringLiteral("Location not recognized: '%1'").arg(location);
+ return false;
+ }
+
+ Include inc(loc, fileName);
+ if (topElement.type
+ & (StackElement::ComplexTypeEntryMask | StackElement::PrimitiveTypeEntry)) {
+ entry->setInclude(inc);
+ } else if (topElement.type == StackElement::ExtraIncludes) {
+ entry->addExtraInclude(inc);
+ } else {
+ m_error = QLatin1String("Only supported parent tags are primitive-type, complex types or extra-includes");
+ return false;
+ }
+ if (InterfaceTypeEntry *di = entry->designatedInterface()) {
+ di->setInclude(entry->include());
+ di->setExtraIncludes(entry->extraIncludes());
+ }
+ return true;
+}
+
+TemplateInstance *
+ TypeSystemParser::parseTemplateInstanceEnum(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::CodeSnipMask) &&
+ (topElement.type != StackElement::Template) &&
+ (topElement.type != StackElement::CustomMetaConstructor) &&
+ (topElement.type != StackElement::CustomMetaDestructor) &&
+ (topElement.type != StackElement::NativeToTarget) &&
+ (topElement.type != StackElement::AddConversion) &&
+ (topElement.type != StackElement::ConversionRule)) {
+ m_error = QLatin1String("Can only insert templates into code snippets, templates, custom-constructors, "\
+ "custom-destructors, conversion-rule, native-to-target or add-conversion tags.");
+ return nullptr;
+ }
+ const int nameIndex = indexOfAttribute(*attributes, nameAttribute());
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute());
+ return nullptr;
+ }
+ return new TemplateInstance(attributes->takeAt(nameIndex).value().toString());
+}
+
+bool TypeSystemParser::parseReplace(const QXmlStreamReader &,
+ const StackElement &topElement,
+ StackElement *element, QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::TemplateInstanceEnum) {
+ m_error = QLatin1String("Can only insert replace rules into insert-template.");
+ return false;
+ }
+ QString from;
+ QString to;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("from"))
+ from = attributes->takeAt(i).value().toString();
+ else if (name == toAttribute())
+ to = attributes->takeAt(i).value().toString();
+ }
+ element->parent->value.templateInstance->addReplaceRule(from, to);
+ return true;
+}
+
+bool TypeSystemParser::startElement(const QXmlStreamReader &reader)
+{
+ if (m_ignoreDepth) {
+ ++m_ignoreDepth;
+ return true;
+ }
+
+ const QStringRef tagName = reader.name();
+ QXmlStreamAttributes attributes = reader.attributes();
+
+ QVersionNumber since(0, 0);
+ int index = indexOfAttribute(attributes, sinceAttribute());
+ if (index != -1) {
+ const QStringRef sinceSpec = attributes.takeAt(index).value();
+ since = QVersionNumber::fromString(sinceSpec.toString());
+ if (since.isNull()) {
+ m_error = msgInvalidVersion(sinceSpec, m_defaultPackage);
+ return false;
+ }
+ }
+
+ if (!m_defaultPackage.isEmpty() && since > QVersionNumber(0, 0)) {
+ TypeDatabase* td = TypeDatabase::instance();
+ if (!td->checkApiVersion(m_defaultPackage, since)) {
+ ++m_ignoreDepth;
+ return true;
+ }
+ }
+
+ if (tagName.compare(QLatin1String("import-file"), Qt::CaseInsensitive) == 0)
+ return importFileElement(attributes);
+
+ const StackElement::ElementType elementType = elementFromTag(tagName);
+ if (elementType == StackElement::None) {
+ m_error = QStringLiteral("Unknown tag name: '%1'").arg(tagName);
+ return false;
+ }
+
+ if (m_currentDroppedEntry) {
+ ++m_currentDroppedEntryDepth;
+ return true;
+ }
+
+ auto *element = new StackElement(m_current);
+ element->type = elementType;
+
+ if (element->type == StackElement::Root && m_generate == TypeEntry::GenerateAll)
+ customConversionsForReview.clear();
+
+ if (element->type == StackElement::CustomMetaConstructor
+ || element->type == StackElement::CustomMetaDestructor) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedElementWarning(reader, tagName)));
+ }
+
+ switch (element->type) {
+ case StackElement::Root:
+ case StackElement::NamespaceTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::PrimitiveTypeEntry:
+ case StackElement::TypedefTypeEntry:
+ m_contextStack.push(new StackElementContext());
+ break;
+ default:
+ break;
+ }
+
+ if (element->type & StackElement::TypeEntryMask) {
+ QString name;
+ if (element->type != StackElement::FunctionTypeEntry) {
+ const int nameIndex = indexOfAttribute(attributes, nameAttribute());
+ if (nameIndex != -1) {
+ name = attributes.takeAt(nameIndex).value().toString();
+ } else if (element->type != StackElement::EnumTypeEntry) { // anonymous enum?
+ m_error = msgMissingAttribute(nameAttribute());
+ return false;
+ }
+ }
+
+ if (m_database->hasDroppedTypeEntries()) {
+ QString identifier = getNamePrefix(element) + QLatin1Char('.');
+ identifier += element->type == StackElement::FunctionTypeEntry
+ ? attributes.value(signatureAttribute()).toString()
+ : name;
+ if (m_database->shouldDropTypeEntry(identifier)) {
+ m_currentDroppedEntry = element;
+ m_currentDroppedEntryDepth = 1;
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug)) {
+ qCDebug(lcShiboken)
+ << QStringLiteral("Type system entry '%1' was intentionally dropped from generation.").arg(identifier);
+ }
+ return true;
+ }
+ }
+
+ // The top level tag 'function' has only the 'signature' tag
+ // and we should extract the 'name' value from it.
+ if (element->type == StackElement::FunctionTypeEntry
+ && !parseRenameFunction(reader, &name, &attributes)) {
+ return false;
+ }
+
+ // We need to be able to have duplicate primitive type entries,
+ // or it's not possible to cover all primitive target language
+ // types (which we need to do in order to support fake meta objects)
+ if (element->type != StackElement::PrimitiveTypeEntry
+ && element->type != StackElement::FunctionTypeEntry) {
+ TypeEntry *tmp = m_database->findType(name);
+ if (tmp && !tmp->isNamespace())
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Duplicate type entry: '%1'").arg(name);
+ }
+
+ if (element->type == StackElement::EnumTypeEntry) {
+ const int enumIdentifiedByIndex = indexOfAttribute(attributes, enumIdentifiedByValueAttribute());
+ const QString identifiedByValue = enumIdentifiedByIndex != -1
+ ? attributes.takeAt(enumIdentifiedByIndex).value().toString() : QString();
+ if (name.isEmpty()) {
+ name = identifiedByValue;
+ } else if (!identifiedByValue.isEmpty()) {
+ m_error = QLatin1String("can't specify both 'name' and 'identified-by-value' attributes");
+ return false;
+ }
+ }
+
+ // Fix type entry name using nesting information.
+ if (element->type & StackElement::TypeEntryMask
+ && element->parent && element->parent->type != StackElement::Root) {
+ name = element->parent->entry->name() + colonColon() + name;
+ }
+
+
+ if (name.isEmpty()) {
+ m_error = QLatin1String("no 'name' attribute specified");
+ return false;
+ }
+
+ switch (element->type) {
+ case StackElement::CustomTypeEntry:
+ element->entry = new TypeEntry(name, TypeEntry::CustomType, since);
+ break;
+ case StackElement::PrimitiveTypeEntry:
+ element->entry = parsePrimitiveTypeEntry(reader, name, since, &attributes);
+ if (Q_UNLIKELY(!element->entry))
+ return false;
+ break;
+ case StackElement::ContainerTypeEntry:
+ if (ContainerTypeEntry *ce = parseContainerTypeEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, ce, &attributes);
+ element->entry = ce;
+ } else {
+ return false;
+ }
+ break;
+
+ case StackElement::SmartPointerTypeEntry:
+ if (SmartPointerTypeEntry *se = parseSmartPointerEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, se, &attributes);
+ element->entry = se;
+ } else {
+ return false;
+ }
+ break;
+ case StackElement::EnumTypeEntry:
+ m_currentEnum = parseEnumTypeEntry(reader, name, since, &attributes);
+ if (Q_UNLIKELY(!m_currentEnum))
+ return false;
+ element->entry = m_currentEnum;
+ break;
+
+ case StackElement::InterfaceTypeEntry:
+ if (ObjectTypeEntry *oe = parseInterfaceTypeEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, oe, &attributes);
+ element->entry = oe;
+ } else {
+ return false;
+ }
+ break;
+ case StackElement::ValueTypeEntry:
+ if (ValueTypeEntry *ve = parseValueTypeEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, ve, &attributes);
+ element->entry = ve;
+ } else {
+ return false;
+ }
+ break;
+ case StackElement::NamespaceTypeEntry:
+ if (auto entry = parseNamespaceTypeEntry(reader, name, since, &attributes))
+ element->entry = entry;
+ else
+ return false;
+ break;
+ case StackElement::ObjectTypeEntry:
+ element->entry = new ObjectTypeEntry(name, since);
+ applyCommonAttributes(element->entry, &attributes);
+ applyComplexTypeAttributes(reader, static_cast<ComplexTypeEntry *>(element->entry), &attributes);
+ break;
+ case StackElement::FunctionTypeEntry:
+ element->entry = parseFunctionTypeEntry(reader, name, since, &attributes);
+ if (Q_UNLIKELY(!element->entry))
+ return false;
+ break;
+ case StackElement::TypedefTypeEntry:
+ if (TypedefEntry *te = parseTypedefEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, te, &attributes);
+ element->entry = te;
+ } else {
+ return false;
+ }
+ break;
+ default:
+ Q_ASSERT(false);
+ };
+
+ if (element->entry) {
+ if (!m_database->addType(element->entry, &m_error))
+ return false;
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Type: %1 was rejected by typesystem").arg(name);
+ }
+
+ } else if (element->type == StackElement::InjectDocumentation) {
+ if (!parseInjectDocumentation(reader, &attributes))
+ return false;
+ } else if (element->type == StackElement::ModifyDocumentation) {
+ if (!parseModifyDocumentation(reader, &attributes))
+ return false;
+ } else if (element->type != StackElement::None) {
+ bool topLevel = element->type == StackElement::Root
+ || element->type == StackElement::SuppressedWarning
+ || element->type == StackElement::Rejection
+ || element->type == StackElement::LoadTypesystem
+ || element->type == StackElement::InjectCode
+ || element->type == StackElement::ExtraIncludes
+ || element->type == StackElement::ConversionRule
+ || element->type == StackElement::AddFunction
+ || element->type == StackElement::Template;
+
+ if (!topLevel && m_current->type == StackElement::Root) {
+ m_error = QStringLiteral("Tag requires parent: '%1'").arg(tagName);
+ return false;
+ }
+
+ StackElement topElement = !m_current ? StackElement(nullptr) : *m_current;
+ element->entry = topElement.entry;
+
+ switch (element->type) {
+ case StackElement::Root:
+ element->entry = parseRootElement(reader, since, &attributes);
+ element->type = StackElement::Root;
+ break;
+ case StackElement::LoadTypesystem:
+ if (!loadTypesystem(reader, &attributes))
+ return false;
+ break;
+ case StackElement::RejectEnumValue:
+ if (!parseRejectEnumValue(reader, &attributes))
+ return false;
+ break;
+ case StackElement::ReplaceType:
+ if (!parseReplaceArgumentType(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::ConversionRule:
+ if (!TypeSystemParser::parseCustomConversion(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::NativeToTarget:
+ if (!parseNativeToTarget(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::TargetToNative: {
+ if (topElement.type != StackElement::ConversionRule) {
+ m_error = QLatin1String("Target to Native conversions can only be specified for custom conversion rules.");
+ return false;
+ }
+ const int replaceIndex = indexOfAttribute(attributes, replaceAttribute());
+ const bool replace = replaceIndex == -1
+ || convertBoolean(attributes.takeAt(replaceIndex).value(),
+ replaceAttribute(), true);
+ m_current->entry->customConversion()->setReplaceOriginalTargetToNativeConversions(replace);
+ }
+ break;
+ case StackElement::AddConversion:
+ if (!parseAddConversion(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::ModifyArgument:
+ if (!parseModifyArgument(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::NoNullPointers:
+ if (!parseNoNullPointer(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::DefineOwnership:
+ if (!parseDefineOwnership(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::SuppressedWarning: {
+ const int textIndex = indexOfAttribute(attributes, textAttribute());
+ if (textIndex == -1) {
+ qCWarning(lcShiboken) << "Suppressed warning with no text specified";
+ } else {
+ const QString suppressedWarning =
+ attributes.takeAt(textIndex).value().toString();
+ if (!m_database->addSuppressedWarning(suppressedWarning, &m_error))
+ return false;
+ }
+ }
+ break;
+ case StackElement::ArgumentMap:
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedElementWarning(reader, tagName)));
+ if (!parseArgumentMap(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::Removal:
+ if (!parseRemoval(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::Rename:
+ case StackElement::Access:
+ if (!parseRename(reader, element->type, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::RemoveArgument:
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("Removing argument requires argument modification as parent");
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().removed = true;
+ break;
+
+ case StackElement::ModifyField:
+ if (!parseModifyField(reader, &attributes))
+ return false;
+ break;
+ case StackElement::AddFunction:
+ if (!parseAddFunction(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::ModifyFunction:
+ if (!parseModifyFunction(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::ReplaceDefaultExpression:
+ if (!parseReplaceDefaultExpression(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::RemoveDefaultExpression:
+ m_contextStack.top()->functionMods.last().argument_mods.last().removedDefaultExpression = true;
+ break;
+ case StackElement::CustomMetaConstructor:
+ case StackElement::CustomMetaDestructor:
+ element->value.customFunction =
+ parseCustomMetaConstructor(reader, element->type, topElement, &attributes);
+ break;
+ case StackElement::ReferenceCount:
+ if (!parseReferenceCount(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::ParentOwner:
+ if (!parseParentOwner(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::Array:
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("array must be child of modify-argument");
+ return false;
+ }
+ m_contextStack.top()->functionMods.last().argument_mods.last().array = true;
+ break;
+ case StackElement::InjectCode:
+ if (!parseInjectCode(reader, topElement, element, &attributes))
+ return false;
+ break;
+ case StackElement::Include:
+ if (!parseInclude(reader, topElement, element->entry, &attributes))
+ return false;
+ break;
+ case StackElement::Rejection:
+ if (!addRejection(m_database, &attributes, &m_error))
+ return false;
+ break;
+ case StackElement::Template: {
+ const int nameIndex = indexOfAttribute(attributes, nameAttribute());
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute());
+ return false;
+ }
+ element->value.templateEntry =
+ new TemplateEntry(attributes.takeAt(nameIndex).value().toString());
+ }
+ break;
+ case StackElement::TemplateInstanceEnum:
+ element->value.templateInstance =
+ parseTemplateInstanceEnum(reader, topElement, &attributes);
+ if (!element->value.templateInstance)
+ return false;
+ break;
+ case StackElement::Replace:
+ if (!parseReplace(reader, topElement, element, &attributes))
+ return false;
+ break;
+ default:
+ break; // nada
+ }
+ }
+
+ if (!attributes.isEmpty()) {
+ const QString message = msgUnusedAttributes(tagName, attributes);
+ qCWarning(lcShiboken, "%s", qPrintable(msgReaderWarning(reader, message)));
+ }
+
+ m_current = element;
+ return true;
+}
diff --git a/sources/shiboken2/ApiExtractor/typesystem_p.h b/sources/shiboken2/ApiExtractor/typesystemparser.h
index 5b8b93ce..aaf22353 100644
--- a/sources/shiboken2/ApiExtractor/typesystem_p.h
+++ b/sources/shiboken2/ApiExtractor/typesystemparser.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -25,13 +25,14 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef TYPESYSTEM_P_H
-#define TYPESYSTEM_P_H
+#ifndef TYPESYSTEMPARSER_H
+#define TYPESYSTEMPARSER_H
-#include <QStack>
-#include <QtCore/QScopedPointer>
#include "typesystem.h"
+#include <QtCore/QStack>
+#include <QtCore/QScopedPointer>
+
QT_FORWARD_DECLARE_CLASS(QXmlStreamAttributes)
QT_FORWARD_DECLARE_CLASS(QXmlStreamReader)
@@ -137,13 +138,13 @@ struct StackElementContext
int addedFunctionModificationIndex = -1;
};
-class Handler
+class TypeSystemParser
{
public:
- Q_DISABLE_COPY(Handler)
+ Q_DISABLE_COPY(TypeSystemParser)
- Handler(TypeDatabase* database, bool generate);
- ~Handler();
+ TypeSystemParser(TypeDatabase* database, bool generate);
+ ~TypeSystemParser();
bool parse(QXmlStreamReader &reader);
@@ -270,4 +271,4 @@ private:
QScopedPointer<TypeSystemEntityResolver> m_entityResolver;
};
-#endif
+#endif // TYPESYSTEMPARSER_H
diff --git a/sources/shiboken2/doc/typesystemvariables.rst b/sources/shiboken2/doc/typesystemvariables.rst
index a07ba0d8..b1b9bbfe 100644
--- a/sources/shiboken2/doc/typesystemvariables.rst
+++ b/sources/shiboken2/doc/typesystemvariables.rst
@@ -126,6 +126,29 @@ Variables
Replaced by a |project| conversion call that converts a Python variable
to a C++ variable of the type indicated by ``CPPTYPE``.
+ Typically, this is a variable assignment:
+
+ .. code-block:: c++
+
+ double value = %CONVERTTOCPP[double](pyValue);
+
+ Pointer assignments are also possible:
+
+ .. code-block:: c++
+
+ void f(double *valuePtr)
+ {
+ *valuePtr = %CONVERTTOCPP[double](pyValue);
+
+ Note however, that for variable definitions, the type must
+ be a space-delimited token:
+
+ .. code-block:: c++
+
+ double * valuePtr = %CONVERTTOCPP[double](pyValue);
+
+ since it otherwise would be indistinguishable from the pointer assignment
+ above.
.. _converttopython:
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 104b0a42..b86a5eb4 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -3032,18 +3032,21 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMe
s << INDENT << "if (kwds) {" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "PyObject *";
+ s << INDENT << "PyObject *keyName = nullptr;" << endl;
+ s << INDENT << "PyObject *value = nullptr;" << endl;
for (const AbstractMetaArgument *arg : args) {
int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex());
QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex) : QLatin1String(PYTHON_ARG);
- s << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl;
+ s << INDENT << "keyName = Py_BuildValue(\"s\",\"" << arg->name() << "\");" << endl;
+ s << INDENT << "if (PyDict_Contains(kwds, keyName)) {" << endl;
+ s << INDENT << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl;
s << INDENT << "if (value && " << pyArgName << ") {" << endl;
{
Indentation indent(INDENT);
s << INDENT << pyErrString.arg(arg->name()) << endl;
s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
- s << INDENT << "} else if (value) {" << endl;
+ s << INDENT << INDENT << "} else if (value) {" << endl;
{
Indentation indent(INDENT);
s << INDENT << pyArgName << " = value;" << endl;
@@ -3058,6 +3061,7 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMe
s << INDENT << '}' << endl;
if (arg != args.constLast())
s << INDENT;
+ s << "}" << endl;
}
}
s << INDENT << '}' << endl;
@@ -4558,23 +4562,6 @@ void CppGenerator::writeMethodDefinition(QTextStream &s, const AbstractMetaFunct
s << ',' << endl;
}
-static QString resolveRetOrArgType(const AbstractMetaType *someType)
-{
- QString strRetArg;
- if (CppGenerator::isCString(someType)) {
- strRetArg = QLatin1String("str");
- } else if (someType->isPrimitive()) {
- auto ptp = static_cast<const PrimitiveTypeEntry *>(someType->typeEntry());
- while (ptp->referencedTypeEntry())
- ptp = ptp->referencedTypeEntry();
- strRetArg = ptp->name();
- } else {
- strRetArg = someType->fullName();
- }
- strRetArg.replace(QLatin1String("::"), QLatin1String("."));
- return strRetArg;
-}
-
void CppGenerator::writeSignatureInfo(QTextStream &s, const AbstractMetaFunctionList &overloads)
{
OverloadData overloadData(overloads, this);
@@ -4588,11 +4575,7 @@ void CppGenerator::writeSignatureInfo(QTextStream &s, const AbstractMetaFunction
QStringList args;
const AbstractMetaArgumentList &arguments = f->arguments();
for (const AbstractMetaArgument *arg : arguments) {
- AbstractMetaType *argType = getTypeWithoutContainer(arg->type());
- QString strArg = resolveRetOrArgType(arg->type());
- // PYSIDE-921: Handle container returntypes correctly.
- if (argType != arg->type())
- strArg += QLatin1Char('[') + resolveRetOrArgType(argType) + QLatin1Char(']');
+ QString strArg = arg->type()->pythonSignature();
if (!arg->defaultValueExpression().isEmpty()) {
strArg += QLatin1Char('=');
QString e = arg->defaultValueExpression();
@@ -4607,12 +4590,8 @@ void CppGenerator::writeSignatureInfo(QTextStream &s, const AbstractMetaFunction
if (multiple)
s << idx-- << ':';
s << funcName << '(' << args.join(QLatin1Char(',')) << ')';
- AbstractMetaType *returnType = getTypeWithoutContainer(f->type());
- // PYSIDE-921: Handle container returntypes correctly.
- if (returnType != f->type())
- s << "->" << resolveRetOrArgType(f->type()) << '[' << resolveRetOrArgType(returnType) << ']';
- else if (returnType)
- s << "->" << resolveRetOrArgType(returnType);
+ if (f->type())
+ s << "->" << f->type()->pythonSignature();
s << endl;
}
}
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index 8e27777d..e41c9171 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -149,6 +149,8 @@ ShibokenGenerator::ShibokenGenerator()
const char CHECKTYPE_REGEX[] = R"(%CHECKTYPE\[([^\[]*)\]\()";
const char ISCONVERTIBLE_REGEX[] = R"(%ISCONVERTIBLE\[([^\[]*)\]\()";
const char CONVERTTOPYTHON_REGEX[] = R"(%CONVERTTOPYTHON\[([^\[]*)\]\()";
+ // Capture a '*' leading the variable name into the target
+ // so that "*valuePtr = %CONVERTTOCPP..." works as expected.
const char CONVERTTOCPP_REGEX[] =
R"((\*?%?[a-zA-Z_][\w\.]*(?:\[[^\[^<^>]+\])*)(?:\s+)=(?:\s+)%CONVERTTOCPP\[([^\[]*)\]\()";
m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegularExpression(QLatin1String(CHECKTYPE_REGEX));
@@ -2044,10 +2046,9 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
varType = miniNormalizer(varType);
QString varName = list.at(1).trimmed();
if (!varType.isEmpty()) {
- if (varType != conversionType->cppSignature()) {
- qFatal("Types of receiver variable ('%s') and %%CONVERTTOCPP type system variable ('%s') differ.",
- qPrintable(varType), qPrintable(conversionType->cppSignature()));
- }
+ const QString conversionSignature = conversionType->cppSignature();
+ if (varType != conversionSignature)
+ qFatal("%s", qPrintable(msgConversionTypesDiffer(varType, conversionSignature)));
c << getFullTypeName(conversionType) << ' ' << varName;
writeMinimalConstructorExpression(c, conversionType);
c << ';' << endl;
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
index e62f861a..7eaf35e1 100644
--- a/sources/shiboken2/libshiboken/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature.cpp
@@ -77,6 +77,7 @@ typedef struct safe_globals_struc {
PyObject *create_signature_func;
PyObject *seterror_argument_func;
PyObject *make_helptext_func;
+ PyObject *finish_import_func;
} safe_globals_struc, *safe_globals;
static safe_globals pyside_globals = nullptr;
@@ -543,6 +544,9 @@ init_phase_1(void)
if (p->value_dict == nullptr)
goto error;
+ // This function will be disabled until phase 2 is done.
+ p->finish_import_func = nullptr;
+
return p;
}
error:
@@ -585,6 +589,10 @@ init_phase_2(safe_globals_struc *p, PyMethodDef *methods)
p->make_helptext_func = PyObject_GetAttrString(loader, "make_helptext");
if (p->make_helptext_func == nullptr)
goto error;
+ p->finish_import_func = PyObject_GetAttrString(loader, "finish_import");
+ if (p->finish_import_func == nullptr)
+ goto error;
+ return 0;
return 0;
}
error:
@@ -1014,7 +1022,16 @@ PySide_FinishSignatures(PyObject *module, const char *signatures[])
return -1;
if (_finish_nested_classes(obdict) < 0)
return -1;
- return 0;
+ // The finish_import function will not work the first time since phase 2
+ // was not yet run. But that is ok, because the first import is always for
+ // the shiboken module (or a test module).
+ if (pyside_globals->finish_import_func == nullptr) {
+ assert(strncmp(name, "PySide2.", 8) != 0);
+ return 0;
+ }
+ Shiboken::AutoDecRef ret(PyObject_CallFunction(
+ pyside_globals->finish_import_func, const_cast<char *>("(O)"), module));
+ return ret.isNull() ? -1 : 0;
}
static int
diff --git a/sources/shiboken2/libshiboken/signature_doc.rst b/sources/shiboken2/libshiboken/signature_doc.rst
index 9c42c597..a984de4c 100644
--- a/sources/shiboken2/libshiboken/signature_doc.rst
+++ b/sources/shiboken2/libshiboken/signature_doc.rst
@@ -73,8 +73,8 @@ It calls ``GetSignature_Function`` which returns the signature if it is found.
Why this Code is Fast
---------------------
-It costs a little time (maybe 4 seconds) to run througs every single signature
-object, since these are more than 15000 Python objects. But all the signature
+It costs a little time (maybe 6 seconds) to run througs every single signature
+object, since these are more than 25000 Python objects. But all the signature
objects will be rarely accessed but in special applications.
The normal case are only a few accesses, and these are working pretty fast.
@@ -111,10 +111,6 @@ the ``signature`` Python package. It has the following structure::
shiboken2/files.dir/shibokensupport/
backport_inspect.py
- python_minilib_2_7.py
- python_minilib_3_5.py
- python_minilib_3_6.py
- python_minilib_3_7.py
signature/
loader.py
@@ -125,6 +121,8 @@ the ``signature`` Python package. It has the following structure::
lib/
enum_sig.py
+ tool.py
+
Really important are the **parser**, **mapping**, **errorhandler**, **enum_sig**,
diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt
index 09731240..5e5cf21d 100644
--- a/sources/shiboken2/shibokenmodule/CMakeLists.txt
+++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt
@@ -53,6 +53,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/
"${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/layout.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/loader.py"
"${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/loader.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/importhandler.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/importhandler.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/mapping.py"
"${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/mapping.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/parser.py"
@@ -61,6 +63,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/
"${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/__init__.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/enum_sig.py"
"${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/enum_sig.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/tool.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/tool.py" COPYONLY)
if (PYTHON_VERSION_MAJOR EQUAL 3)
else()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/backport_inspect.py"
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py
new file mode 100644
index 00000000..0417f132
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py
@@ -0,0 +1,103 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+"""
+importhandler.py
+
+This module handles special actions after the import of PySide modules.
+The reason for this was the wish to replace some deprecated functions
+by a Python implementation that gives a warning.
+
+It provides a framework to safely call functions outside of files.dir,
+because the implementation of deprecated functions should be visible
+to the users (in the hope they don't use it any longer <wink>).
+
+As a first approach, the function finish_import redirects to
+PySide2/support/deprecated.py . There can come other extensions as well.
+"""
+
+try:
+ from PySide2.support import deprecated
+ have_deprecated = True
+except ImportError:
+ have_deprecated = False
+
+
+# called by loader.py from signature.cpp
+def finish_import(module):
+ if have_deprecated and module.__name__.startswith("PySide2."):
+ try:
+ name = "fix_for_" + module.__name__.split(".")[1]
+ func = getattr(deprecated, name, None)
+ if func:
+ func(module)
+ except Exception as e:
+ name = e.__class__.__name__
+ print(72 * "*")
+ print("Error in deprecated.py, ignored:")
+ print(" {name}: {e}".format(**locals()))
+
+"""
+A note for people who might think this could be written in pure Python:
+
+Sure, by an explicit import of the modules to patch, this is no problem.
+But in the general case, a module should only be imported on user
+request and not because we want to patch it. So I started over.
+
+I then tried to do it on demand by redirection of the __import__ function.
+Things worked quite nicely as it seemed, but at second view this solution
+was much less appealing.
+
+Reason:
+If someone executes as the first PySide statement
+
+ from PySide2 import QtGui
+
+then this import is already running. We can see the other imports like the
+diverse initializations and QtCore, because it is triggered by import of
+QtGui. But the QtGui import can not be seen at all!
+
+With a lot of effort, sys.setprofile() and stack inspection with the inspect
+module, it is *perhaps* possible to solve that. I tried for a day and then
+gave up, since the solution is anyway not too nice when __import__ must
+be overridden.
+"""
+#eof
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py
index c43d6d07..bd827f1e 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py
@@ -58,20 +58,7 @@ used literally as strings like "signature", "existence", etc.
from textwrap import dedent
from shibokensupport.signature import inspect
from shibokensupport.signature.mapping import ellipsis
-
-
-class SimpleNamespace(object):
- # From types.rst, because the builtin is implemented in Python 3, only.
- def __init__(self, **kwargs):
- self.__dict__.update(kwargs)
-
- def __repr__(self):
- keys = sorted(self.__dict__)
- items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
- return "{}({})".format(type(self).__name__, ", ".join(items))
-
- def __eq__(self, other):
- return self.__dict__ == other.__dict__
+from shibokensupport.signature.lib.tool import SimpleNamespace
class SignatureLayout(SimpleNamespace):
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
new file mode 100644
index 00000000..b34bfb40
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
@@ -0,0 +1,135 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+"""
+tool.py
+
+Some useful stuff, see below.
+"""
+
+from textwrap import dedent
+
+
+class SimpleNamespace(object):
+ # From types.rst, because the builtin is implemented in Python 3, only.
+ def __init__(self, **kwargs):
+ self.__dict__.update(kwargs)
+
+ def __repr__(self):
+ keys = sorted(self.__dict__)
+ items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
+ return "{}({})".format(type(self).__name__, ", ".join(items))
+
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
+
+try:
+ from types import SimpleNamespace
+except ImportError:
+ pass
+
+
+def build_brace_pattern(level, separators=""):
+ """
+ Build a brace pattern upto a given depth
+
+ The brace pattern parses any pattern with round, square, curly, or angle
+ brackets. Inside those brackets, any characters are allowed.
+
+ The structure is quite simple and is recursively repeated as needed.
+ When separators are given, the match stops at that separator.
+
+ Reason to use this instead of some Python function:
+ The resulting regex is _very_ fast!
+
+ A faster replacement would be written in C, but this solution is
+ sufficient when the nesting level is not too large.
+
+ Because of the recursive nature of the pattern, the size grows by a factor
+ of 4 at every level, as does the creation time. Up to a level of 6, this
+ is below 10 ms.
+
+ There are other regex engines available which allow recursive patterns,
+ avoiding this problem completely. It might be considered to switch to
+ such an engine if the external module is not a problem.
+ """
+ def escape(str):
+ return "".join("\\" + c for c in str)
+
+ ro, rc = round = "()"
+ so, sc = square = "[]"
+ co, cc = curly = "CD" # we insert "{}", later...
+ ao, ac = angle = "<>"
+ qu, bs = '"', "\\"
+ all = round + square + curly + angle
+ __ = " "
+ ro, rc, so, sc, co, cc, ao, ac, separators, qu, bs, all = map(
+ escape, (ro, rc, so, sc, co, cc, ao, ac, separators, qu, bs, all))
+
+ no_brace_sep_q = r"[^{all}{separators}{qu}{bs}]".format(**locals())
+ no_quote = r"(?: [^{qu}{bs}] | {bs}. )*".format(**locals())
+ pattern = dedent(r"""
+ (
+ (?: {__} {no_brace_sep_q}
+ | {qu} {no_quote} {qu}
+ | {ro} {replacer} {rc}
+ | {so} {replacer} {sc}
+ | {co} {replacer} {cc}
+ | {ao} {replacer} {ac}
+ )*
+ )
+ """)
+ no_braces_q = "[^{all}{qu}{bs}]*".format(**locals())
+ repeated = dedent(r"""
+ {indent} (?: {__} {no_braces_q}
+ {indent} | {qu} {no_quote} {qu}
+ {indent} | {ro} {replacer} {rc}
+ {indent} | {so} {replacer} {sc}
+ {indent} | {co} {replacer} {cc}
+ {indent} | {ao} {replacer} {ac}
+ {indent} )*
+ """)
+ for idx in range(level):
+ pattern = pattern.format(replacer = repeated if idx < level-1 else no_braces_q,
+ indent = idx * " ", **locals())
+ return pattern.replace("C", "{").replace("D", "}")
+
+# eof
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
index 6c76483a..3d25c569 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
@@ -103,6 +103,10 @@ def _typevar__repr__(self):
# break the Python license decorated files without an encoding line.
# name used in signature.cpp
+def pyside_type_init(type_key, sig_strings):
+ return parser.pyside_type_init(type_key, sig_strings)
+
+# name used in signature.cpp
def create_signature(props, key):
return layout.create_signature(props, key)
@@ -114,6 +118,11 @@ def seterror_argument(args, func_name):
def make_helptext(func):
return errorhandler.make_helptext(func)
+# name used in signature.cpp
+def finish_import(module):
+ return importhandler.finish_import(module)
+
+
import signature_bootstrap
from shibokensupport import signature
signature.get_signature = signature_bootstrap.get_signature
@@ -194,6 +203,7 @@ def move_into_pyside_package():
put_into_package(PySide2.support.signature, layout)
put_into_package(PySide2.support.signature, lib)
put_into_package(PySide2.support.signature, parser)
+ put_into_package(PySide2.support.signature, importhandler)
put_into_package(PySide2.support.signature.lib, enum_sig)
put_into_package(PySide2.support.signature, typing)
@@ -204,8 +214,8 @@ from shibokensupport.signature import errorhandler
from shibokensupport.signature import layout
from shibokensupport.signature import lib
from shibokensupport.signature import parser
+from shibokensupport.signature import importhandler
from shibokensupport.signature.lib import enum_sig
-from shibokensupport.signature.parser import pyside_type_init
if "PySide2" in sys.modules:
# We publish everything under "PySide2.support.signature", again.
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
index 5f92446c..5d6a2401 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
@@ -61,24 +61,12 @@ class ellipsis(object):
return "..."
ellipsis = ellipsis()
-StringList = typing.List[str]
-IntList = typing.List[int]
Point = typing.Tuple[float, float]
-PointList = typing.List[Point]
-IntMatrix = typing.List[IntList]
Variant = typing.Any
ModelIndexList = typing.List[int]
QImageCleanupFunction = typing.Callable
-# First time installing our own Pair type into typing.
-T = TypeVar('T')
-S = TypeVar('S')
-
-class Pair(Generic[T, S]):
- __module__ = "typing"
-
-typing.Pair = Pair
-
+_S = TypeVar("_S")
# Building our own Char type, which is much nicer than
# Char = typing.Union[str, int] # how do I model the limitation to 1 char?
@@ -174,7 +162,12 @@ class _NotCalled(str):
text = self if self.endswith(")") else self + "()"
return eval(text, namespace)
-USE_PEP563 = sys.version_info[:2] >= (3, 7)
+USE_PEP563 = False
+# Note: we cannot know if this feature has been imported.
+# Otherwise it would be "sys.version_info[:2] >= (3, 7)".
+# We *can* eventually inspect sys.modules and look if
+# the calling module has this future statement set,
+# but should we do that?
# Some types are abstract. They just show their name.
@@ -183,10 +176,11 @@ class Virtual(_NotCalled):
# Other types I simply could not find.
class Missing(_NotCalled):
- if not USE_PEP563:
- # The string must be quoted, because the object does not exist.
- def __repr__(self):
- return '{}("{}")'.format(type(self).__name__, self)
+ # The string must be quoted, because the object does not exist.
+ def __repr__(self):
+ if USE_PEP563:
+ return _NotCalled.__repr__(self)
+ return '{}("{}")'.format(type(self).__name__, self)
class Invalid(_NotCalled):
@@ -200,6 +194,27 @@ class Default(_NotCalled):
class Instance(_NotCalled):
pass
+# Parameterized primitive variables
+class _Parameterized(object):
+ def __init__(self, type):
+ self.type = type
+ self.__name__ = self.__class__.__name__
+
+ def __repr__(self):
+ return "{}({})".format(
+ type(self).__name__, self.type.__name__)
+
+# Mark the primitive variables to be moved into the result.
+class ResultVariable(_Parameterized):
+ pass
+
+# Mark the primitive variables to become Sequence, Iterator or List
+# (decided in the parser).
+class ArrayLikeVariable(_Parameterized):
+ pass
+
+StringList = ArrayLikeVariable(str)
+
class Reloader(object):
"""
@@ -230,7 +245,7 @@ class Reloader(object):
self.sys_module_count = len(sys.modules)
g = globals()
# PYSIDE-1009: Try to recognize unknown modules in errorhandler.py
- candidates = list(mod_name for mod_name in sys.modules
+ candidates = list(mod_name for mod_name in sys.modules.copy()
if self.module_valid(sys.modules[mod_name]))
for mod_name in candidates:
# 'top' is PySide2 when we do 'import PySide.QtCore'
@@ -260,20 +275,130 @@ type_map = {}
namespace = globals() # our module's __dict__
type_map.update({
- "QList": typing.List,
- "QVector": typing.List,
- "QSet": typing.Set,
- "QPair": Pair,
+ "bool": bool,
+ "char": Char,
+ "char*": str,
+ "char*const": str,
+ "double": float,
+ "float": float,
+ "int": int,
+ "List": ArrayLikeVariable,
+ "long": int,
+ "PyCallable": typing.Callable,
+ "PyObject": object,
+ "PySequence": typing.Iterable, # important for numpy
+ "PyTypeObject": type,
+ "QChar": Char,
+ "QHash": typing.Dict,
+ "qint16": int,
+ "qint32": int,
+ "qint64": int,
+ "qint8": int,
+ "qintptr": int,
+ "QList": ArrayLikeVariable,
+ "qlonglong": int,
"QMap": typing.Dict,
+ "QPair": typing.Tuple,
+ "qptrdiff": int,
+ "qreal": float,
+ "QSet": typing.Set,
+ "QString": str,
+ "QStringList": StringList,
+ "quint16": int,
+ "quint32": int,
+ "quint32": int,
+ "quint64": int,
+ "quint8": int,
+ "quintptr": int,
+ "qulonglong": int,
+ "QVariant": Variant,
+ "QVector": typing.List,
+ "real": float,
+ "short": int,
+ "signed char": Char,
+ "signed long": int,
+ "std.list": typing.List,
+ "std.map": typing.Dict,
+ "std.pair": typing.Tuple,
+ "std.vector": typing.List,
+ "str": str,
+ "true": True,
+ "Tuple": typing.Tuple,
+ "uchar": Char,
+ "uchar*": str,
+ "uint": int,
+ "ulong": int,
+ "ULONG_MAX": ulong_max,
+ "unsigned char": Char, # 5.9
+ "unsigned char*": str,
+ "unsigned int": int,
+ "unsigned long int": int, # 5.6, RHEL 6.6
+ "unsigned long long": int,
+ "unsigned long": int,
+ "unsigned short int": int, # 5.6, RHEL 6.6
+ "unsigned short": int,
+ "ushort": int,
+ "void": int, # be more specific?
+ "WId": WId,
+ "zero(bytes)": b"",
+ "zero(Char)": 0,
+ "zero(float)": 0,
+ "zero(int)": 0,
+ "zero(object)": None,
+ "zero(str)": "",
+ "zero(typing.Any)": None,
+ })
+
+type_map.update({
+ # Handling variables declared as array:
+ "array double*" : ArrayLikeVariable(float),
+ "array float*" : ArrayLikeVariable(float),
+ "array GLint*" : ArrayLikeVariable(int),
+ "array GLuint*" : ArrayLikeVariable(int),
+ "array int*" : ArrayLikeVariable(int),
+ "array long long*" : ArrayLikeVariable(int),
+ "array short*" : ArrayLikeVariable(int),
+ "array signed char*" : bytes,
+ "array unsigned char*" : bytes,
+ "array unsigned int*" : ArrayLikeVariable(int),
+ "array unsigned short*" : ArrayLikeVariable(int),
+ })
+
+type_map.update({
+ # Special cases:
+ "char*" : bytes,
+ "QChar*" : bytes,
+ "quint32*" : int, # only for QRandomGenerator
+ "quint8*" : bytearray, # only for QCborStreamReader and QCborValue
+ "uchar*" : bytes,
+ "unsigned char*": bytes,
+ })
+
+type_map.update({
+ # Handling variables that are returned, eventually as Tuples:
+ "bool*" : ResultVariable(bool),
+ "float*" : ResultVariable(float),
+ "int*" : ResultVariable(int),
+ "long long*" : ResultVariable(int),
+ "long*" : ResultVariable(int),
+ "PStr*" : ResultVariable(str), # module sample
+ "qint32*" : ResultVariable(int),
+ "qint64*" : ResultVariable(int),
+ "qreal*" : ResultVariable(float),
+ "QString*" : ResultVariable(str),
+ "quint16*" : ResultVariable(int),
+ "uint*" : ResultVariable(int),
+ "unsigned int*" : ResultVariable(int),
+ "QStringList*" : ResultVariable(StringList),
})
# The Shiboken Part
def init_Shiboken():
type_map.update({
+ "PyType": type,
"shiboken2.bool": bool,
"size_t": int,
- "PyType": type,
})
return locals()
@@ -288,36 +413,34 @@ def init_minimal():
def init_sample():
import datetime
type_map.update({
- "double": float,
- "sample.int": int,
+ "char": Char,
+ "char**": typing.List[str],
"Complex": complex,
- "sample.OddBool": bool,
- "sample.bool": bool,
- "sample.PStr": str,
+ "double": float,
+ "Foo.HANDLE": int,
+ "HANDLE": int,
+ "Null": None,
+ "ObjectType.Identifier": Missing("sample.ObjectType.Identifier"),
"OddBool": bool,
"PStr": str,
- "char": Char,
+ "PyDate": datetime.date,
+ "sample.bool": bool,
"sample.char": Char,
- "sample.Point": Point,
+ "sample.double": float,
+ "sample.int": int,
"sample.ObjectType": object,
- "std.string": str,
- "HANDLE": int,
- "Foo.HANDLE": int,
- "sample.Photon.TemplateBase": Missing("sample.Photon.TemplateBase"),
- "ObjectType.Identifier": Missing("sample.ObjectType.Identifier"),
- "zero(HANDLE)": 0,
- "Null": None,
- "zero(sample.ObjectType)": None,
+ "sample.OddBool": bool,
+ "sample.Photon.TemplateBase[Photon.DuplicatorType]": sample.Photon.ValueDuplicator,
+ "sample.Photon.TemplateBase[Photon.IdentityType]": sample.Photon.ValueIdentity,
+ "sample.Point": Point,
+ "sample.PStr": str,
+ "sample.unsigned char": Char,
"std.size_t": int,
- 'Str("<unknown>")': "<unknown>",
+ "std.string": str,
+ "ZeroIn": 0,
'Str("<unk")': "<unk",
+ 'Str("<unknown>")': "<unknown>",
'Str("nown>")': "nown>",
- "zero(sample.ObjectModel)": None,
- "sample.unsigned char": Char,
- "sample.double": float,
- "zero(sample.bool)": False,
- "PyDate": datetime.date,
- "ZeroIn": 0,
})
return locals()
@@ -325,19 +448,25 @@ def init_sample():
def init_other():
import numbers
type_map.update({
- "other.Number": numbers.Number,
"other.ExtendsNoImplicitConversion": Missing("other.ExtendsNoImplicitConversion"),
+ "other.Number": numbers.Number,
})
return locals()
def init_smart():
+ # This missing type should be defined in module smart. We cannot set it to Missing()
+ # because it is a container type. Therefore, we supply a surrogate:
+ global SharedPtr
+ class SharedPtr(Generic[_S]):
+ __module__ = "smart"
+ smart.SharedPtr = SharedPtr
type_map.update({
- "smart.SharedPtr": Missing("smart.SharedPtr"), # bad object "SharedPtr<Obj >"
"smart.Smart.Integer2": int,
})
return locals()
+
# The PySide Part
def init_PySide2_QtCore():
from PySide2.QtCore import Qt, QUrl, QDir
@@ -349,131 +478,53 @@ def init_PySide2_QtCore():
except ImportError:
pass
type_map.update({
- "str": str,
- "int": int,
- "QString": str,
- "bool": bool,
- "PyObject": object,
- "void": int, # be more specific?
- "char": Char,
- "'%'": "%",
"' '": " ",
- "false": False,
- "double": float,
+ "'%'": "%",
"'g'": "g",
- "long long": int,
- "unsigned int": int, # should we define an unsigned type?
- "Q_NULLPTR": None,
- "long": int,
- "float": float,
- "short": int,
- "unsigned long": int,
- "unsigned long long": int,
- "unsigned short": int,
- "QStringList": StringList,
- "QChar": Char,
- "signed char": Char,
- "QVariant": Variant,
- "QVariant.Type": type, # not so sure here...
- "QStringRef": str,
- "QString()": "",
- "QModelIndexList": ModelIndexList,
- "unsigned char": Char,
- "QJsonObject": typing.Dict[str, PySide2.QtCore.QJsonValue],
- "QStringList()": [],
- "ULONG_MAX": ulong_max,
- "quintptr": int,
- "PyCallable": typing.Callable,
- "PyTypeObject": type,
- "PySequence": typing.Iterable, # important for numpy
- "qptrdiff": int,
- "true": True,
- "Qt.HANDLE": int, # be more explicit with some consts?
- "list of QAbstractState": typing.List[PySide2.QtCore.QAbstractState],
+ "4294967295UL": 4294967295, # 5.6, RHEL 6.6
+ "CheckIndexOption.NoOption": Instance(
+ "PySide2.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11
+ "false": False,
"list of QAbstractAnimation": typing.List[PySide2.QtCore.QAbstractAnimation],
- "QVariant()": Invalid(Variant),
- "PySide2.QtCore.bool": bool,
- "QHash": typing.Dict,
- "PySide2.QtCore.QChar": Char,
- "PySide2.QtCore.qreal": float,
- "PySide2.QtCore.float": float,
- "PySide2.QtCore.qint16": int,
- "PySide2.QtCore.qint32": int,
- "PySide2.QtCore.qint64": int,
- "PySide2.QtCore.qint8": int,
- "PySide2.QtCore.QString": str,
- "PySide2.QtCore.QStringList": StringList,
- "PySide2.QtCore.QVariant": Variant,
- "PySide2.QtCore.quint16": int,
- "PySide2.QtCore.quint32": int,
- "PySide2.QtCore.quint64": int,
- "PySide2.QtCore.quint8": int,
- "PySide2.QtCore.short": int,
- "PySide2.QtCore.unsigned short": int,
- "PySide2.QtCore.signed char": Char,
- "PySide2.QtCore.uchar": Char,
- "PySide2.QtCore.unsigned char": Char, # 5.9
- "PySide2.QtCore.long": int,
+ "list of QAbstractState": typing.List[PySide2.QtCore.QAbstractState],
+ "long long": int,
+ "NULL": None, # 5.6, MSVC
+ "nullptr": None, # 5.9
+ "PyByteArray": bytearray,
+ "PyBytes": bytes,
+ "PySide2.QtCore.QCborStreamReader.StringResult[PySide2.QtCore.QByteArray]":
+ PySide2.QtCore.QCborStringResultByteArray,
+ "PySide2.QtCore.QCborStreamReader.StringResult[QString]":
+ PySide2.QtCore.QCborStringResultString,
"PySide2.QtCore.QUrl.ComponentFormattingOptions":
PySide2.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why???
- "QUrl.FormattingOptions(PrettyDecoded)": Instance(
- "QUrl.FormattingOptions(QUrl.PrettyDecoded)"),
- # from 5.9
+ "PyUnicode": typing.Text,
+ "Q_NULLPTR": None,
"QDir.Filters(AllEntries | NoDotAndDotDot)": Instance(
"QDir.Filters(QDir.AllEntries | QDir.NoDotAndDotDot)"),
- "NULL": None, # 5.6, MSVC
"QDir.SortFlags(Name | IgnoreCase)": Instance(
"QDir.SortFlags(QDir.Name | QDir.IgnoreCase)"),
- "PyBytes": bytes,
- "PyByteArray": bytearray,
- "PyUnicode": typing.Text,
- "signed long": int,
- "PySide2.QtCore.int": int,
- "PySide2.QtCore.char": StringList, # A 'char **' is a list of strings.
- "unsigned long int": int, # 5.6, RHEL 6.6
- "unsigned short int": int, # 5.6, RHEL 6.6
- "4294967295UL": 4294967295, # 5.6, RHEL 6.6
- "PySide2.QtCore.int32_t": int, # 5.9
- "PySide2.QtCore.int64_t": int, # 5.9
- "UnsignedShortType": int, # 5.9
- "nullptr": None, # 5.9
- "uint64_t": int, # 5.9
- "PySide2.QtCore.uint32_t": int, # 5.9
- "PySide2.QtCore.unsigned int": int, # 5.9 Ubuntu
- "PySide2.QtCore.long long": int, # 5.9, MSVC 15
- "QGenericArgument(nullptr)": ellipsis, # 5.10
- "QModelIndex()": Invalid("PySide2.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?!
"QGenericArgument((0))": ellipsis, # 5.6, RHEL 6.6. Is that ok?
"QGenericArgument()": ellipsis,
"QGenericArgument(0)": ellipsis,
"QGenericArgument(NULL)": ellipsis, # 5.6, MSVC
+ "QGenericArgument(nullptr)": ellipsis, # 5.10
"QGenericArgument(Q_NULLPTR)": ellipsis,
- "zero(PySide2.QtCore.QObject)": None,
- "zero(PySide2.QtCore.QThread)": None,
- "zero(quintptr)": 0,
- "zero(str)": "",
- "zero(int)": 0,
- "zero(PySide2.QtCore.QState)": None,
- "zero(PySide2.QtCore.bool)": False,
- "zero(PySide2.QtCore.int)": 0,
- "zero(void)": None,
- "zero(long long)": 0,
- "zero(PySide2.QtCore.QAbstractItemModel)": None,
- "zero(PySide2.QtCore.QJsonParseError)": None,
- "zero(double)": 0.0,
- "zero(PySide2.QtCore.qint64)": 0,
- "zero(PySide2.QtCore.QTextCodec.ConverterState)": None,
- "zero(long long)": 0,
- "zero(QImageCleanupFunction)": None,
- "zero(unsigned int)": 0,
- "zero(PySide2.QtCore.QPoint)": Default("PySide2.QtCore.QPoint"),
- "zero(unsigned char)": 0,
- "zero(PySide2.QtCore.QEvent.Type)": None,
- "CheckIndexOption.NoOption": Instance(
- "PySide2.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11
+ "QJsonObject": typing.Dict[str, PySide2.QtCore.QJsonValue],
+ "QModelIndex()": Invalid("PySide2.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?!
+ "QModelIndexList": ModelIndexList,
+ "QModelIndexList": ModelIndexList,
+ "QString()": "",
+ "QStringList()": [],
+ "QStringRef": str,
+ "QStringRef": str,
+ "Qt.HANDLE": int, # be more explicit with some constants?
+ "QUrl.FormattingOptions(PrettyDecoded)": Instance(
+ "QUrl.FormattingOptions(QUrl.PrettyDecoded)"),
+ "QVariant()": Invalid(Variant),
+ "QVariant.Type": type, # not so sure here...
+ "QVariantMap": typing.Dict[str, Variant],
"QVariantMap": typing.Dict[str, Variant],
- "PySide2.QtCore.QCborStreamReader.StringResult": typing.AnyStr,
- "PySide2.QtCore.double": float,
})
try:
type_map.update({
@@ -488,29 +539,17 @@ def init_PySide2_QtCore():
def init_PySide2_QtGui():
from PySide2.QtGui import QPageLayout, QPageSize # 5.12 macOS
type_map.update({
- "QVector< QTextLayout.FormatRange >()": [], # do we need more structure?
- "USHRT_MAX": ushort_max,
"0.0f": 0.0,
"1.0f": 1.0,
- "uint32_t": int,
- "uint8_t": int,
- "int32_t": int,
"GL_COLOR_BUFFER_BIT": GL_COLOR_BUFFER_BIT,
"GL_NEAREST": GL_NEAREST,
- "WId": WId,
- "PySide2.QtGui.QPlatformSurface": int, # a handle
- "QList< QTouchEvent.TouchPoint >()": [], # XXX improve?
+ "int32_t": int,
"QPixmap()": Default("PySide2.QtGui.QPixmap"), # can't create without qApp
- "PySide2.QtCore.uint8_t": int, # macOS 5.9
- "zero(uint32_t)": 0,
- "zero(PySide2.QtGui.QWindow)": None,
- "zero(PySide2.QtGui.QOpenGLContext)": None,
- "zero(PySide2.QtGui.QRegion)": None,
- "zero(PySide2.QtGui.QPaintDevice)": None,
- "zero(PySide2.QtGui.QTextLayout.FormatRange)": None,
- "zero(PySide2.QtGui.QTouchDevice)": None,
- "zero(PySide2.QtGui.QScreen)": None,
- "PySide2.QtGui.QGenericMatrix": Missing("PySide2.QtGui.QGenericMatrix"),
+ "QPlatformSurface*": int, # a handle
+ "QVector< QTextLayout.FormatRange >()": [], # do we need more structure?
+ "uint32_t": int,
+ "uint8_t": int,
+ "USHRT_MAX": ushort_max,
})
return locals()
@@ -523,26 +562,12 @@ def init_PySide2_QtWidgets():
"QMessageBox.StandardButtons(QMessageBox.Yes | QMessageBox.No)"),
"QWidget.RenderFlags(DrawWindowBackground | DrawChildren)": Instance(
"QWidget.RenderFlags(QWidget.DrawWindowBackground | QWidget.DrawChildren)"),
+ "SH_Default": QStyleHintReturn.SH_Default,
+ "SO_Complex": QStyleOptionComplex.SO_Complex,
+ "SO_Default": QStyleOption.SO_Default,
"static_cast<Qt.MatchFlags>(Qt.MatchExactly|Qt.MatchCaseSensitive)": Instance(
"Qt.MatchFlags(Qt.MatchExactly | Qt.MatchCaseSensitive)"),
- "QVector< int >()": [],
- "WId": WId,
- # from 5.9
"Type": PySide2.QtWidgets.QListWidgetItem.Type,
- "SO_Default": QStyleOption.SO_Default,
- "SH_Default": QStyleHintReturn.SH_Default,
- "SO_Complex": QStyleOptionComplex.SO_Complex,
- "zero(PySide2.QtWidgets.QWidget)": None,
- "zero(PySide2.QtWidgets.QGraphicsItem)": None,
- "zero(PySide2.QtCore.QEvent)": None,
- "zero(PySide2.QtWidgets.QStyleOption)": None,
- "zero(PySide2.QtWidgets.QStyleHintReturn)": None,
- "zero(PySide2.QtWidgets.QGraphicsLayoutItem)": None,
- "zero(PySide2.QtWidgets.QListWidget)": None,
- "zero(PySide2.QtGui.QKeySequence)": None,
- "zero(PySide2.QtWidgets.QAction)": None,
- "zero(PySide2.QtWidgets.QUndoCommand)": None,
- "zero(WId)": 0,
})
return locals()
@@ -557,20 +582,20 @@ def init_PySide2_QtSql():
def init_PySide2_QtNetwork():
+ best_structure = typing.OrderedDict if getattr(typing, "OrderedDict", None) else typing.Dict
type_map.update({
- "QMultiMap": MultiMap,
- "zero(unsigned short)": 0,
- "zero(PySide2.QtCore.QIODevice)": None,
- "zero(QList)": [],
+ "QMultiMap[PySide2.QtNetwork.QSsl.AlternativeNameEntryType, QString]":
+ best_structure[PySide2.QtNetwork.QSsl.AlternativeNameEntryType, typing.List[str]],
})
+ del best_structure
return locals()
def init_PySide2_QtXmlPatterns():
from PySide2.QtXmlPatterns import QXmlName
type_map.update({
+ "QXmlName.NamespaceCode": Missing("PySide2.QtXmlPatterns.QXmlName.NamespaceCode"),
"QXmlName.PrefixCode": Missing("PySide2.QtXmlPatterns.QXmlName.PrefixCode"),
- "QXmlName.NamespaceCode": Missing("PySide2.QtXmlPatterns.QXmlName.NamespaceCode")
})
return locals()
@@ -581,6 +606,7 @@ def init_PySide2_QtMultimedia():
check_module(PySide2.QtMultimediaWidgets)
type_map.update({
"QGraphicsVideoItem": PySide2.QtMultimediaWidgets.QGraphicsVideoItem,
+ "qint64": int,
"QVideoWidget": PySide2.QtMultimediaWidgets.QVideoWidget,
})
return locals()
@@ -588,16 +614,11 @@ def init_PySide2_QtMultimedia():
def init_PySide2_QtOpenGL():
type_map.update({
- "GLuint": int,
- "GLenum": int,
- "GLint": int,
"GLbitfield": int,
- "PySide2.QtOpenGL.GLint": int,
- "PySide2.QtOpenGL.GLuint": int,
+ "GLenum": int,
"GLfloat": float, # 5.6, MSVC 15
- "zero(PySide2.QtOpenGL.QGLContext)": None,
- "zero(GLenum)": 0,
- "zero(PySide2.QtOpenGL.QGLWidget)": None,
+ "GLint": int,
+ "GLuint": int,
})
return locals()
@@ -605,22 +626,16 @@ def init_PySide2_QtOpenGL():
def init_PySide2_QtQml():
type_map.update({
"QJSValueList()": [],
- "PySide2.QtQml.bool volatile": bool,
- # from 5.9
- "QVariantHash()": typing.Dict[str, Variant], # XXX sorted?
- "zero(PySide2.QtQml.QQmlContext)": None,
- "zero(PySide2.QtQml.QQmlEngine)": None,
+ "QVariantHash()": typing.Dict[str, Variant], # from 5.9
})
return locals()
def init_PySide2_QtQuick():
type_map.update({
- "PySide2.QtQuick.QSharedPointer": int,
- "PySide2.QtCore.uint": int,
- "T": int,
- "zero(PySide2.QtQuick.QQuickItem)": None,
- "zero(GLuint)": 0,
+ "PySide2.QtQuick.QSharedPointer[PySide2.QtQuick.QQuickItemGrabResult]":
+ PySide2.QtQuick.QQuickItemGrabResult,
+ "UnsignedShortType": int,
})
return locals()
@@ -634,17 +649,11 @@ def init_PySide2_QtScript():
def init_PySide2_QtTest():
type_map.update({
+ "PySide2.QtTest.QTest.PySideQTouchEventSequence": PySide2.QtTest.QTest.QTouchEventSequence,
"PySide2.QtTest.QTouchEventSequence": PySide2.QtTest.QTest.QTouchEventSequence,
})
return locals()
-# from 5.9
-def init_PySide2_QtWebEngineWidgets():
- type_map.update({
- "zero(PySide2.QtWebEngineWidgets.QWebEnginePage.FindFlags)": 0,
- })
- return locals()
-
# from 5.6, MSVC
def init_PySide2_QtWinExtras():
type_map.update({
@@ -661,6 +670,10 @@ def init_PySide2_QtDataVisualization():
QtDataVisualization.QSurfaceDataArray = typing.List[QtDataVisualization.QSurfaceDataRow]
type_map.update({
"100.0f": 100.0,
+ "QtDataVisualization.QBarDataArray": QtDataVisualization.QBarDataArray,
+ "QtDataVisualization.QBarDataArray*": QtDataVisualization.QBarDataArray,
+ "QtDataVisualization.QSurfaceDataArray": QtDataVisualization.QSurfaceDataArray,
+ "QtDataVisualization.QSurfaceDataArray*": QtDataVisualization.QSurfaceDataArray,
})
return locals()
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
index 72ca3575..204f3738 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
@@ -46,7 +46,9 @@ import types
import keyword
import functools
from shibokensupport.signature.mapping import (type_map, update_mapping,
- namespace, typing, _NotCalled)
+ namespace, typing, _NotCalled, ResultVariable, ArrayLikeVariable)
+from shibokensupport.signature.lib.tool import (SimpleNamespace,
+ build_brace_pattern)
_DEBUG = False
LIST_KEYWORDS = False
@@ -78,6 +80,23 @@ def dprint(*args, **kw):
pprint.pprint(arg)
sys.stdout.flush()
+
+_cache = {}
+
+def _parse_arglist(argstr):
+ # The following is a split re. The string is broken into pieces which are
+ # between the recognized strings. Because the re has groups, both the
+ # strings and the separators are returned, where the strings are not
+ # interesting at all: They are just the commata.
+ key = "_parse_arglist"
+ if key not in _cache:
+ regex = build_brace_pattern(level=3, separators=",")
+ _cache[key] = re.compile(regex, flags=re.VERBOSE)
+ split = _cache[key].split
+ # Note: this list is interspersed with "," and surrounded by ""
+ return [x.strip() for x in split(argstr) if x.strip() not in ("", ",")]
+
+
def _parse_line(line):
line_re = r"""
((?P<multi> ([0-9]+)) : )? # the optional multi-index
@@ -86,38 +105,9 @@ def _parse_line(line):
( -> (?P<returntype> .*) )? # the optional return type
$
"""
- ret = re.match(line_re, line, re.VERBOSE).groupdict()
- arglist = ret["arglist"]
- # The following is a split re. The string is broken into pieces which are
- # between the recognized strings. Because the re has groups, both the
- # strings and the delimiters are returned, where the strings are not
- # interesting at all: They are just the commata.
- # Note that it is necessary to put the characters with special handling in
- # the first group (comma, brace, angle bracket).
- # Then they are not recognized there, and we can handle them differently
- # in the following expressions.
- arglist = list(x.strip() for x in re.split(r"""
- (
- (?: # inner group is not capturing
- [^,()<>] # no commas or braces or angle brackets
- |
- \(
- (?:
- [^()]* # or one brace pair
- |
- \(
- [^()]* # or doubls nested pair
- \)
- )*
- \)
- |
- < # or one angle bracket pair
- [^<>]*
- >
- )+ # longest possible span
- ) # this list is interspersed with "," and surrounded by ""
- """, arglist, flags=re.VERBOSE)
- if x.strip() not in ("", ","))
+ ret = SimpleNamespace(**re.match(line_re, line, re.VERBOSE).groupdict())
+ argstr = ret.arglist
+ arglist = _parse_arglist(argstr)
args = []
for arg in arglist:
name, ann = arg.split(":")
@@ -131,15 +121,16 @@ def _parse_line(line):
else:
tup = name, ann
args.append(tup)
- ret["arglist"] = args
- multi = ret["multi"]
+ ret.arglist = args
+ multi = ret.multi
if multi is not None:
- ret["multi"] = int(multi)
- funcname = ret["funcname"]
+ ret.multi = int(multi)
+ funcname = ret.funcname
parts = funcname.split(".")
if parts[-1] in keyword.kwlist:
- ret["funcname"] = funcname + "_"
- return ret
+ ret.funcname = funcname + "_"
+ return vars(ret)
+
def make_good_value(thing, valtype):
try:
@@ -153,6 +144,7 @@ def make_good_value(thing, valtype):
except Exception:
pass
+
def try_to_guess(thing, valtype):
if "." not in thing and "(" not in thing:
text = "{}.{}".format(valtype, thing)
@@ -172,9 +164,15 @@ def try_to_guess(thing, valtype):
return ret
return None
+
def _resolve_value(thing, valtype, line):
if thing in ("0", "None") and valtype:
- thing = "zero({})".format(valtype)
+ if valtype.startswith("PySide2."):
+ return None
+ map = type_map[valtype]
+ # typing.Any: '_SpecialForm' object has no attribute '__name__'
+ name = map.__name__ if hasattr(map, "__name__") else str(map)
+ thing = "zero({})".format(name)
if thing in type_map:
return type_map[thing]
res = make_good_value(thing, valtype)
@@ -192,40 +190,126 @@ def _resolve_value(thing, valtype, line):
""".format(thing, line), RuntimeWarning)
return thing
+
def _resolve_arraytype(thing, line):
- thing = thing[:-2]
- if thing.endswith("[]"):
+ search = re.search(r"\[(\d*)\]$", thing)
+ thing = thing[:search.start()]
+ if thing.endswith("]"):
thing = _resolve_arraytype(thing, line)
- # this mapping is in shiboken
- thing = "QList[" + thing + "]"
+ if search.group(1):
+ # concrete array, use a tuple
+ nelem = int(search.group(1))
+ thing = ", ".join([thing] * nelem)
+ thing = "Tuple[" + thing + "]"
+ else:
+ thing = "QList[" + thing + "]"
return thing
+
def to_string(thing):
if isinstance(thing, str):
return thing
if hasattr(thing, "__name__"):
- dot = "." in str(type(thing))
+ dot = "." in str(thing)
return thing.__module__ + "." + thing.__name__ if dot else thing.__name__
# Note: This captures things from the typing module:
return str(thing)
-def _resolve_type(thing, line):
- if thing.endswith("[]"):
- thing = _resolve_arraytype(thing, line)
+
+matrix_pattern = "PySide2.QtGui.QGenericMatrix"
+
+def handle_matrix(arg):
+ n, m, typstr = tuple(map(lambda x:x.strip(), arg.split(",")))
+ assert typstr == "float"
+ result = "PySide2.QtGui.QMatrix{n}x{m}".format(**locals())
+ return eval(result, namespace)
+
+
+debugging_aid = """
+from inspect import currentframe
+
+def lno(level):
+ lineno = currentframe().f_back.f_lineno
+ spaces = level * " "
+ return "{lineno}{spaces}".format(**locals())
+"""
+
+
+def _resolve_type(thing, line, level, var_handler):
+ # Capture total replacements, first. Happens in
+ # "PySide2.QtCore.QCborStreamReader.StringResult[PySide2.QtCore.QByteArray]"
+ if thing in type_map:
+ return type_map[thing]
+ # Now the nested structures are handled.
if "[" in thing:
+ # handle primitive arrays
+ if re.search(r"\[\d*\]$", thing):
+ thing = _resolve_arraytype(thing, line)
# Handle a container return type. (see PYSIDE-921 in cppgenerator.cpp)
contr, thing = re.match(r"(.*?)\[(.*?)\]$", thing).groups()
- contr = to_string(_resolve_type(contr, line))
- thing = to_string(_resolve_type(thing, line))
+ # Special case: Handle the generic matrices.
+ if contr == matrix_pattern:
+ return handle_matrix(thing)
+ contr = var_handler(_resolve_type(contr, line, level+1, var_handler))
+ if isinstance(contr, _NotCalled):
+ raise SystemError("Container types must exist:", repr(contr))
+ contr = to_string(contr)
+ pieces = []
+ for part in _parse_arglist(thing):
+ part = var_handler(_resolve_type(part, line, level+1, var_handler))
+ if isinstance(part, _NotCalled):
+ # fix the tag (i.e. "Missing") by repr
+ part = repr(part)
+ pieces.append(to_string(part))
+ thing = ", ".join(pieces)
result = "{contr}[{thing}]".format(**locals())
- if not isinstance(thing, _NotCalled):
- result = eval(result, namespace)
- return result
+ return eval(result, namespace)
return _resolve_value(thing, None, line)
+
+def _handle_generic(obj, repl):
+ """
+ Assign repl if obj is an ArrayLikeVariable
+
+ This is a neat trick. Example:
+
+ obj repl result
+ ---------------------- -------- ---------
+ ArrayLikeVariable List List
+ ArrayLikeVariable(str) List List[str]
+ ArrayLikeVariable Sequence Sequence
+ ArrayLikeVariable(str) Sequence Sequence[str]
+ """
+ if isinstance(obj, ArrayLikeVariable):
+ return repl[obj.type]
+ if isinstance(obj, type) and issubclass(obj, ArrayLikeVariable):
+ # was "if obj is ArrayLikeVariable"
+ return repl
+ return obj
+
+
+def handle_argvar(obj):
+ """
+ Decide how array-like variables are resolved in arguments
+
+ Currently, the best approximation is types.Sequence.
+ We want to change that to types.Iterable in the near future.
+ """
+ return _handle_generic(obj, typing.Sequence)
+
+
+def handle_retvar(obj):
+ """
+ Decide how array-like variables are resolved in results
+
+ This will probably stay typing.List forever.
+ """
+ return _handle_generic(obj, typing.List)
+
+
def calculate_props(line):
- res = _parse_line(line)
- arglist = res["arglist"]
+ parsed = SimpleNamespace(**_parse_line(line.strip()))
+ arglist = parsed.arglist
annotations = {}
_defaults = []
for idx, tup in enumerate(arglist):
@@ -236,27 +320,85 @@ def calculate_props(line):
ann = 'NULL' # maps to None
tup = name, ann
arglist[idx] = tup
- annotations[name] = _resolve_type(ann, line)
+ annotations[name] = _resolve_type(ann, line, 0, handle_argvar)
if len(tup) == 3:
default = _resolve_value(tup[2], ann, line)
_defaults.append(default)
defaults = tuple(_defaults)
- returntype = res["returntype"]
+ returntype = parsed.returntype
if returntype is not None:
- annotations["return"] = _resolve_type(returntype, line)
- props = {}
- props["defaults"] = defaults
- props["kwdefaults"] = {}
- props["annotations"] = annotations
- props["varnames"] = varnames = tuple(tup[0] for tup in arglist)
- funcname = res["funcname"]
- props["fullname"] = funcname
+ annotations["return"] = _resolve_type(returntype, line, 0, handle_retvar)
+ props = SimpleNamespace()
+ props.defaults = defaults
+ props.kwdefaults = {}
+ props.annotations = annotations
+ props.varnames = varnames = tuple(tup[0] for tup in arglist)
+ funcname = parsed.funcname
+ props.fullname = funcname
shortname = funcname[funcname.rindex(".")+1:]
- props["name"] = shortname
- props["multi"] = res["multi"]
- return props
+ props.name = shortname
+ props.multi = parsed.multi
+ fix_variables(props, line)
+ return vars(props)
+
+
+def fix_variables(props, line):
+ annos = props.annotations
+ if not any(isinstance(ann, (ResultVariable, ArrayLikeVariable))
+ for ann in annos.values()):
+ return
+ retvar = annos.get("return", None)
+ if retvar and isinstance(retvar, (ResultVariable, ArrayLikeVariable)):
+ # Special case: a ResultVariable which is the result will always be an array!
+ annos["return"] = retvar = typing.List[retvar.type]
+ fullname = props.fullname
+ varnames = list(props.varnames)
+ defaults = list(props.defaults)
+ diff = len(varnames) - len(defaults)
+
+ safe_annos = annos.copy()
+ retvars = [retvar] if retvar else []
+ deletions = []
+ for idx, name in enumerate(varnames):
+ ann = safe_annos[name]
+ if isinstance(ann, ArrayLikeVariable):
+ ann = typing.Sequence[ann.type]
+ annos[name] = ann
+ if not isinstance(ann, ResultVariable):
+ continue
+ # We move the variable to the end and remove it.
+ retvars.append(ann.type)
+ deletions.append(idx)
+ del annos[name]
+ for idx in reversed(deletions):
+ # varnames: 0 1 2 3 4 5 6 7
+ # defaults: 0 1 2 3 4
+ # diff: 3
+ del varnames[idx]
+ if idx >= diff:
+ del defaults[idx - diff]
+ else:
+ diff -= 1
+ if retvars:
+ rvs = []
+ retvars = list(handle_retvar(rv) if isinstance(rv, ArrayLikeVariable) else rv
+ for rv in retvars)
+ if len(retvars) == 1:
+ returntype = retvars[0]
+ else:
+ typestr = "typing.Tuple[{}]".format(", ".join(map(to_string, retvars)))
+ returntype = eval(typestr, namespace)
+ props.annotations["return"] = returntype
+ props.varnames = tuple(varnames)
+ props.defaults = tuple(defaults)
+
def fixup_multilines(lines):
+ """
+ Multilines can collapse when certain distinctions between C++ types
+ vanish after mapping to Python.
+ This function fixes this by re-computing multiline-ness.
+ """
res = []
multi_lines = []
for line in lines:
@@ -280,6 +422,7 @@ def fixup_multilines(lines):
res.append(line)
return res
+
def pyside_type_init(type_key, sig_strings):
dprint()
dprint("Initialization of type key '{}'".format(type_key))
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py
index dba8f8c7..786a84ec 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py
@@ -1996,6 +1996,21 @@ class DefaultDict(collections.defaultdict, MutableMapping[KT, VT]):
return _generic_new(collections.defaultdict, cls, *args, **kwds)
+############################
+# Insertion by CT 2019-02-21
+#
+class OrderedDict(collections.OrderedDict, MutableMapping[KT, VT]):
+ __slots__ = ()
+ __extra__ = collections.OrderedDict
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is OrderedDict:
+ return collections.OrderedDict(*args, **kwds)
+ return _generic_new(collections.OrderedDict, cls, *args, **kwds)
+#
+############################
+
+
class Counter(collections.Counter, Dict[T, int]):
__slots__ = ()
__extra__ = collections.Counter
diff --git a/sources/shiboken2/tests/minimalbinding/brace_pattern_test.py b/sources/shiboken2/tests/minimalbinding/brace_pattern_test.py
new file mode 100644
index 00000000..89df998e
--- /dev/null
+++ b/sources/shiboken2/tests/minimalbinding/brace_pattern_test.py
@@ -0,0 +1,121 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from __future__ import absolute_import, print_function
+
+import re
+import sys
+import os
+
+import shiboken2
+type.__signature__ # trigger bootstrap
+
+from shibokensupport.signature.lib.tool import build_brace_pattern
+import unittest
+
+"""
+This test tests the brace pattern from signature.lib.tool
+against a slower reference implementation.
+The pattern is crucial, because it is used heavily in signature.parser .
+"""
+
+# A slow reference parser for braces and strings
+def check(s):
+ open, close = "[{(<", "]})>"
+ escape, quote = "\\", '"'
+ instring = blind = False
+ stack = []
+ for c in s:
+ if instring:
+ if blind:
+ blind = False
+ elif c == escape:
+ blind = True
+ elif c == quote:
+ instring = False
+ stack.pop()
+ continue
+ if c in open:
+ stack.append(c)
+ elif c in close:
+ pos = close.index(c)
+ if ((len(stack) > 0) and
+ (open[pos] == stack[len(stack)-1])):
+ stack.pop()
+ else:
+ return False
+ elif c == escape:
+ return False
+ elif c == quote:
+ instring = True
+ stack.append(c)
+ return len(stack) == 0
+
+
+class TestBracePattern(unittest.TestCase):
+ tests = [
+ (r'{[]{()}}', True),
+ (r'[{}{})(]', False),
+ (r'[{}{} ")(" ]', True),
+ (r'[{}{} ")(\" ]', False),
+ (r'[{}{} ")(\" ]"]', True),
+ (r'a < b ( c [ d { "} \"\"}" } ] ) >', True),
+ (r'a < b ( c [ d { } ] ) >', True),
+ (r'a < b ( c [ d { "huh" } ] ) >', True),
+ (r'a < b ( c [ d { "huh\" \" \\\"" } ] ) >', True),
+ ]
+
+ def test_checkfunc(self):
+ for test, result in self.tests:
+ if result:
+ self.assertTrue(check(test))
+ else:
+ self.assertFalse(check(test))
+
+ def test_the_brace_pattern(self):
+ func = re.compile(build_brace_pattern(5) + "$", re.VERBOSE).match
+ for test, result in self.tests:
+ if result:
+ self.assertTrue(func(test))
+ else:
+ self.assertFalse(func(test))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken2/tests/samplebinding/pointerprimitivetype_test.py b/sources/shiboken2/tests/samplebinding/pointerprimitivetype_test.py
new file mode 100644
index 00000000..c4077086
--- /dev/null
+++ b/sources/shiboken2/tests/samplebinding/pointerprimitivetype_test.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+"""
+pointerprimitivetype_test.py
+
+check that the primitive types are correctly mapped by the signature module.
+
+Mapping
+-------
+IntArray2(const int*) -- <Signature (self, data: typing.Sequence)>
+getMargins(int*,int*,int*,int*)const -- <Signature (self) -> typing.Tuple[int, int, int, int]>
+
+We explicitly check only against typing.Iterable in the first test,
+because typing.Sequence is a subclass, but we will generalize this
+to typing.Iterable in the future.
+"""
+
+import unittest
+from sample import IntArray2, VirtualMethods
+
+import shiboken2
+type.__signature__ # trigger init, which does not happen in tests
+from shibokensupport.signature import typing
+
+
+class PointerPrimitiveTypeTest(unittest.TestCase):
+
+ def testArraySignature(self):
+ # signature="IntArray2(const int*)"
+ found = False
+ for sig in IntArray2.__signature__:
+ if "data" in sig.parameters:
+ found = True
+ break
+ self.assertTrue(found)
+ ann = sig.parameters["data"].annotation
+ self.assertEqual(ann.__args__, (int,))
+ # un-specify this class (forget "int") by setting the _special
+ # flag, so we can check using issubclass (undocumented feature).
+ ann._special = True
+ self.assertTrue(issubclass(ann, typing.Iterable))
+
+ def testReturnVarSignature(self):
+ # signature="getMargins(int*,int*,int*,int*)const">
+ ann = VirtualMethods.getMargins.__signature__.return_annotation
+ self.assertEqual(ann, typing.Tuple[int, int, int, int])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/testing/wheel_tester.py b/testing/wheel_tester.py
index 180526b3..535cb371 100644
--- a/testing/wheel_tester.py
+++ b/testing/wheel_tester.py
@@ -53,6 +53,7 @@ directory (e.g. setup.py bdist_wheel was already executed).
"""
from __future__ import print_function, absolute_import
+from argparse import ArgumentParser, RawTextHelpFormatter
import os, sys
try:
@@ -327,12 +328,13 @@ def try_build_examples():
run_make()
-def run_wheel_tests():
+def run_wheel_tests(install_wheels):
wheels_dir = get_wheels_dir()
py_version = sys.version_info[0]
- log.info("Attempting to install wheels.\n")
- try_install_wheels(wheels_dir, py_version)
+ if install_wheels:
+ log.info("Attempting to install wheels.\n")
+ try_install_wheels(wheels_dir, py_version)
log.info("Attempting to build examples.\n")
try_build_examples()
@@ -341,4 +343,10 @@ def run_wheel_tests():
if __name__ == "__main__":
- run_wheel_tests()
+ parser = ArgumentParser(description="wheel_tester",
+ formatter_class=RawTextHelpFormatter)
+ parser.add_argument('--no-install-wheels', '-n', action='store_true',
+ help='Do not install wheels'
+ ' (for developer builds with virtualenv)')
+ options = parser.parse_args()
+ run_wheel_tests(not options.no_install_wheels)