summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/kernel/qjnitypes
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2023-09-27 08:19:21 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2023-09-27 19:44:58 +0200
commit185c3b080c5d4875266833eda703fca57f8a30af (patch)
tree1b8ae6cf38753e386d31a63d9b02bd1c9e3bbe6f /tests/auto/corelib/kernel/qjnitypes
parent62cb5589b3723fe8162e190cd54d9c78929b98d2 (diff)
JNI: Fix native functions that take a declared QtJniTypes class
Now that QtJniTypes::Objects are no longer primitive types that are the same as a jobject, using those types in registered native functions breaks. JNI will call those function with a jobject on the function pointer, and lacking any type safety, the call to the registered function will proceed with a wrong type of object on the stack. To fix that, register the native function via a proxy that is a variadic argument function, and unpack the variadic arguments into a list of typed arguments, using the types we know the user-code function wants. Then call the function with a tuple of those types using std::apply, which gives us type safety and implicit conversion for free. Add a test that exercises this. Change-Id: I9f980e55d3d13f8fc16c410dc0d17dbdc200cb47 Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
Diffstat (limited to 'tests/auto/corelib/kernel/qjnitypes')
-rw-r--r--tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp31
1 files changed, 27 insertions, 4 deletions
diff --git a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
index 0ce2295092..a499b6f2d2 100644
--- a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
+++ b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
@@ -14,6 +14,9 @@ class tst_QJniTypes : public QObject
public:
tst_QJniTypes() = default;
+ static void nativeClassMethod(JNIEnv *, jclass, int);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(nativeClassMethod);
+
private slots:
void initTestCase();
void nativeMethod();
@@ -154,12 +157,32 @@ Q_DECLARE_JNI_NATIVE_METHOD(nativeFunction)
static_assert(QtJniTypes::nativeMethodSignature(nativeFunction) == "(ILjava/lang/String;J)Z");
+static int forwardDeclaredNativeFunction(JNIEnv *, jobject, bool);
+Q_DECLARE_JNI_NATIVE_METHOD(forwardDeclaredNativeFunction)
+static int forwardDeclaredNativeFunction(JNIEnv *, jobject, bool) { return 0; }
+static_assert(QtJniTypes::nativeMethodSignature(forwardDeclaredNativeFunction) == "(Z)I");
+
+static_assert(QtJniTypes::nativeMethodSignature(tst_QJniTypes::nativeClassMethod) == "(I)V");
+void tst_QJniTypes::nativeClassMethod(JNIEnv *, jclass, int) {}
+
void tst_QJniTypes::nativeMethod()
{
- const auto method = Q_JNI_NATIVE_METHOD(nativeFunction);
- QVERIFY(method.fnPtr == nativeFunction);
- QCOMPARE(method.name, "nativeFunction");
- QCOMPARE(method.signature, "(ILjava/lang/String;J)Z");
+ {
+ const auto method = Q_JNI_NATIVE_METHOD(nativeFunction);
+ QVERIFY(method.fnPtr == QtJniMethods::va_nativeFunction);
+ QCOMPARE(method.name, "nativeFunction");
+ QCOMPARE(method.signature, "(ILjava/lang/String;J)Z");
+ }
+
+ {
+ const auto method = Q_JNI_NATIVE_METHOD(forwardDeclaredNativeFunction);
+ QVERIFY(method.fnPtr == QtJniMethods::va_forwardDeclaredNativeFunction);
+ }
+
+ {
+ const auto method = Q_JNI_NATIVE_SCOPED_METHOD(nativeClassMethod, tst_QJniTypes);
+ QVERIFY(method.fnPtr == va_nativeClassMethod);
+ }
}
void tst_QJniTypes::construct()