aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2021-10-20 13:51:08 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2021-10-21 13:03:11 +0200
commite70fbd8d91af1fa9813bc1df7dfad44b1665957e (patch)
tree459fdff3bb60d2405bd5d0a02292a44b358689d7
parentc0beb9f29f36ea3bc8be26675a05253cc5584fe4 (diff)
shiboken6: Implement opaque containers for getters returning a const reference
Add a bool m_const member to the container helper template that indicates a const container. Error out of the modification functions if that is set. Create an additional creation function for the const case. A const opaque containers is then of same Python type as the non-const version, requiring no further type checks. Pick-to: 6.2 Task-number: PYSIDE-1605 Change-Id: I45faeb0d68e6144a9dfbe25497694b8acdd98c09 Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.cpp9
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator_container.cpp45
-rw-r--r--sources/shiboken6/libshiboken/sbkcontainer.h30
-rw-r--r--sources/shiboken6/tests/libminimal/listuser.cpp5
-rw-r--r--sources/shiboken6/tests/libminimal/listuser.h1
-rw-r--r--sources/shiboken6/tests/minimalbinding/listuser_test.py5
-rw-r--r--sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml5
7 files changed, 84 insertions, 16 deletions
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
index a6abeb077..06299a2ab 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
@@ -197,8 +197,11 @@ static QString opaqueContainerCreationFunc(const AbstractMetaType &type)
static_cast<const ContainerTypeEntry *>(type.typeEntry());
const auto *instantiationTypeEntry =
type.instantiations().constFirst().typeEntry();
- return u"create"_qs
- + containerTypeEntry->opaqueContainerName(instantiationTypeEntry->name());
+ QString result = u"create"_qs;
+ if (type.isConstant())
+ result += u"Const"_qs;
+ result += containerTypeEntry->opaqueContainerName(instantiationTypeEntry->name());
+ return result;
}
// Write declaration of the function to create PyObject wrapping a container
@@ -206,7 +209,7 @@ static void writeOpaqueContainerCreationFuncDecl(TextStream &s, const QString &n
AbstractMetaType type)
{
type.setReferenceType(NoReference);
- type.setConstant(false);
+ // Maintain const
s << "PyObject *" << name << '(' << type.cppSignature() << "*);\n";
}
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp
index bc29e1d1e..eab57bcc0 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp
@@ -73,6 +73,35 @@ static void writeSlot(TextStream &s, const QString &privateObjType,
<< "::" << methodName << ")},\n";
}
+// Write creation function from C++ reference, used by field accessors
+// and getters which are within extern "C"
+static void writeContainerCreationFunc(TextStream &s,
+ const QString &funcName,
+ const QString &typeFName,
+ const QString &containerSignature,
+ bool isConst = false)
+{
+
+ // creation function from C++ reference, used by field accessors
+ // which are within extern "C"
+ s << "extern \"C\" PyObject *" << funcName << '(';
+ if (isConst)
+ s << "const ";
+ s << containerSignature << "* ct)\n{\n" << indent
+ << "auto *container = PyObject_New(ShibokenContainer, " << typeFName << "());\n"
+ << "auto *d = new ShibokenSequenceContainerPrivate<"
+ << containerSignature << ">();\n";
+ if (isConst) {
+ s << "d->m_list = const_cast<" << containerSignature << " *>(ct);\n"
+ << "d->m_const = true;\n";
+ } else {
+ s << "d->m_list = ct;\n";
+ }
+ s << "container->d = d;\n";
+ s << "return reinterpret_cast<PyObject *>(container);\n" << outdent
+ << "}\n\n";
+}
+
// Generate code for a type wrapping a C++ container instantiation
CppGenerator::OpaqueContainerData
CppGenerator::writeOpaqueContainerConverterFunctions(TextStream &s,
@@ -184,17 +213,11 @@ CppGenerator::OpaqueContainerData
<< "static PyTypeObject *type = " << typeCreationFName
<< "();\nreturn type;\n" << outdent << "}\n\n";
- // creation function from C++ reference, used by field accessors
- // which are within extern "C"
- const QString creationFunctionName = u"create"_qs + result.name;
- s << "extern \"C\" PyObject *" << creationFunctionName
- << '(' << containerType.cppSignature() << "*ct)\n{\n" << indent
- << "auto *container = PyObject_New(ShibokenContainer, " << typeFName << "());\n"
- << "auto *d = new ShibokenSequenceContainerPrivate<"
- << containerType.cppSignature() << ">();\n"
- << "d->m_list = ct;\ncontainer->d = d;\n"
- << "return reinterpret_cast<PyObject *>(container);\n" << outdent
- << "}\n\n";
+ // creation functions from C++ references
+ writeContainerCreationFunc(s, u"create"_qs + result.name, typeFName,
+ containerType.cppSignature());
+ writeContainerCreationFunc(s, u"createConst"_qs + result.name, typeFName,
+ containerType.cppSignature(), true);
// Check function
result.checkFunctionName = result.name + u"_Check"_qs;
diff --git a/sources/shiboken6/libshiboken/sbkcontainer.h b/sources/shiboken6/libshiboken/sbkcontainer.h
index 284bf8c5c..97062a198 100644
--- a/sources/shiboken6/libshiboken/sbkcontainer.h
+++ b/sources/shiboken6/libshiboken/sbkcontainer.h
@@ -76,6 +76,9 @@ public:
SequenceContainer *m_list{};
bool m_ownsList = false;
+ bool m_const = false;
+ static constexpr const char *msgModifyConstContainer =
+ "Attempt to modify a constant container.";
static PyObject *tpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
{
@@ -137,12 +140,16 @@ public:
static PyObject *push_back(PyObject *self, PyObject *pyArg)
{
+ auto *d = get(self);
if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg)) {
PyErr_SetString(PyExc_TypeError, "wrong type passed to append.");
return nullptr;
}
+ if (d->m_const) {
+ PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
+ return nullptr;
+ }
- auto *d = get(self);
OptionalValue value = ShibokenContainerValueConverter<value_type>::convertValueToCpp(pyArg);
if (!value.has_value())
return nullptr;
@@ -152,12 +159,16 @@ public:
static PyObject *push_front(PyObject *self, PyObject *pyArg)
{
+ auto *d = get(self);
if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg)) {
PyErr_SetString(PyExc_TypeError, "wrong type passed to append.");
return nullptr;
}
+ if (d->m_const) {
+ PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
+ return nullptr;
+ }
- auto *d = get(self);
OptionalValue value = ShibokenContainerValueConverter<value_type>::convertValueToCpp(pyArg);
if (!value.has_value())
return nullptr;
@@ -168,6 +179,11 @@ public:
static PyObject *clear(PyObject *self)
{
auto *d = get(self);
+ if (d->m_const) {
+ PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
+ return nullptr;
+ }
+
d->m_list->clear();
Py_RETURN_NONE;
}
@@ -175,6 +191,11 @@ public:
static PyObject *pop_back(PyObject *self)
{
auto *d = get(self);
+ if (d->m_const) {
+ PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
+ return nullptr;
+ }
+
d->m_list->pop_back();
Py_RETURN_NONE;
}
@@ -182,6 +203,11 @@ public:
static PyObject *pop_front(PyObject *self)
{
auto *d = get(self);
+ if (d->m_const) {
+ PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
+ return nullptr;
+ }
+
d->m_list->pop_front();
Py_RETURN_NONE;
}
diff --git a/sources/shiboken6/tests/libminimal/listuser.cpp b/sources/shiboken6/tests/libminimal/listuser.cpp
index 5ad570faa..6a0230d60 100644
--- a/sources/shiboken6/tests/libminimal/listuser.cpp
+++ b/sources/shiboken6/tests/libminimal/listuser.cpp
@@ -128,3 +128,8 @@ std::list<int> &ListUser::getIntList()
{
return m_stdIntList;
}
+
+const std::list<int> &ListUser::getConstIntList() const
+{
+ return m_stdIntList;
+}
diff --git a/sources/shiboken6/tests/libminimal/listuser.h b/sources/shiboken6/tests/libminimal/listuser.h
index e3b38049c..0eae69ae1 100644
--- a/sources/shiboken6/tests/libminimal/listuser.h
+++ b/sources/shiboken6/tests/libminimal/listuser.h
@@ -72,6 +72,7 @@ struct LIBMINIMAL_API ListUser
void setStdIntList(const std::list<int> &l);
std::list<int> &getIntList();
+ const std::list<int> &getConstIntList() const;
std::list<int> m_stdIntList;
};
diff --git a/sources/shiboken6/tests/minimalbinding/listuser_test.py b/sources/shiboken6/tests/minimalbinding/listuser_test.py
index 7bb65d359..a1fc48c08 100644
--- a/sources/shiboken6/tests/minimalbinding/listuser_test.py
+++ b/sources/shiboken6/tests/minimalbinding/listuser_test.py
@@ -351,6 +351,11 @@ class ListOfIntListConversionTest(unittest.TestCase):
self.assertEqual(len(lu.m_stdIntList), 4)
self.assertEqual(lu.m_stdIntList[3], 6)
+ # Access a const list via getter and verify that it cannot be modified
+ const_l = lu.getConstIntList()
+ self.assertEqual(len(const_l), 4)
+ self.assertRaises(TypeError, const_l.append, 6)
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml b/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml
index 94ec4a649..9bb7e7b7e 100644
--- a/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml
+++ b/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml
@@ -53,6 +53,11 @@
<replace-type modified-type="StdIntList"/>
</modify-argument>
</modify-function>
+ <modify-function signature="getConstIntList()const">
+ <modify-argument index="return">
+ <replace-type modified-type="StdIntList"/>
+ </modify-argument>
+ </modify-function>
</value-type>
<value-type name="MinBoolUser"/>