aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2020-10-14 20:34:46 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2020-10-14 20:34:46 +0200
commit68ec9c643abf30cf22b9932ec82098cdebc08b98 (patch)
tree18e6db70e971b3e437145183d07ed017933ab64d
parent30724622333ffc8bce61f7e19217977eebbf9564 (diff)
parentb0da5a06e147b02af0bf2d69364e3bfcc04327d5 (diff)
Merge remote-tracking branch 'origin/5.15' into dev
-rw-r--r--build_scripts/main.py114
-rw-r--r--build_scripts/options.py225
-rw-r--r--build_scripts/setup_runner.py8
-rw-r--r--build_scripts/wheel_override.py22
-rw-r--r--sources/pyside2/libpyside/pysideproperty.cpp225
-rw-r--r--sources/pyside2/libpyside/pysideproperty_p.h1
-rw-r--r--sources/pyside2/tests/QtCore/qproperty_decorator.py4
-rw-r--r--sources/pyside2/tests/pysidetest/CMakeLists.txt1
-rw-r--r--sources/pyside2/tests/pysidetest/property_python_test.py232
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp86
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp67
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h21
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp4
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase.cpp15
-rw-r--r--sources/shiboken2/generator/generator.cpp5
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp2
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp38
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.cpp9
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.cpp34
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp11
20 files changed, 815 insertions, 309 deletions
diff --git a/build_scripts/main.py b/build_scripts/main.py
index 8429c1fdb..84628d8e0 100644
--- a/build_scripts/main.py
+++ b/build_scripts/main.py
@@ -48,7 +48,7 @@ from textwrap import dedent
import time
from .config import config
from .utils import get_python_dict
-from .options import OPTION
+from .options import DistUtilsCommandMixin, OPTION
from .wheel_utils import (get_package_version, get_qt_version,
get_package_timestamp, macos_plat_name,
macos_pyside_min_deployment_target)
@@ -284,57 +284,6 @@ def check_allowed_python_version():
qt_src_dir = ''
-if OPTION["QT_VERSION"] is None:
- OPTION["QT_VERSION"] = "5"
-if OPTION["QMAKE"] is None:
- OPTION["QMAKE"] = find_executable("qmake-qt5")
-if OPTION["QMAKE"] is None:
- OPTION["QMAKE"] = find_executable("qmake")
-
-# make qtinfo.py independent of relative paths.
-if OPTION["QMAKE"] is not None and os.path.exists(OPTION["QMAKE"]):
- OPTION["QMAKE"] = os.path.abspath(OPTION["QMAKE"])
-if OPTION["CMAKE"] is not None and os.path.exists(OPTION["CMAKE"]):
- OPTION["CMAKE"] = os.path.abspath(OPTION["CMAKE"])
-
-if len(OPTION["QMAKE"]) == 0:
- print("qmake could not be found.")
- sys.exit(1)
-if not os.path.exists(OPTION["QMAKE"]):
- print("'{}' does not exist.".format(OPTION["QMAKE"]))
- sys.exit(1)
-
-if OPTION["CMAKE"] is None:
- OPTION["CMAKE"] = find_executable("cmake")
-
-if OPTION["CMAKE"] is None:
- print("cmake could not be found.")
- sys.exit(1)
-if not os.path.exists(OPTION["CMAKE"]):
- print("'{}' does not exist.".format(OPTION["CMAKE"]))
- sys.exit(1)
-
-# First element is default
-available_mkspecs = ["msvc", "mingw", "ninja"] if sys.platform == "win32" else ["make", "ninja"]
-
-if OPTION["MAKESPEC"] is None:
- OPTION["MAKESPEC"] = available_mkspecs[0]
-
-if OPTION["MAKESPEC"] not in available_mkspecs:
- print('Invalid option --make-spec "{}". Available values are {}'.format(OPTION["MAKESPEC"],
- available_mkspecs))
- sys.exit(1)
-
-if OPTION["JOBS"]:
- if sys.platform == 'win32' and OPTION["NO_JOM"]:
- print("Option --jobs can only be used with jom on Windows.")
- sys.exit(1)
- else:
- if not OPTION["JOBS"].startswith('-j'):
- OPTION["JOBS"] = '-j' + OPTION["JOBS"]
-else:
- OPTION["JOBS"] = ''
-
def is_debug_python():
return getattr(sys, "gettotalrefcount", None) is not None
@@ -357,10 +306,41 @@ def prefix():
return name
-# Single global instance of QtInfo to be used later in multiple code
-# paths.
-qtinfo = QtInfo()
-qtinfo.setup(OPTION["QMAKE"], OPTION["QT_VERSION"])
+# Initialize, pull and checkout submodules
+def prepare_sub_modules():
+ print("Initializing submodules for PySide2 version: {}".format(
+ get_package_version()))
+ submodules_dir = os.path.join(setup_script_dir, "sources")
+
+ # Create list of [name, desired branch, absolute path, desired
+ # branch] and determine whether all submodules are present
+ need_init_sub_modules = False
+
+ for m in submodules:
+ module_name = m[0]
+ module_dir = m[1] if len(m) > 1 else ''
+ module_dir = os.path.join(submodules_dir, module_dir, module_name)
+ # Check for non-empty directory (repository checked out)
+ if not os.listdir(module_dir):
+ need_init_sub_modules = True
+ break
+
+ if need_init_sub_modules:
+ git_update_cmd = ["git", "submodule", "update", "--init"]
+ if run_process(git_update_cmd) != 0:
+ m = "Failed to initialize the git submodules: update --init failed"
+ raise DistutilsSetupError(m)
+ git_pull_cmd = ["git", "submodule", "foreach", "git", "fetch", "--all"]
+ if run_process(git_pull_cmd) != 0:
+ m = "Failed to initialize the git submodules: git fetch --all failed"
+ raise DistutilsSetupError(m)
+ else:
+ print("All submodules present.")
+
+ git_update_cmd = ["git", "submodule", "update"]
+ if run_process(git_update_cmd) != 0:
+ m = "Failed to checkout the correct git submodules SHA1s."
+ raise DistutilsSetupError(m)
def prepare_build():
@@ -377,7 +357,7 @@ def prepare_build():
# locate Qt sources for the documentation
if OPTION["QT_SRC"] is None:
- install_prefix = qtinfo.prefix_dir
+ install_prefix = QtInfo().prefix_dir
if install_prefix:
global qt_src_dir
# In-source, developer build
@@ -387,9 +367,13 @@ def prepare_build():
qt_src_dir = os.path.join(os.path.dirname(install_prefix), 'Src', 'qtbase')
-class PysideInstall(_install):
+class PysideInstall(_install, DistUtilsCommandMixin):
+
+ user_options = _install.user_options + DistUtilsCommandMixin.mixin_user_options
+
def __init__(self, *args, **kwargs):
_install.__init__(self, *args, **kwargs)
+ DistUtilsCommandMixin.__init__(self)
def initialize_options(self):
_install.initialize_options(self)
@@ -408,6 +392,10 @@ class PysideInstall(_install):
# similar cases.
self.warn_dir = False
+ def finalize_options(self):
+ DistUtilsCommandMixin.mixin_finalize_options(self)
+ _install.finalize_options(self)
+
def run(self):
_install.run(self)
print('--- Install completed ({}s)'.format(elapsed()))
@@ -471,13 +459,17 @@ class PysideInstallLib(_install_lib):
return outfiles
-class PysideBuild(_build):
+class PysideBuild(_build, DistUtilsCommandMixin):
+
+ user_options = _build.user_options + DistUtilsCommandMixin.mixin_user_options
def __init__(self, *args, **kwargs):
_build.__init__(self, *args, **kwargs)
+ DistUtilsCommandMixin.__init__(self)
def finalize_options(self):
os_name_backup = os.name
+ DistUtilsCommandMixin.mixin_finalize_options(self)
if sys.platform == 'darwin':
self.plat_name = macos_plat_name()
# This is a hack to circumvent the dubious check in
@@ -498,7 +490,6 @@ class PysideBuild(_build):
_build.initialize_options(self)
self.make_path = None
self.make_generator = None
- self.debug = False
self.script_dir = None
self.sources_dir = None
self.build_dir = None
@@ -543,7 +534,7 @@ class PysideBuild(_build):
py_scripts_dir = os.path.join(py_prefix, "bin")
self.py_scripts_dir = py_scripts_dir
- self.qtinfo = qtinfo
+ self.qtinfo = QtInfo()
qt_dir = os.path.dirname(OPTION["QMAKE"])
qt_version = get_qt_version()
@@ -583,7 +574,6 @@ class PysideBuild(_build):
self.make_path = make_path
self.make_generator = make_generator
- self.debug = OPTION["DEBUG"]
self.script_dir = script_dir
self.st_build_dir = os.path.join(self.script_dir, self.build_lib)
self.sources_dir = sources_dir
diff --git a/build_scripts/options.py b/build_scripts/options.py
index db2a7e367..eb5d438a0 100644
--- a/build_scripts/options.py
+++ b/build_scripts/options.py
@@ -38,10 +38,27 @@
#############################################################################
from __future__ import print_function
+import distutils.log as log
+from distutils.spawn import find_executable
import sys
import os
import warnings
+from .qtinfo import QtInfo
+
+
+_AVAILABLE_MKSPECS = ["msvc", "mingw", "ninja"] if sys.platform == "win32" else ["make", "ninja"]
+
+
+# Global options not which are not part of the commands
+ADDITIONAL_OPTIONS = """
+Additional options:
+ --limited-api Use Limited API [yes/no]
+ ---macos-use-libc++ Use libc++ on macOS
+ --snapshot-build Snapshot build
+ --package-timestamp Package Timestamp
+"""
+
def _warn_multiple_option(option):
warnings.warn('Option "{}" occurs multiple times on the command line.'.format(option))
@@ -132,60 +149,192 @@ def option_value(*args, **kwargs):
return options.option_value(*args, **kwargs)
-# Declare options
+def _jobs_option_value():
+ """Option value for parallel builds."""
+ value = option_value('parallel', short_option_name='j')
+ if value:
+ return '-j' + value if not value.startswith('-j') else value
+ return ''
+
+
+# Declare options which need to be known when instantiating the DistUtils
+# commands.
OPTION = {
"BUILD_TYPE": option_value("build-type"),
"INTERNAL_BUILD_TYPE": option_value("internal-build-type"),
- "DEBUG": has_option("debug"),
- "RELWITHDEBINFO": has_option('relwithdebinfo'),
- "QMAKE": option_value("qmake"),
- "QT_VERSION": option_value("qt"),
- "CMAKE": option_value("cmake"),
- "OPENSSL": option_value("openssl"),
- "SHIBOKEN_CONFIG_DIR": option_value("shiboken-config-dir"),
- "ONLYPACKAGE": has_option("only-package"),
- "STANDALONE": has_option("standalone"),
- "MAKESPEC": option_value("make-spec"),
- "IGNOREGIT": has_option("ignore-git"),
- # don't generate documentation
- "SKIP_DOCS": has_option("skip-docs"),
- # don't include pyside2-examples
- "NOEXAMPLES": has_option("no-examples"),
# number of parallel build jobs
- "JOBS": option_value('parallel', short_option_name='j'),
+ "JOBS": _jobs_option_value(),
# Legacy, not used any more.
"JOM": has_option('jom'),
- # Do not use jom instead of nmake with msvc
- "NO_JOM": has_option('no-jom'),
- "BUILDTESTS": has_option("build-tests"),
- "MACOS_ARCH": option_value("macos-arch"),
"MACOS_USE_LIBCPP": has_option("macos-use-libc++"),
- "MACOS_SYSROOT": option_value("macos-sysroot"),
- "MACOS_DEPLOYMENT_TARGET": option_value("macos-deployment-target"),
- "XVFB": has_option("use-xvfb"),
- "REUSE_BUILD": has_option("reuse-build"),
- "SKIP_CMAKE": has_option("skip-cmake"),
- "SKIP_MAKE_INSTALL": has_option("skip-make-install"),
- "SKIP_PACKAGING": has_option("skip-packaging"),
- "SKIP_MODULES": option_value("skip-modules"),
- "MODULE_SUBSET": option_value("module-subset"),
- "RPATH_VALUES": option_value("rpath"),
- "QT_CONF_PREFIX": option_value("qt-conf-prefix"),
- "QT_SRC": option_value("qt-src-dir"),
"QUIET": has_option('quiet', remove=False),
- "VERBOSE_BUILD": has_option("verbose-build"),
- "SANITIZE_ADDRESS": has_option("sanitize-address"),
"SNAPSHOT_BUILD": has_option("snapshot-build"),
"LIMITED_API": option_value("limited-api"),
"PACKAGE_TIMESTAMP": option_value("package-timestamp"),
- "SHORTER_PATHS": has_option("shorter-paths"),
# This is used automatically by distutils.command.install object, to
# specify the final installation location.
- "FINAL_INSTALL_PREFIX": option_value("prefix", remove=False),
+ "FINAL_INSTALL_PREFIX": option_value("prefix", remove=False)
# This is used to identify the template for doc builds
- "DOC_BUILD_ONLINE": has_option("doc-build-online"),
}
_deprecated_option_jobs = option_value('jobs')
if _deprecated_option_jobs:
_warn_deprecated_option('jobs', 'parallel')
OPTION["JOBS"] = _deprecated_option_jobs
+
+
+class DistUtilsCommandMixin(object):
+ """Mixin for the DistUtils build/install commands handling the options."""
+
+ _finalized = False
+
+ mixin_user_options = [
+ ('debug', None, 'Build with debug information'),
+ ('relwithdebinfo', None, 'Build in release mode with debug information'),
+ ('only-package', None, 'Package only'),
+ ('standalone', None, 'Standalone build'),
+ ('ignore-git', None, 'Do update subrepositories'),
+ ('skip-docs', None, 'Skip documentation build'),
+ ('no-examples', None, 'Do not build examples'),
+ ('no-jom', None, 'Do not use jom (MSVC)'),
+ ('build-tests', None, 'Build tests'),
+ ('use-xvfb', None, 'Use Xvfb for testing'),
+ ('reuse-build', None, 'Reuse existing build'),
+ ('skip-cmake', None, 'Skip CMake step'),
+ ('skip-make-install', None, 'Skip install step'),
+ ('skip-packaging', None, 'Skip packaging step'),
+ ('verbose-build', None, 'Verbose build'),
+ ('sanitize-address', None, 'Build with address sanitizer'),
+ ('shorter-paths', None, 'Use shorter paths'),
+ ('doc-build-online', None, 'Build online documentation'),
+ ('qmake=', None, 'Path to qmake'),
+ ('qt=', None, 'Qt version'),
+ ('cmake=', None, 'Path to CMake'),
+ ('openssl=', None, 'Path to OpenSSL libraries'),
+ ('shiboken-config-dir=', None, 'shiboken configuration directory'),
+ ('make-spec=', None, 'Qt make-spec'),
+ ('macos-arch=', None, 'macOS architecture'),
+ ('macos-sysroot=', None, 'macOS sysroot'),
+ ('macos-deployment-target=', None, 'macOS deployment target'),
+ ('skip-modules=', None, 'Qt modules to be skipped'),
+ ('module-subset=', None, 'Qt modules to be built'),
+ ('rpath=', None, 'RPATH'),
+ ('qt-conf-prefix=', None, 'Qt configuration prefix'),
+ ('qt-src-dir=', None, 'Qt source directory')]
+
+ def __init__(self):
+ self.debug = False
+ self.relwithdebinfo = False
+ self.only_package = False
+ self.standalone = False
+ self.ignore_git = False
+ self.skip_docs = False
+ self.no_examples = False
+ self.no_jom = False
+ self.build_tests = False
+ self.use_xvfb = False
+ self.reuse_build = False
+ self.skip_cmake = False
+ self.skip_make_install = False
+ self.skip_packaging = False
+ self.verbose_build = False
+ self.sanitize_address = False
+ self.snapshot_build = False
+ self.shorter_paths = False
+ self.doc_build_online = False
+ self.qmake = None
+ self.qt = '5'
+ self.cmake = None
+ self.openssl = None
+ self.shiboken_config_dir = None
+ self.make_spec = None
+ self.macos_arch = None
+ self.macos_sysroot = None
+ self.macos_deployment_target = None
+ self.skip_modules = None
+ self.module_subset = None
+ self.rpath = None
+ self.qt_conf_prefix = None
+ self.qt_src_dir = None
+
+ def mixin_finalize_options(self):
+ # Bail out on 2nd call to mixin_finalize_options() since that is the
+ # build command following the install command when invoking
+ # setup.py install
+ if not DistUtilsCommandMixin._finalized:
+ DistUtilsCommandMixin._finalized = True
+ self._do_finalize()
+
+ def _do_finalize(self):
+ if not self._determine_defaults_and_check():
+ sys.exit(-1)
+ OPTION['DEBUG'] = self.debug
+ OPTION['RELWITHDEBINFO'] = self.relwithdebinfo
+ OPTION['ONLYPACKAGE'] = self.only_package
+ OPTION['STANDALONE'] = self.standalone
+ OPTION['IGNOREGIT'] = self.ignore_git
+ OPTION['SKIP_DOCS'] = self.skip_docs
+ OPTION['NOEXAMPLES'] = self.no_examples
+ OPTION['BUILDTESTS'] = self.build_tests
+ OPTION['NO_JOM'] = self.no_jom
+ OPTION['XVFB'] = self.use_xvfb
+ OPTION['REUSE_BUILD'] = self.reuse_build
+ OPTION['SKIP_CMAKE'] = self.skip_cmake
+ OPTION['SKIP_MAKE_INSTALL'] = self.skip_make_install
+ OPTION['SKIP_PACKAGING'] = self.skip_packaging
+ OPTION['VERBOSE_BUILD'] = self.verbose_build
+ if self.verbose_build:
+ log.set_verbosity(1)
+ OPTION['SANITIZE_ADDRESS'] = self.sanitize_address
+ OPTION['SHORTER_PATHS'] = self.shorter_paths
+ OPTION['DOC_BUILD_ONLINE'] = self.doc_build_online
+ # make qtinfo.py independent of relative paths.
+ qmake_abs_path = os.path.abspath(self.qmake)
+ OPTION['QMAKE'] = qmake_abs_path
+ OPTION['QT_VERSION'] = self.qt
+ QtInfo().setup(qmake_abs_path, self.qt)
+ OPTION['CMAKE'] = os.path.abspath(self.cmake)
+ OPTION['OPENSSL'] = self.openssl
+ OPTION['SHIBOKEN_CONFIG_DIR'] = self.shiboken_config_dir
+ OPTION['MAKESPEC'] = self.make_spec
+ OPTION['MACOS_ARCH'] = self.macos_arch
+ OPTION['MACOS_SYSROOT'] = self.macos_sysroot
+ OPTION['MACOS_DEPLOYMENT_TARGET'] = self.macos_deployment_target
+ OPTION['SKIP_MODULES'] = self.skip_modules
+ OPTION['MODULE_SUBSET'] = self.module_subset
+ OPTION['RPATH_VALUES'] = self.rpath
+ OPTION['QT_CONF_PREFIX'] = self.qt_conf_prefix
+ OPTION['QT_SRC'] = self.qt_src_dir
+
+ def _determine_defaults_and_check(self):
+ if not self.cmake:
+ self.cmake = find_executable("cmake")
+ if not self.cmake:
+ print("cmake could not be found.")
+ return False
+ if not os.path.exists(self.cmake):
+ print("'{}' does not exist.".format(self.cmake))
+ return False
+
+ if not self.qmake:
+ self.qmake = find_executable("qmake")
+ if not self.qmake:
+ self.qmake = find_executable("qmake-qt5")
+ if not self.qmake:
+ print("qmake could not be found.")
+ return False
+ if not os.path.exists(self.qmake):
+ print("'{}' does not exist.".format(self.qmake))
+ return False
+
+ if not self.make_spec:
+ self.make_spec = _AVAILABLE_MKSPECS[0]
+ if self.make_spec not in _AVAILABLE_MKSPECS:
+ print('Invalid option --make-spec "{}". Available values are {}'.format(OPTION["MAKESPEC"],
+ _AVAILABLE_MKSPECS))
+ return False
+
+ if OPTION["JOBS"] and sys.platform == 'win32' and self.no_jom:
+ print("Option --jobs can only be used with jom on Windows.")
+ return False
+
+ return True
diff --git a/build_scripts/setup_runner.py b/build_scripts/setup_runner.py
index b54c62796..6b944c2c8 100644
--- a/build_scripts/setup_runner.py
+++ b/build_scripts/setup_runner.py
@@ -46,13 +46,11 @@ import distutils.log as log
from build_scripts.config import config
from build_scripts.main import get_package_version, get_setuptools_extension_modules
from build_scripts.main import cmd_class_dict
-from build_scripts.options import OPTION
+from build_scripts.options import ADDITIONAL_OPTIONS, OPTION
from build_scripts.utils import run_process
from setuptools import setup
-if OPTION["VERBOSE_BUILD"]:
- log.set_verbosity(1)
class SetupRunner(object):
@@ -166,6 +164,10 @@ class SetupRunner(object):
""").format(exit_code, cmd_as_string)
raise RuntimeError(msg)
+ if help_requested:
+ print(ADDITIONAL_OPTIONS)
+
+
@staticmethod
def run_setuptools_setup():
"""
diff --git a/build_scripts/wheel_override.py b/build_scripts/wheel_override.py
index e4147a5bc..20e6f942c 100644
--- a/build_scripts/wheel_override.py
+++ b/build_scripts/wheel_override.py
@@ -40,22 +40,22 @@
wheel_module_exists = False
+import os
+import sys
+from .options import DistUtilsCommandMixin, OPTION
+from distutils import log as logger
+from email.generator import Generator
+from .wheel_utils import get_package_version, get_qt_version, macos_plat_name
+
try:
- import os
- import sys
- from distutils import log as logger
from wheel import pep425tags
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
from wheel.bdist_wheel import safer_name as _safer_name
from wheel.pep425tags import get_abbr_impl, get_impl_ver, get_abi_tag
from wheel.pep425tags import get_platform as wheel_get_platform
- from email.generator import Generator
from wheel import __version__ as wheel_version
- from .options import OPTION
- from .wheel_utils import get_package_version, get_qt_version, macos_plat_name
-
wheel_module_exists = True
except Exception as e:
_bdist_wheel, wheel_version = type, '' # dummy to make class statement happy
@@ -67,12 +67,18 @@ def get_bdist_wheel_override():
return PysideBuildWheel if wheel_module_exists else None
-class PysideBuildWheel(_bdist_wheel):
+class PysideBuildWheel(_bdist_wheel, DistUtilsCommandMixin):
+
+ user_options = (_bdist_wheel.user_options + DistUtilsCommandMixin.mixin_user_options
+ if wheel_module_exists else None)
+
def __init__(self, *args, **kwargs):
self._package_version = None
_bdist_wheel.__init__(self, *args, **kwargs)
+ DistUtilsCommandMixin.__init__(self)
def finalize_options(self):
+ DistUtilsCommandMixin.mixin_finalize_options(self)
if sys.platform == 'darwin':
# Override the platform name to contain the correct
# minimum deployment target.
diff --git a/sources/pyside2/libpyside/pysideproperty.cpp b/sources/pyside2/libpyside/pysideproperty.cpp
index 79464541d..d79a46ade 100644
--- a/sources/pyside2/libpyside/pysideproperty.cpp
+++ b/sources/pyside2/libpyside/pysideproperty.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -47,6 +47,8 @@
#include <shiboken.h>
#include <signature.h>
+using namespace Shiboken;
+
extern "C"
{
@@ -55,25 +57,41 @@ static int qpropertyTpInit(PyObject *, PyObject *, PyObject *);
static void qpropertyDeAlloc(PyObject *self);
//methods
-static PyObject *qPropertyCall(PyObject *, PyObject *, PyObject *);
-static PyObject *qPropertySetter(PyObject *, PyObject *);
static PyObject *qPropertyGetter(PyObject *, PyObject *);
+static PyObject *qPropertySetter(PyObject *, PyObject *);
+static PyObject *qPropertyResetter(PyObject *, PyObject *);
+static PyObject *qPropertyDeleter(PyObject *, PyObject *);
+static PyObject *qPropertyCall(PyObject *, PyObject *, PyObject *);
static int qpropertyTraverse(PyObject *self, visitproc visit, void *arg);
static int qpropertyClear(PyObject *self);
// Attributes
static PyObject *qPropertyDocGet(PyObject *, void *);
+static int qPropertyDocSet(PyObject *, PyObject *, void *);
+static PyObject *qProperty_fget(PyObject *, void *);
+static PyObject *qProperty_fset(PyObject *, void *);
+static PyObject *qProperty_freset(PyObject *, void *);
+static PyObject *qProperty_fdel(PyObject *, void *);
static PyMethodDef PySidePropertyMethods[] = {
- {"setter", (PyCFunction)qPropertySetter, METH_O, 0},
- {"write", (PyCFunction)qPropertySetter, METH_O, 0},
{"getter", (PyCFunction)qPropertyGetter, METH_O, 0},
+ {"setter", (PyCFunction)qPropertySetter, METH_O, 0},
+ {"resetter", (PyCFunction)qPropertyResetter, METH_O, 0},
+ {"deleter", (PyCFunction)qPropertyDeleter, METH_O, 0},
+ // Synonyms from Qt
{"read", (PyCFunction)qPropertyGetter, METH_O, 0},
+ {"write", (PyCFunction)qPropertySetter, METH_O, 0},
{0, 0, 0, 0}
};
static PyGetSetDef PySidePropertyType_getset[] = {
- {const_cast<char *>("__doc__"), qPropertyDocGet, nullptr, nullptr, nullptr},
+ // Note: we could not use `PyMemberDef` like Python's properties,
+ // because of the indirection of PySidePropertyPrivate.
+ {const_cast<char *>("fget"), qProperty_fget, nullptr, nullptr, nullptr},
+ {const_cast<char *>("fset"), qProperty_fset, nullptr, nullptr, nullptr},
+ {const_cast<char *>("freset"), qProperty_freset, nullptr, nullptr, nullptr},
+ {const_cast<char *>("fdel"), qProperty_fdel, nullptr, nullptr, nullptr},
+ {const_cast<char *>("__doc__"), qPropertyDocGet, qPropertyDocSet, nullptr, nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr}
};
@@ -166,21 +184,26 @@ static int qpropertyTpInit(PyObject *self, PyObject *args, PyObject *kwds)
pData->metaCallHandler = &qpropertyMetaCall;
static const char *kwlist[] = {"type", "fget", "fset", "freset", "fdel", "doc", "notify",
- "designable", "scriptable", "stored", "user",
- "constant", "final", 0};
+ "designable", "scriptable", "stored",
+ "user", "constant", "final", 0};
char *doc{};
if (!PyArg_ParseTupleAndKeywords(args, kwds,
- "O|OOOOsObbbbbb:QtCore.QProperty",
+ "O|OOOOsObbbbbb:QtCore.Property",
const_cast<char **>(kwlist),
/*OO*/ &type, &(pData->fget),
/*OOO*/ &(pData->fset), &(pData->freset), &(pData->fdel),
/*s*/ &doc,
/*O*/ &(pData->notify),
- /*bbbbbb*/ &(pData->designable), &(pData->scriptable), &(pData->stored), &(pData->user), &(pData->constant), &(pData->final))) {
+ /*bbb*/ &(pData->designable), &(pData->scriptable), &(pData->stored),
+ /*bbb*/ &(pData->user), &(pData->constant), &(pData->final))) {
return -1;
}
+ // PYSIDE-1019: Fetching the default `__doc__` from fget would fail for inherited functions
+ // because we don't initialize the mro with signatures (and we will not!).
+ // But it is efficient and in-time to do that on demand in qPropertyDocGet.
+ pData->getter_doc = false;
if (doc)
pData->doc = doc;
else
@@ -220,53 +243,107 @@ static void qpropertyDeAlloc(PyObject *self)
Py_TYPE(self)->tp_free(self);
}
-static PyObject *qPropertyCall(PyObject *self, PyObject *args, PyObject * /* kw */)
+static PyObject *
+_property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *reset, PyObject *del)
{
- PyObject *callback = PyTuple_GetItem(args, 0);
- if (PyFunction_Check(callback)) {
- auto prop = reinterpret_cast<PySideProperty *>(self);
- PySidePropertyPrivate *pData = prop->d;
+ PySideProperty *pold = reinterpret_cast<PySideProperty *>(old);
+ PySidePropertyPrivate *pData = pold->d;
- Py_INCREF(callback);
- pData->fget = callback;
+ AutoDecRef type(PyObject_Type(old));
+ QByteArray doc{};
+ if (type.isNull())
+ return nullptr;
- Py_INCREF(self);
- return self;
+ if (get == nullptr || get == Py_None) {
+ Py_XDECREF(get);
+ get = pData->fget ? pData->fget : Py_None;
+ }
+ if (set == nullptr || set == Py_None) {
+ Py_XDECREF(set);
+ set = pData->fset ? pData->fset : Py_None;
+ }
+ if (reset == nullptr || reset == Py_None) {
+ Py_XDECREF(reset);
+ reset = pData->freset ? pData->freset : Py_None;
+ }
+ if (del == nullptr || del == Py_None) {
+ Py_XDECREF(del);
+ del = pData->fdel ? pData->fdel : Py_None;
+ }
+ if (pData->getter_doc && get != Py_None) {
+ /* make _init use __doc__ from getter */
+ doc = "";
+ }
+ else {
+ doc = !pData->doc.isEmpty() ? pData->doc : "";
}
- PyErr_SetString(PyExc_TypeError, "Invalid property usage.");
- return nullptr;
+ auto notify = pData->notify ? pData->notify : Py_None;
+
+ PyObject *typeName = String::fromCString(pData->typeName);
+ PyObject *obNew = PyObject_CallFunction(type, const_cast<char *>("OOOOOsO" "bbb" "bbb"),
+ typeName, get, set, reset, del, doc.data(), notify,
+ pData->designable, pData->scriptable, pData->stored,
+ pData->user, pData->constant, pData->final);
+
+ return obNew;
}
-static PyObject *qPropertySetter(PyObject *self, PyObject *callback)
+static PyObject *qPropertyGetter(PyObject *self, PyObject *getter)
{
- if (PyFunction_Check(callback)) {
- PySideProperty *prop = reinterpret_cast<PySideProperty *>(self);
- PySidePropertyPrivate *pData = prop->d;
+ return _property_copy(self, getter, nullptr, nullptr, nullptr);
+}
- Py_INCREF(callback);
- pData->fset = callback;
+static PyObject *qPropertySetter(PyObject *self, PyObject *setter)
+{
+ return _property_copy(self, nullptr, setter, nullptr, nullptr);
+}
- Py_INCREF(callback);
- return callback;
- }
- PyErr_SetString(PyExc_TypeError, "Invalid property setter agument.");
- return nullptr;
+static PyObject *qPropertyResetter(PyObject *self, PyObject *resetter)
+{
+ return _property_copy(self, nullptr, nullptr, resetter, nullptr);
}
-static PyObject *qPropertyGetter(PyObject *self, PyObject *callback)
+static PyObject *qPropertyDeleter(PyObject *self, PyObject *deleter)
{
- if (PyFunction_Check(callback)) {
- PySideProperty *prop = reinterpret_cast<PySideProperty *>(self);
- PySidePropertyPrivate *pData = prop->d;
+ return _property_copy(self, nullptr, nullptr, nullptr, deleter);
+}
- Py_INCREF(callback);
- pData->fget = callback;
+static PyObject *qPropertyCall(PyObject *self, PyObject *args, PyObject * /* kw */)
+{
+ PyObject *getter = PyTuple_GetItem(args, 0);
+ return _property_copy(self, getter, nullptr, nullptr, nullptr);
+}
- Py_INCREF(callback);
- return callback;
- }
- PyErr_SetString(PyExc_TypeError, "Invalid property getter agument.");
- return nullptr;
+// PYSIDE-1019: Provide the same getters as Pythons `PyProperty`.
+static PyObject *_property_func(PyObject *self, ssize_t offset)
+{
+ auto data = reinterpret_cast<PySideProperty *>(self);
+ PySidePropertyPrivate *pData = data->d;
+ auto funcptr = reinterpret_cast<char *>(pData) + offset;
+ auto func = *reinterpret_cast<PyObject **>(funcptr);
+ auto ret = func != nullptr ? func : Py_None;
+ Py_INCREF(ret);
+ return ret;
+}
+
+static PyObject *qProperty_fget(PyObject *self, void *)
+{
+ return _property_func(self, offsetof(PySidePropertyPrivate, fget));
+}
+
+static PyObject *qProperty_fset(PyObject *self, void *)
+{
+ return _property_func(self, offsetof(PySidePropertyPrivate, fset));
+}
+
+static PyObject *qProperty_freset(PyObject *self, void *)
+{
+ return _property_func(self, offsetof(PySidePropertyPrivate, freset));
+}
+
+static PyObject *qProperty_fdel(PyObject *self, void *)
+{
+ return _property_func(self, offsetof(PySidePropertyPrivate, fdel));
}
static PyObject *qPropertyDocGet(PyObject *self, void *)
@@ -282,9 +359,40 @@ static PyObject *qPropertyDocGet(PyObject *self, void *)
return PyString_FromString(doc);
#endif
}
+ if (pData->fget != nullptr) {
+ // PYSIDE-1019: Fetch the default `__doc__` from fget. We do it late.
+ AutoDecRef get_doc(PyObject_GetAttr(pData->fget, PyMagicName::doc()));
+ if (!get_doc.isNull()) {
+ pData->doc = String::toCString(get_doc);
+ pData->getter_doc = true;
+ if (Py_TYPE(self) == PySidePropertyTypeF())
+ return qPropertyDocGet(self, nullptr);
+ /*
+ * If this is a property subclass, put __doc__ in dict of the
+ * subclass instance instead, otherwise it gets shadowed by
+ * __doc__ in the class's dict.
+ */
+ auto get_doc_obj = get_doc.object();
+ int err = PyObject_SetAttr(self, PyMagicName::doc(), get_doc);
+ return err < 0 ? nullptr : (Py_INCREF(get_doc_obj), get_doc_obj);
+ }
+ PyErr_Clear();
+ }
Py_RETURN_NONE;
}
+static int qPropertyDocSet(PyObject *self, PyObject *value, void *)
+{
+ auto data = reinterpret_cast<PySideProperty *>(self);
+ PySidePropertyPrivate *pData = data->d;
+
+ if (String::check(value)) {
+ pData->doc = String::toCString(value);
+ return 0;
+ }
+ PyErr_SetString(PyExc_TypeError, "String argument expected.");
+ return -1;
+}
static int qpropertyTraverse(PyObject *self, visitproc visit, void *arg)
{
@@ -345,14 +453,20 @@ static PyObject *getFromType(PyTypeObject *type, PyObject *name)
namespace PySide { namespace Property {
static const char *Property_SignatureStrings[] = {
- "PySide2.QtCore.Property(type:type,fget:typing.Callable=None,fset:typing.Callable=None,"
+ "PySide2.QtCore.Property(self,type:type,fget:typing.Callable=None,fset:typing.Callable=None,"
"freset:typing.Callable=None,fdel:typing.Callable=None,doc:str=None,"
"notify:typing.Callable=None,designable:bool=True,scriptable:bool=True,"
- "stored:bool=True,user:bool=False,constant:bool=False,final:bool=False)",
- "PySide2.QtCore.Property.getter(func:typing.Callable)",
- "PySide2.QtCore.Property.read(func:typing.Callable)",
- "PySide2.QtCore.Property.setter(func:typing.Callable)",
- "PySide2.QtCore.Property.write(func:typing.Callable)",
+ "stored:bool=True,user:bool=False,constant:bool=False,final:bool=False)"
+ "->PySide2.QtCore.Property",
+ "PySide2.QtCore.Property.deleter(self,func:typing.Callable)",
+ "PySide2.QtCore.Property.fdel(self)->typing.Callable",
+ "PySide2.QtCore.Property.fget(self)->typing.Callable",
+ "PySide2.QtCore.Property.freset(self)->typing.Callable",
+ "PySide2.QtCore.Property.fset(self)->typing.Callable",
+ "PySide2.QtCore.Property.getter(self,func:typing.Callable)",
+ "PySide2.QtCore.Property.read(self,func:typing.Callable)",
+ "PySide2.QtCore.Property.setter(self,func:typing.Callable)",
+ "PySide2.QtCore.Property.write(self,func:typing.Callable)",
nullptr}; // Sentinel
void init(PyObject *module)
@@ -375,7 +489,7 @@ bool checkType(PyObject *pyObj)
int setValue(PySideProperty *self, PyObject *source, PyObject *value)
{
PyObject *fset = self->d->fset;
- if (fset) {
+ if (fset && value) {
Shiboken::AutoDecRef args(PyTuple_New(2));
PyTuple_SET_ITEM(args, 0, source);
PyTuple_SET_ITEM(args, 1, value);
@@ -383,9 +497,16 @@ int setValue(PySideProperty *self, PyObject *source, PyObject *value)
Py_INCREF(value);
Shiboken::AutoDecRef result(PyObject_CallObject(fset, args));
return (result.isNull() ? -1 : 0);
- } else {
- PyErr_SetString(PyExc_AttributeError, "Attibute read only");
}
+ PyObject *fdel = self->d->fdel;
+ if (fdel) {
+ Shiboken::AutoDecRef args(PyTuple_New(1));
+ PyTuple_SET_ITEM(args, 0, source);
+ Py_INCREF(source);
+ Shiboken::AutoDecRef result(PyObject_CallObject(fdel, args));
+ return (result.isNull() ? -1 : 0);
+ }
+ PyErr_SetString(PyExc_AttributeError, "Attibute read only");
return -1;
}
diff --git a/sources/pyside2/libpyside/pysideproperty_p.h b/sources/pyside2/libpyside/pysideproperty_p.h
index 4db638021..e7b6e4d77 100644
--- a/sources/pyside2/libpyside/pysideproperty_p.h
+++ b/sources/pyside2/libpyside/pysideproperty_p.h
@@ -56,6 +56,7 @@ struct PySidePropertyPrivate
PyObject *freset = nullptr;
PyObject *fdel = nullptr;
PyObject *notify = nullptr;
+ bool getter_doc = false;
QByteArray notifySignature;
QByteArray doc;
bool designable = true;
diff --git a/sources/pyside2/tests/QtCore/qproperty_decorator.py b/sources/pyside2/tests/QtCore/qproperty_decorator.py
index aa31e59c4..c845ac6d3 100644
--- a/sources/pyside2/tests/QtCore/qproperty_decorator.py
+++ b/sources/pyside2/tests/QtCore/qproperty_decorator.py
@@ -47,7 +47,9 @@ class MyObject(QObject):
return self._value
@value.setter
- def valueSet(self, value):
+ # Note: The name of property and setter must be the same, because the
+ # object changes its identity all the time. `valueSet` no longer works.
+ def value(self, value):
self._value = value
diff --git a/sources/pyside2/tests/pysidetest/CMakeLists.txt b/sources/pyside2/tests/pysidetest/CMakeLists.txt
index bbdeb6a98..361f7d541 100644
--- a/sources/pyside2/tests/pysidetest/CMakeLists.txt
+++ b/sources/pyside2/tests/pysidetest/CMakeLists.txt
@@ -160,6 +160,7 @@ PYSIDE_TEST(modelview_test.py)
PYSIDE_TEST(new_inherited_functions_test.py)
PYSIDE_TEST(notify_id.py)
PYSIDE_TEST(properties_test.py)
+PYSIDE_TEST(property_python_test.py)
PYSIDE_TEST(qapp_like_a_macro_test.py)
PYSIDE_TEST(qvariant_test.py)
PYSIDE_TEST(repr_test.py)
diff --git a/sources/pyside2/tests/pysidetest/property_python_test.py b/sources/pyside2/tests/pysidetest/property_python_test.py
new file mode 100644
index 000000000..7df104525
--- /dev/null
+++ b/sources/pyside2/tests/pysidetest/property_python_test.py
@@ -0,0 +1,232 @@
+#############################################################################
+##
+## Copyright (C) 2020 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 for PySide's Property
+==========================
+
+This test is copied from Python's `test_property.py` and adapted to
+the PySide Property implementation.
+
+This test is to ensure maximum compatibility.
+"""
+
+# Test case for property
+# more tests are in test_descr
+
+import os
+import sys
+import unittest
+
+sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from PySide2.QtCore import Property, QObject
+#from PyQt5.QtCore import pyqtProperty as Property, QObject
+
+# This are the original imports.
+import sys
+import unittest
+has_test = False
+try:
+ if sys.version_info[0] >= 3: # This test has no support in Python 2
+ from test import support
+ has_test = True
+except ImportError:
+ pass
+
+class PropertyBase(Exception):
+ pass
+
+class PropertyGet(PropertyBase):
+ pass
+
+class PropertySet(PropertyBase):
+ pass
+
+class PropertyDel(PropertyBase):
+ pass
+
+class BaseClass(QObject):
+ def __init__(self):
+ QObject.__init__(self)
+
+ self._spam = 5
+
+ @Property(object)
+ def spam(self):
+ """BaseClass.getter"""
+ return self._spam
+
+ @spam.setter
+ def spam(self, value):
+ self._spam = value
+
+ @spam.deleter
+ def spam(self):
+ del self._spam
+
+class SubClass(BaseClass):
+
+ @BaseClass.spam.getter
+ def spam(self):
+ """SubClass.getter"""
+ raise PropertyGet(self._spam)
+
+ @spam.setter
+ def spam(self, value):
+ raise PropertySet(self._spam)
+
+ @spam.deleter
+ def spam(self):
+ raise PropertyDel(self._spam)
+
+class PropertyDocBase(object):
+ _spam = 1
+ def _get_spam(self):
+ return self._spam
+ spam = Property(object, _get_spam, doc="spam spam spam")
+
+class PropertyDocSub(PropertyDocBase):
+ @PropertyDocBase.spam.getter
+ def spam(self):
+ """The decorator does not use this doc string"""
+ return self._spam
+
+class PropertySubNewGetter(BaseClass):
+ @BaseClass.spam.getter
+ def spam(self):
+ """new docstring"""
+ return 5
+
+class PropertyNewGetter(QObject):
+ def __init__(self):
+ QObject.__init__(self)
+
+ @Property(object)
+ def spam(self):
+ """original docstring"""
+ return 1
+ @spam.getter
+ def spam(self):
+ """new docstring"""
+ return 8
+
+class PropertyTests(unittest.TestCase):
+ def test_property_decorator_baseclass(self):
+ # see #1620
+ base = BaseClass()
+ self.assertEqual(base.spam, 5)
+ self.assertEqual(base._spam, 5)
+ base.spam = 10
+ self.assertEqual(base.spam, 10)
+ self.assertEqual(base._spam, 10)
+ delattr(base, "spam")
+ self.assertTrue(not hasattr(base, "spam"))
+ self.assertTrue(not hasattr(base, "_spam"))
+ base.spam = 20
+ self.assertEqual(base.spam, 20)
+ self.assertEqual(base._spam, 20)
+
+ def test_property_decorator_subclass(self):
+ # see #1620
+ sub = SubClass()
+ self.assertRaises(PropertyGet, getattr, sub, "spam")
+ self.assertRaises(PropertySet, setattr, sub, "spam", None)
+ self.assertRaises(PropertyDel, delattr, sub, "spam")
+
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
+ def test_property_decorator_subclass_doc(self):
+ sub = SubClass()
+ self.assertEqual(sub.__class__.spam.__doc__, "SubClass.getter")
+
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
+ def test_property_decorator_baseclass_doc(self):
+ base = BaseClass()
+ self.assertEqual(base.__class__.spam.__doc__, "BaseClass.getter")
+
+ def test_property_decorator_doc(self):
+ base = PropertyDocBase()
+ sub = PropertyDocSub()
+ self.assertEqual(base.__class__.spam.__doc__, "spam spam spam")
+ self.assertEqual(sub.__class__.spam.__doc__, "spam spam spam")
+
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
+ def test_property_getter_doc_override(self):
+ newgettersub = PropertySubNewGetter()
+ self.assertEqual(newgettersub.spam, 5)
+ self.assertEqual(newgettersub.__class__.spam.__doc__, "new docstring")
+ newgetter = PropertyNewGetter()
+ self.assertEqual(newgetter.spam, 8)
+ self.assertEqual(newgetter.__class__.spam.__doc__, "new docstring")
+
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
+ def test_property_builtin_doc_writable(self):
+ p = Property(object, doc='basic')
+ self.assertEqual(p.__doc__, 'basic')
+ p.__doc__ = 'extended'
+ self.assertEqual(p.__doc__, 'extended')
+
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
+ def test_property_decorator_doc_writable(self):
+ class PropertyWritableDoc(object):
+
+ @Property(object)
+ def spam(self):
+ """Eggs"""
+ return "eggs"
+
+ sub = PropertyWritableDoc()
+ self.assertEqual(sub.__class__.spam.__doc__, 'Eggs')
+ sub.__class__.spam.__doc__ = 'Spam'
+ self.assertEqual(sub.__class__.spam.__doc__, 'Spam')
+
+ if has_test: # This test has no support in Python 2
+ @support.refcount_test
+ def test_refleaks_in___init__(self):
+ gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount')
+ fake_prop = Property(object, 'fget', 'fset', "freset", 'fdel', 'doc')
+ refs_before = gettotalrefcount()
+ for i in range(100):
+ fake_prop.__init__(object, 'fget', 'fset', "freset", 'fdel', 'doc')
+ self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
+
+
+# Note: We ignore the whole subclass tests concerning __doc__ strings.
+# See the original Python test starting with:
+# "Issue 5890: subclasses of property do not preserve method __doc__ strings"
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
index 70cccebcd..af10f1831 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
@@ -1258,9 +1258,7 @@ void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaF
if (!retType)
return;
- auto *metaType = new AbstractMetaType;
- metaType->setTypeEntry(retType);
- metaFunction->replaceType(metaType);
+ metaFunction->replaceType(new AbstractMetaType(retType));
}
AbstractMetaFunctionList AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem,
@@ -1300,7 +1298,7 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem,
QPropertySpec *read = nullptr;
if (!metaFunction->isSignal() && (read = metaClass->propertySpecForRead(metaFunction->name()))) {
// Property reader must be in the form "<type> name()"
- if (metaFunction->type() && (read->typeEntry() == metaFunction->type()->typeEntry())
+ if (read->typeEntry() == metaFunction->type()->typeEntry()
&& metaFunction->arguments().isEmpty()) {
*metaFunction += AbstractMetaAttributes::PropertyReader;
metaFunction->setPropertySpec(read);
@@ -1309,14 +1307,14 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem,
// Property setter must be in the form "void name(<type>)"
// Make sure the function was created with all arguments; some argument can be
// missing during the parsing because of errors in the typesystem.
- if ((!metaFunction->type()) && (metaFunction->arguments().size() == 1)
+ if (metaFunction->isVoid() && metaFunction->arguments().size() == 1
&& (write->typeEntry() == metaFunction->arguments().at(0)->type()->typeEntry())) {
*metaFunction += AbstractMetaAttributes::PropertyWriter;
metaFunction->setPropertySpec(write);
}
} else if (QPropertySpec *reset = metaClass->propertySpecForReset(metaFunction->name())) {
// Property resetter must be in the form "void name()"
- if ((!metaFunction->type()) && metaFunction->arguments().isEmpty()) {
+ if (metaFunction->isVoid() && metaFunction->arguments().isEmpty()) {
*metaFunction += AbstractMetaAttributes::PropertyResetter;
metaFunction->setPropertySpec(reset);
}
@@ -1516,16 +1514,13 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu
{
QString errorMessage;
- AbstractMetaType *returnType = nullptr;
- if (addedFunc->returnType().name != QLatin1String("void")) {
- returnType = translateType(addedFunc->returnType(), &errorMessage);
- if (!returnType) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgAddedFunctionInvalidReturnType(addedFunc->name(),
- addedFunc->returnType().name,
- errorMessage)));
- return nullptr;
- }
+ AbstractMetaType *returnType = translateType(addedFunc->returnType(), &errorMessage);
+ if (!returnType) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgAddedFunctionInvalidReturnType(addedFunc->name(),
+ addedFunc->returnType().name,
+ errorMessage)));
+ return nullptr;
}
auto metaFunction = new AbstractMetaFunction(addedFunc);
@@ -1806,10 +1801,12 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
QString errorMessage;
switch (metaFunction->functionType()) {
case AbstractMetaFunction::DestructorFunction:
+ metaFunction->setType(AbstractMetaType::createVoid());
break;
case AbstractMetaFunction::ConstructorFunction:
metaFunction->setExplicit(functionItem->isExplicit());
metaFunction->setName(currentClass->name());
+ metaFunction->setType(AbstractMetaType::createVoid());
break;
default: {
TypeInfo returnType = functionItem->type();
@@ -1820,17 +1817,14 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
return nullptr;
}
- AbstractMetaType *type = nullptr;
- if (!returnType.isVoid()) {
- type = translateType(returnType, currentClass, {}, &errorMessage);
- if (!type) {
- const QString reason = msgUnmatchedReturnType(functionItem, errorMessage);
- qCWarning(lcShiboken, "%s",
- qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason)));
- m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType);
- delete metaFunction;
- return nullptr;
- }
+ AbstractMetaType *type = translateType(returnType, currentClass, {}, &errorMessage);
+ if (!type) {
+ const QString reason = msgUnmatchedReturnType(functionItem, errorMessage);
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason)));
+ m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType);
+ delete metaFunction;
+ return nullptr;
}
metaFunction->setType(type);
@@ -1979,7 +1973,7 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction:
QString typeName = typeInfo.name;
if (typeName == QLatin1String("void"))
- return nullptr;
+ return AbstractMetaType::createVoid();
type = typeDb->findType(typeName);
if (!type)
@@ -1989,13 +1983,21 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction:
bool isTemplate = false;
QStringList templateArgs;
if (!type && typeInfo.name.contains(QLatin1Char('<'))) {
- const QStringList& parsedType = parseTemplateType(typeInfo.name);
+ QStringList parsedType = parseTemplateType(typeInfo.name);
if (parsedType.isEmpty()) {
*errorMessage = QStringLiteral("Template type parsing failed for '%1'").arg(typeInfo.name);
return nullptr;
}
- templateArgs = parsedType.mid(1);
- isTemplate = (type = typeDb->findContainerType(parsedType[0]));
+ const QString name = parsedType.takeFirst();
+ templateArgs = parsedType;
+ type = typeDb->findContainerType(name);
+ if (!type) { // A template typedef?
+ if (auto candidate = typeDb->findType(name)) {
+ if (candidate->type() == TypeEntry::ObjectType || candidate->type() == TypeEntry::BasicValueType)
+ type = candidate;
+ }
+ }
+ isTemplate = type != nullptr;
}
if (!type) {
@@ -2021,20 +2023,16 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction:
}
// These are only implicit and should not appear in code...
- auto *metaType = new AbstractMetaType;
- metaType->setTypeEntry(type);
+ auto *metaType = new AbstractMetaType(type);
metaType->setIndirections(typeInfo.indirections);
if (typeInfo.isReference)
metaType->setReferenceType(LValueReference);
metaType->setConstant(typeInfo.isConstant);
if (isTemplate) {
for (const QString& templateArg : qAsConst(templateArgs)) {
- AbstractMetaType *metaArgType = nullptr;
- if (templateArg != QLatin1String("void")) {
- metaArgType = translateType(AddedFunction::TypeInfo::fromSignature(templateArg), errorMessage);
- if (!metaArgType)
- return nullptr;
- }
+ AbstractMetaType *metaArgType = translateType(AddedFunction::TypeInfo::fromSignature(templateArg), errorMessage);
+ if (!metaArgType)
+ return nullptr;
metaType->addInstantiation(metaArgType);
}
metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
@@ -2120,6 +2118,9 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo
TranslateTypeFlags flags,
QString *errorMessageIn)
{
+ if (_typei.isVoid())
+ return AbstractMetaType::createVoid();
+
// 1. Test the type info without resolving typedefs in case this is present in the
// type system
const bool resolveType = !flags.testFlag(AbstractMetaBuilder::DontResolveType);
@@ -2622,7 +2623,7 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
const TypeInfo &info)
{
QVector<TypeInfo> targs = info.instantiations();
- QVector<AbstractMetaType *> templateTypes;
+ AbstractMetaTypeList templateTypes;
QString errorMessage;
if (subclass->isTypeDef()) {
@@ -2665,8 +2666,7 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
}
if (t) {
- auto *temporaryType = new AbstractMetaType;
- temporaryType->setTypeEntry(t);
+ auto *temporaryType = new AbstractMetaType(t);
temporaryType->setConstant(i.isConstant());
temporaryType->setReferenceType(i.referenceType());
temporaryType->setIndirectionsV(i.indirectionsV());
@@ -2692,7 +2692,7 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
QScopedPointer<AbstractMetaFunction> f(function->copy());
f->setArguments(AbstractMetaArgumentList());
- if (function->type()) { // Non-void
+ if (!function->isVoid()) {
AbstractMetaType *returnType = inheritTemplateType(templateTypes, function->type());
if (!returnType)
continue;
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
index f705994f2..2f68dd743 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -186,7 +186,8 @@ void AbstractMetaAttributes::assignMetaAttributes(const AbstractMetaAttributes &
* AbstractMetaType
*/
-AbstractMetaType::AbstractMetaType() :
+AbstractMetaType::AbstractMetaType(const TypeEntry *t) :
+ m_typeEntry(t),
m_constant(false),
m_volatile(false),
m_cppInstantiation(true),
@@ -220,7 +221,7 @@ QString AbstractMetaType::fullName() const
AbstractMetaType *AbstractMetaType::copy() const
{
- auto *cpy = new AbstractMetaType;
+ auto *cpy = new AbstractMetaType(typeEntry());
cpy->setTypeUsagePattern(typeUsagePattern());
cpy->setConstant(isConstant());
@@ -234,8 +235,6 @@ AbstractMetaType *AbstractMetaType::copy() const
cpy->setArrayElementType(arrayElementType() ? arrayElementType()->copy() : nullptr);
- cpy->setTypeEntry(typeEntry());
-
return cpy;
}
@@ -322,8 +321,11 @@ AbstractMetaType::TypeUsagePattern AbstractMetaType::determineUsagePattern() con
if (m_typeEntry->isPrimitive() && (actualIndirections() == 0 || passByConstRef()))
return PrimitivePattern;
- if (m_typeEntry->isVoid())
- return NativePointerPattern;
+ if (m_typeEntry->isVoid()) {
+ return m_arrayElementCount < 0 && m_referenceType == NoReference
+ && m_indirections.isEmpty() && m_constant == 0 && m_volatile == 0
+ ? VoidPattern : NativePointerPattern;
+ }
if (m_typeEntry->isVarargs())
return VarargsPattern;
@@ -413,6 +415,15 @@ bool AbstractMetaType::compare(const AbstractMetaType &rhs, ComparisonFlags flag
return true;
}
+AbstractMetaType *AbstractMetaType::createVoid()
+{
+ static const TypeEntry *voidTypeEntry = TypeDatabase::instance()->findType(QLatin1String("void"));
+ Q_ASSERT(voidTypeEntry);
+ auto *metaType = new AbstractMetaType(voidTypeEntry);
+ metaType->decideUsagePattern();
+ return metaType;
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const AbstractMetaType *at)
{
@@ -647,8 +658,7 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const
cpy->setImplementingClass(implementingClass());
cpy->setFunctionType(functionType());
cpy->setDeclaringClass(declaringClass());
- if (type())
- cpy->setType(type()->copy());
+ cpy->setType(type()->copy());
cpy->setConstant(isConstant());
cpy->setExceptionSpecification(m_exceptionSpecification);
cpy->setAllowThreadModification(m_allowThreadModification);
@@ -658,8 +668,7 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const
for (AbstractMetaArgument *arg : m_arguments)
cpy->addArgument(arg->copy());
- Q_ASSERT((!type() && !cpy->type())
- || (type()->instantiations() == cpy->type()->instantiations()));
+ Q_ASSERT(type()->instantiations() == cpy->type()->instantiations());
return cpy;
}
@@ -668,7 +677,7 @@ bool AbstractMetaFunction::usesRValueReferences() const
{
if (m_functionType == MoveConstructorFunction || m_functionType == MoveAssignmentOperatorFunction)
return true;
- if (m_type && m_type->referenceType() == RValueReference)
+ if (m_type->referenceType() == RValueReference)
return true;
for (const AbstractMetaArgument *a : m_arguments) {
if (a->type()->referenceType() == RValueReference)
@@ -833,8 +842,7 @@ bool AbstractMetaFunction::isDeprecated() const
bool AbstractMetaFunction::autoDetectAllowThread() const
{
// Disallow for simple getter functions.
- const bool maybeGetter = m_constant != 0 && m_type != nullptr
- && m_arguments.isEmpty();
+ const bool maybeGetter = m_constant != 0 && !isVoid() && m_arguments.isEmpty();
return !maybeGetter;
}
@@ -1409,8 +1417,7 @@ AbstractMetaClass::~AbstractMetaClass()
qDeleteAll(m_fields);
qDeleteAll(m_enums);
qDeleteAll(m_propertySpecs);
- if (hasTemplateBaseClassInstantiations())
- qDeleteAll(templateBaseClassInstantiations());
+ qDeleteAll(m_baseTemplateInstantiations);
}
/*******************************************************************************
@@ -1736,28 +1743,20 @@ QPropertySpec *AbstractMetaClass::propertySpecForReset(const QString &name) cons
return nullptr;
}
-using AbstractMetaClassBaseTemplateInstantiationsMap = QHash<const AbstractMetaClass *, AbstractMetaTypeList>;
-Q_GLOBAL_STATIC(AbstractMetaClassBaseTemplateInstantiationsMap, metaClassBaseTemplateInstantiations);
-
bool AbstractMetaClass::hasTemplateBaseClassInstantiations() const
{
- if (!templateBaseClass())
- return false;
- return metaClassBaseTemplateInstantiations()->contains(this);
+ return m_templateBaseClass != nullptr && !m_baseTemplateInstantiations.isEmpty();
}
-AbstractMetaTypeList AbstractMetaClass::templateBaseClassInstantiations() const
+const AbstractMetaTypeList &AbstractMetaClass::templateBaseClassInstantiations() const
{
- if (!templateBaseClass())
- return AbstractMetaTypeList();
- return metaClassBaseTemplateInstantiations()->value(this);
+ return m_baseTemplateInstantiations;
}
-void AbstractMetaClass::setTemplateBaseClassInstantiations(AbstractMetaTypeList &instantiations)
+void AbstractMetaClass::setTemplateBaseClassInstantiations(const AbstractMetaTypeList &instantiations)
{
- if (!templateBaseClass())
- return;
- metaClassBaseTemplateInstantiations()->insert(this, instantiations);
+ Q_ASSERT(m_templateBaseClass != nullptr);
+ m_baseTemplateInstantiations = instantiations;
}
// Does any of the base classes require deletion in the main thread?
@@ -1930,6 +1929,7 @@ bool AbstractMetaClass::hasPrivateCopyConstructor() const
void AbstractMetaClass::addDefaultConstructor()
{
auto *f = new AbstractMetaFunction;
+ f->setType(AbstractMetaType::createVoid());
f->setOriginalName(name());
f->setName(name());
f->setOwnerClass(this);
@@ -1948,14 +1948,14 @@ void AbstractMetaClass::addDefaultConstructor()
void AbstractMetaClass::addDefaultCopyConstructor(bool isPrivate)
{
auto f = new AbstractMetaFunction;
+ f->setType(AbstractMetaType::createVoid());
f->setOriginalName(name());
f->setName(name());
f->setOwnerClass(this);
f->setFunctionType(AbstractMetaFunction::CopyConstructorFunction);
f->setDeclaringClass(this);
- auto argType = new AbstractMetaType;
- argType->setTypeEntry(typeEntry());
+ auto argType = new AbstractMetaType(typeEntry());
argType->setReferenceType(LValueReference);
argType->setConstant(true);
argType->setTypeUsagePattern(AbstractMetaType::ValuePattern);
@@ -2184,8 +2184,7 @@ static void addExtraIncludeForType(AbstractMetaClass *metaClass, const AbstractM
}
if (type->hasInstantiations()) {
- const AbstractMetaTypeList &instantiations = type->instantiations();
- for (const AbstractMetaType *instantiation : instantiations)
+ for (const AbstractMetaType *instantiation : type->instantiations())
addExtraIncludeForType(metaClass, instantiation);
}
}
@@ -2630,7 +2629,7 @@ void AbstractMetaClass::format(QDebug &d) const
d << " \"" << b->name() << '"';
}
if (auto templateBase = templateBaseClass()) {
- const auto instantiatedTypes = templateBaseClassInstantiations();
+ const auto &instantiatedTypes = templateBaseClassInstantiations();
d << ", instantiates \"" << templateBase->name();
for (int i = 0, count = instantiatedTypes.size(); i < count; ++i)
d << (i ? ',' : '<') << instantiatedTypes.at(i)->name();
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h
index df9790a3d..154314d69 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h
@@ -293,7 +293,8 @@ public:
ContainerPattern,
SmartPointerPattern,
VarargsPattern,
- ArrayPattern
+ ArrayPattern,
+ VoidPattern // Plain "void", no "void *" or similar.
};
Q_ENUM(TypeUsagePattern)
@@ -302,7 +303,7 @@ public:
};
Q_DECLARE_FLAGS(ComparisonFlags, ComparisonFlag);
- AbstractMetaType();
+ explicit AbstractMetaType(const TypeEntry *t = nullptr);
AbstractMetaType(const AbstractMetaType &);
~AbstractMetaType();
@@ -341,7 +342,7 @@ public:
}
}
- AbstractMetaTypeList instantiations() const
+ const AbstractMetaTypeList &instantiations() const
{
return m_instantiations;
}
@@ -417,6 +418,8 @@ public:
return m_pattern == FlagsPattern;
}
+ bool isVoid() const { return m_pattern == VoidPattern; }
+
bool isConstant() const
{
return m_constant;
@@ -510,7 +513,7 @@ public:
AbstractMetaType *getSmartPointerInnerType() const
{
Q_ASSERT(isSmartPointer());
- AbstractMetaTypeList instantiations = this->instantiations();
+ const AbstractMetaTypeList &instantiations = this->instantiations();
Q_ASSERT(!instantiations.isEmpty());
AbstractMetaType *innerType = instantiations.at(0);
return innerType;
@@ -537,12 +540,14 @@ public:
const AbstractMetaType *viewOn() const { return m_viewOn; }
void setViewOn(const AbstractMetaType *v) { m_viewOn = v; }
+ static AbstractMetaType *createVoid();
+
private:
TypeUsagePattern determineUsagePattern() const;
QString formatSignature(bool minimal) const;
QString formatPythonSignature() const;
- const TypeEntry *m_typeEntry = nullptr;
+ const TypeEntry *m_typeEntry;
AbstractMetaTypeList m_instantiations;
QString m_package;
mutable QString m_cachedCppSignature;
@@ -887,6 +892,7 @@ public:
bool isModifiedRemoved(int types = TypeSystem::All) const;
+ bool isVoid() const { return m_type->isVoid(); }
AbstractMetaType *type() const
{
return m_type;
@@ -1640,8 +1646,8 @@ public:
}
bool hasTemplateBaseClassInstantiations() const;
- AbstractMetaTypeList templateBaseClassInstantiations() const;
- void setTemplateBaseClassInstantiations(AbstractMetaTypeList& instantiations);
+ const AbstractMetaTypeList &templateBaseClassInstantiations() const;
+ void setTemplateBaseClassInstantiations(const AbstractMetaTypeList& instantiations);
void setTypeDef(bool typeDef) { m_isTypeDef = typeDef; }
bool isTypeDef() const { return m_isTypeDef; }
@@ -1712,6 +1718,7 @@ private:
const AbstractMetaClass *m_enclosingClass = nullptr;
AbstractMetaClassList m_baseClasses; // Real base classes after setting up inheritance
+ AbstractMetaTypeList m_baseTemplateInstantiations;
AbstractMetaClass *m_extendedNamespace = nullptr;
const AbstractMetaClass *m_templateBaseClass = nullptr;
diff --git a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp
index ca4af9a10..a131e7fe2 100644
--- a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp
@@ -145,7 +145,7 @@ void TestAddFunction::testAddFunctionConstructor()
QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::ConstructorFunction);
QCOMPARE(addedFunc->arguments().size(), 1);
QVERIFY(addedFunc->isUserAdded());
- QVERIFY(!addedFunc->type());
+ QVERIFY(addedFunc->isVoid());
}
void TestAddFunction::testAddFunctionTagDefaultValues()
@@ -167,7 +167,7 @@ void TestAddFunction::testAddFunctionTagDefaultValues()
QCOMPARE(addedFunc->visibility(), AbstractMetaFunction::Public);
QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction);
QVERIFY(addedFunc->isUserAdded());
- QVERIFY(!addedFunc->type());
+ QVERIFY(addedFunc->isVoid());
}
void TestAddFunction::testAddFunctionCodeSnippets()
diff --git a/sources/shiboken2/ApiExtractor/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp
index 0d5a8cba7..6b56d362e 100644
--- a/sources/shiboken2/ApiExtractor/typedatabase.cpp
+++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp
@@ -887,9 +887,8 @@ void TypeEntry::formatDebug(QDebug &d) const
d << '"' << m_name << '"';
if (m_name != cppName)
d << "\", cppName=\"" << cppName << '"';
- d << ", type=" << m_type << ", codeGeneration=0x"
- << Qt::hex << m_codeGeneration << Qt::dec
- << ", target=\"" << targetLangName() << '"';
+ d << ", type=" << m_type << ", codeGeneration="
+ << m_codeGeneration << ", target=\"" << targetLangName() << '"';
FORMAT_NONEMPTY_STRING("package", m_targetLangPackage)
FORMAT_BOOL("stream", m_stream)
FORMAT_LIST_SIZE("codeSnips", m_codeSnips)
@@ -1002,6 +1001,16 @@ void TypeDatabase::formatDebug(QDebug &d) const
<< "entries[" << m_entries.size() << "]=";
for (auto it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it)
d << " " << it.value() << '\n';
+ if (!m_typedefEntries.isEmpty()) {
+ d << "typedefs[" << m_typedefEntries.size() << "]=(";
+ const auto begin = m_typedefEntries.cbegin();
+ for (auto it = begin, end = m_typedefEntries.cend(); it != end; ++it) {
+ if (it != begin)
+ d << ", ";
+ d << " " << it.value() << '\n';
+ }
+ d << ")\n";
+ }
if (!m_templates.isEmpty()) {
d << "templates[" << m_templates.size() << "]=(";
const auto begin = m_templates.cbegin();
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
index 445743a74..2418f51fe 100644
--- a/sources/shiboken2/generator/generator.cpp
+++ b/sources/shiboken2/generator/generator.cpp
@@ -229,7 +229,7 @@ QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType *type)
// Strip a "const QSharedPtr<const Foo> &" or similar to "QSharedPtr<Foo>" (PYSIDE-1016/454)
const AbstractMetaType *canonicalSmartPtrInstantiation(const AbstractMetaType *type)
{
- AbstractMetaTypeList instantiations = type->instantiations();
+ const AbstractMetaTypeList &instantiations = type->instantiations();
Q_ASSERT(instantiations.size() == 1);
const bool needsFix = type->isConstant() || type->referenceType() != NoReference;
const bool pointeeNeedsFix = instantiations.constFirst()->isConstant();
@@ -256,8 +256,7 @@ void Generator::addInstantiatedContainersAndSmartPointers(const AbstractMetaType
{
if (!type)
return;
- const AbstractMetaTypeList &instantiations = type->instantiations();
- for (const AbstractMetaType *t : instantiations)
+ for (const auto *t : type->instantiations())
addInstantiatedContainersAndSmartPointers(t, context);
const auto typeEntry = type->typeEntry();
const bool isContainer = typeEntry->isContainer();
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
index 282da6eca..81b404239 100644
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
@@ -2081,7 +2081,7 @@ void QtDocGenerator::writeFunctionParametersType(QTextStream &s, const AbstractM
writeParameterType(s, cppClass, arg);
}
- if (!func->isConstructor() && func->type()) {
+ if (!func->isConstructor() && !func->isVoid()) {
QString retType;
// check if the return type was modified
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index a6e9a00b6..434b03dc7 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -85,10 +85,9 @@ static const char *typeNameOf(const T &t)
inline AbstractMetaType *getTypeWithoutContainer(AbstractMetaType *arg)
{
if (arg && arg->typeEntry()->isContainer()) {
- AbstractMetaTypeList lst = arg->instantiations();
// only support containers with 1 type
- if (lst.size() == 1)
- return lst[0];
+ if (arg->instantiations().size() == 1)
+ return arg->instantiations().constFirst();
}
return arg;
}
@@ -247,7 +246,7 @@ const AbstractMetaFunction *CppGenerator::boolCast(const AbstractMetaClass *meta
return nullptr;
// TODO: This could be configurable someday
const AbstractMetaFunction *func = metaClass->findFunction(QLatin1String("isNull"));
- if (!func || !func->type() || !func->type()->typeEntry()->isPrimitive() || !func->isPublic())
+ if (!func || func->isVoid() || !func->type()->typeEntry()->isPrimitive() || !func->isPublic())
return nullptr;
auto pte = static_cast<const PrimitiveTypeEntry *>(func->type()->typeEntry());
while (pte->referencedTypeEntry())
@@ -892,9 +891,9 @@ QString CppGenerator::virtualMethodReturn(QTextStream &s,
const AbstractMetaFunction *func,
const FunctionModificationList &functionModifications)
{
- const AbstractMetaType *returnType = func->type();
- if (!returnType)
+ if (func->isVoid())
return QLatin1String("return;");
+ const AbstractMetaType *returnType = func->type();
for (const FunctionModification &mod : functionModifications) {
for (const ArgumentModification &argMod : mod.argument_mods) {
if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) {
@@ -947,7 +946,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s,
((func->name() == QLatin1String("metaObject")) || (func->name() == QLatin1String("qt_metacall"))))
return;
- const TypeEntry *retType = func->type() ? func->type()->typeEntry() : nullptr;
+ const TypeEntry *retType = func->type()->typeEntry();
const QString funcName = func->isOperatorOverload() ? pythonOperatorFunctionName(func) : func->name();
QString prefix = wrapperName(func->ownerClass()) + QLatin1String("::");
@@ -990,7 +989,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s,
<< R"(] << '\n';)" << '\n';
}
// PYSIDE-803: Build a boolean cache for unused overrides.
- const bool multi_line = retType == nullptr || !snips.isEmpty() || func->isAbstract();
+ const bool multi_line = func->isVoid() || !snips.isEmpty() || func->isAbstract();
s << INDENT << "if (m_PyMethodCache[" << cacheIndex << "])" << (multi_line ? " {\n" : "\n");
{
Indentation indentation(INDENT);
@@ -1122,7 +1121,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s,
}
s << INDENT << "}\n";
- if (retType) {
+ if (!func->isVoid()) {
if (invalidateReturn)
s << INDENT << "bool invalidateArg0 = " << PYTHON_RETURN_VAR << "->ob_refcnt == 1;\n";
@@ -1207,7 +1206,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s,
writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg);
}
- if (retType) {
+ if (!func->isVoid()) {
s << INDENT << "return ";
if (avoidProtectedHack() && retType->isEnum()) {
const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(retType);
@@ -2325,6 +2324,7 @@ void CppGenerator::writeTypeCheck(QTextStream &s, const AbstractMetaType *argTyp
static void checkTypeViability(const AbstractMetaFunction *func, const AbstractMetaType *type, int argIdx)
{
if (!type
+ || type->isVoid()
|| !type->typeEntry()->isPrimitive()
|| type->indirections() == 0
|| (type->indirections() == 1 && type->typeUsagePattern() == AbstractMetaType::NativePointerAsArrayPattern)
@@ -2597,7 +2597,7 @@ void CppGenerator::writeConversionRule(QTextStream &s, const AbstractMetaFunctio
void CppGenerator::writeNoneReturn(QTextStream &s, const AbstractMetaFunction *func, bool thereIsReturnValue)
{
- if (thereIsReturnValue && (!func->type() || func->argumentRemoved(0)) && !injectedCodeHasReturnValueAttribution(func)) {
+ if (thereIsReturnValue && (func->isVoid() || func->argumentRemoved(0)) && !injectedCodeHasReturnValueAttribution(func)) {
s << INDENT << PYTHON_RETURN_VAR << " = Py_None;\n";
s << INDENT << "Py_INCREF(Py_None);\n";
}
@@ -3238,7 +3238,7 @@ QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction *func, in
} else if (argIndex == 0) {
AbstractMetaType *funcType = func->type();
AbstractMetaType *returnType = getTypeWithoutContainer(funcType);
- if (returnType) {
+ if (!returnType->isVoid()) {
pyArgName = QLatin1String(PYTHON_RETURN_VAR);
*wrappedClass = AbstractMetaClass::findClass(classes(), returnType->typeEntry());
} else {
@@ -3561,7 +3561,7 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
if (isCtor) {
s << (useVAddr.isEmpty() ?
QString::fromLatin1("cptr = %1;").arg(methodCall) : useVAddr) << Qt::endl;
- } else if (func->type() && !func->isInplaceOperator()) {
+ } else if (!func->isVoid() && !func->isInplaceOperator()) {
bool writeReturnType = true;
if (avoidProtectedHack()) {
const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(func->type());
@@ -3599,7 +3599,7 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
// Convert result
if (!func->conversionRule(TypeSystem::TargetLangCode, 0).isEmpty()) {
writeConversionRule(s, func, TypeSystem::TargetLangCode, QLatin1String(PYTHON_RETURN_VAR));
- } else if (!isCtor && !func->isInplaceOperator() && func->type()
+ } else if (!isCtor && !func->isInplaceOperator() && !func->isVoid()
&& !injectedCodeHasReturnValueAttribution(func, TypeSystem::TargetLangCode)) {
s << INDENT << PYTHON_RETURN_VAR << " = ";
if (isObjectTypeUsedAsValueType(func->type())) {
@@ -4684,7 +4684,7 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, const GeneratorConte
}
if (generateOperatorCode) {
s << INDENT;
- if (func->type())
+ if (!func->isVoid())
s << func->type()->cppSignature() << " " << CPP_RETURN_VAR << " = ";
// expression
if (func->isPointerOperator())
@@ -4694,7 +4694,7 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, const GeneratorConte
s << '*';
s << CPP_ARG0 << ");\n";
s << INDENT << PYTHON_RETURN_VAR << " = ";
- if (func->type())
+ if (!func->isVoid())
writeToPythonConversion(s, func->type(), metaClass, QLatin1String(CPP_RETURN_VAR));
else
s << "Py_None;\n" << INDENT << "Py_INCREF(Py_None)";
@@ -4821,7 +4821,7 @@ void CppGenerator::writeSignatureInfo(QTextStream &s, const AbstractMetaFunction
if (multiple)
s << idx-- << ':';
s << funcName << '(' << args.join(QLatin1Char(',')) << ')';
- if (f->type())
+ if (!f->isVoid())
s << "->" << f->type()->pythonSignature();
s << Qt::endl;
}
@@ -6182,7 +6182,7 @@ void CppGenerator::writeReturnValueHeuristics(QTextStream &s, const AbstractMeta
AbstractMetaType *type = func->type();
if (!useReturnValueHeuristic()
|| !func->ownerClass()
- || !type
+ || type->isVoid()
|| func->isStatic()
|| func->isConstructor()
|| !func->typeReplaced(0).isEmpty()) {
@@ -6232,7 +6232,7 @@ void CppGenerator::writeDefaultSequenceMethods(QTextStream &s, const GeneratorCo
<< CPP_SELF_VAR << "->begin();\n"
<< INDENT << "std::advance(_item, _i);\n";
- const AbstractMetaTypeList instantiations = metaClass->templateBaseClassInstantiations();
+ const AbstractMetaTypeList &instantiations = metaClass->templateBaseClassInstantiations();
if (instantiations.isEmpty()) {
qFatal("shiboken: %s: Internal error, no instantiations of \"%s\" were found.",
__FUNCTION__, qPrintable(metaClass->qualifiedCppName()));
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
index 1ba846d87..c780df01a 100644
--- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
@@ -239,7 +239,8 @@ void HeaderGenerator::writeFunction(QTextStream &s, const AbstractMetaFunction *
s << INDENT << "inline " << (func->isStatic() ? "static " : "");
s << functionSignature(func, QString(), QLatin1String("_protected"), Generator::EnumAsInts|Generator::OriginalTypeDescription)
<< " { ";
- s << (func->type() ? "return " : "");
+ if (!func->isVoid())
+ s << "return ";
if (!func->isAbstract())
s << func->ownerClass()->qualifiedCppName() << "::";
s << func->originalName() << '(';
@@ -637,8 +638,10 @@ void HeaderGenerator::writeInheritedOverloads(QTextStream &s)
{
for (const AbstractMetaFunction *func : qAsConst(m_inheritedOverloads)) {
s << INDENT << "inline ";
- s << functionSignature(func, QString(), QString(), Generator::EnumAsInts|Generator::OriginalTypeDescription) << " { ";
- s << (func->type() ? "return " : "");
+ s << functionSignature(func, QString(), QString(), Generator::EnumAsInts|Generator::OriginalTypeDescription)
+ << " { ";
+ if (!func->isVoid())
+ s << "return ";
s << func->ownerClass()->qualifiedCppName() << "::" << func->originalName() << '(';
QStringList args;
const AbstractMetaArgumentList &arguments = func->arguments();
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
index 36725d3fc..193384853 100644
--- a/sources/shiboken2/generator/shiboken2/overloaddata.cpp
+++ b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
@@ -57,8 +57,7 @@ static QString getTypeName(const AbstractMetaType *type)
QString typeName = typeEntry->name();
if (typeEntry->isContainer()) {
QStringList types;
- const AbstractMetaTypeList &instantiations = type->instantiations();
- for (const AbstractMetaType *cType : instantiations) {
+ for (const auto *cType : type->instantiations()) {
const TypeEntry *typeEntry = getReferencedTypeEntry(cType->typeEntry());
types << typeEntry->name();
}
@@ -147,8 +146,7 @@ static QString getImplicitConversionTypeName(const AbstractMetaType *containerTy
impConv = getTypeName(function->arguments().constFirst()->type());
QStringList types;
- const AbstractMetaTypeList &instantiations = containerType->instantiations();
- for (const AbstractMetaType *otherType : instantiations)
+ for (const auto *otherType : containerType->instantiations())
types << (otherType == instantiation ? impConv : getTypeName(otherType));
return containerType->typeEntry()->qualifiedCppName() + QLatin1Char('<')
@@ -258,8 +256,7 @@ void OverloadData::sortNextOverloads()
qstringIndex = sortData.lastProcessedItemId();
}
- const AbstractMetaTypeList &instantiations = ov->argType()->instantiations();
- for (const AbstractMetaType *instantiation : instantiations) {
+ for (const auto *instantiation : ov->argType()->instantiations()) {
// Add dependencies for type instantiation of container.
QString typeName = getTypeName(instantiation);
sortData.mapType(typeName);
@@ -346,8 +343,7 @@ void OverloadData::sortNextOverloads()
}
// Process template instantiations
- const AbstractMetaTypeList &instantiations = targetType->instantiations();
- for (const AbstractMetaType *instantiation : instantiations) {
+ for (const auto *instantiation : targetType->instantiations()) {
if (sortData.map.contains(getTypeName(instantiation))) {
int convertible = sortData.map[getTypeName(instantiation)];
@@ -579,10 +575,8 @@ QStringList OverloadData::returnTypes() const
for (const AbstractMetaFunction *func : m_overloads) {
if (!func->typeReplaced(0).isEmpty())
retTypes << func->typeReplaced(0);
- else if (func->type() && !func->argumentRemoved(0))
+ else if (!func->argumentRemoved(0))
retTypes << func->type()->cppSignature();
- else
- retTypes << QLatin1String("void");
}
return retTypes.values();
}
@@ -878,12 +872,9 @@ QString OverloadData::dumpGraph() const
// Shows all function signatures
s << "legend [fontsize=9 fontname=freemono shape=rect label=\"";
for (const AbstractMetaFunction *func : m_overloads) {
- s << "f" << functionNumber(func) << " : ";
- if (func->type())
- s << toHtml(func->type()->cppSignature());
- else
- s << "void";
- s << ' ' << toHtml(func->minimalSignature()) << "\\l";
+ s << "f" << functionNumber(func) << " : "
+ << toHtml(func->type()->cppSignature())
+ << ' ' << toHtml(func->minimalSignature()) << "\\l";
}
s << "\"];\n";
@@ -903,12 +894,9 @@ QString OverloadData::dumpGraph() const
s << "</td></tr>";
// Function return type
- s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">";
- if (rfunc->type())
- s << toHtml(rfunc->type()->cppSignature());
- else
- s << "void";
- s << "</td></tr>";
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">"
+ << toHtml(rfunc->type()->cppSignature())
+ << "</td></tr>";
// Shows type changes for all function signatures
for (const AbstractMetaFunction *func : m_overloads) {
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index 7b8f2c7e4..97aecf529 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -1862,7 +1862,7 @@ void ShibokenGenerator::writeCodeSnips(QTextStream &s,
if (func->isConstructor()) {
code.replace(QLatin1String("%0."), QLatin1String("cptr->"));
code.replace(QLatin1String("%0"), QLatin1String("cptr"));
- } else if (func->type()) {
+ } else if (!func->isVoid()) {
QString returnValueOp = isPointerToWrapperType(func->type())
? QLatin1String("%1->") : QLatin1String("%1.");
if (ShibokenGenerator::isWrapperType(func->type()))
@@ -2406,8 +2406,7 @@ AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const Ty
typeName.remove(0, 2);
if (m_metaTypeFromStringCache.contains(typeName))
return m_metaTypeFromStringCache.value(typeName);
- auto *metaType = new AbstractMetaType;
- metaType->setTypeEntry(typeEntry);
+ auto *metaType = new AbstractMetaType(typeEntry);
metaType->clearIndirections();
metaType->setReferenceType(NoReference);
metaType->setConstant(false);
@@ -2737,8 +2736,7 @@ QString ShibokenGenerator::convertersVariableName(const QString &moduleName) con
static QString processInstantiationsVariableName(const AbstractMetaType *type)
{
QString res = QLatin1Char('_') + _fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper();
- const AbstractMetaTypeList &instantiations = type->instantiations();
- for (const AbstractMetaType *instantiation : instantiations) {
+ for (const auto *instantiation : type->instantiations()) {
res += instantiation->isContainer()
? processInstantiationsVariableName(instantiation)
: QLatin1Char('_') + _fixedCppTypeName(instantiation->cppSignature()).toUpper();
@@ -2762,8 +2760,7 @@ QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass *met
return QString();
QString result = QLatin1String("SBK_")
+ _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper();
- const AbstractMetaTypeList &templateBaseClassInstantiations = metaClass->templateBaseClassInstantiations();
- for (const AbstractMetaType *instantiation : templateBaseClassInstantiations)
+ for (const auto *instantiation : metaClass->templateBaseClassInstantiations())
result += processInstantiationsVariableName(instantiation);
appendIndexSuffix(&result);
return result;