From 1adc8648c19d79fe25b315a6a1f7a09767cd4714 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 12 Jun 2024 11:47:44 +0200 Subject: [PATCH] JNI: Allow list of namespace to be passed into Q_DECLARE_JNI_CLASS Make the macro variadic. For N > 2 arguments, interpret the first N-2 arguments as nested namespaces that are declared as inline namespaces. We can then construct the signature string from those namespaces, so Q_DECLARE_JNI_CLASS(String, "java/lang/String") is equivalent to Q_DECLARE_JNI_CLASS(java, lang, String) except that with the second overload, the C++ type will be in the QtJniTypes::java::lang namespace. Since both the java and the lang namespaces are made inline, QtJniTypes::String still works. This helps with avoiding conflicts, as there might be Java classes in different packages, but with the same name. Change-Id: I0355239e7fc3c91cb26e041f19c4e0853d3678ac Reviewed-by: Assam Boudjelthia (cherry picked from commit 2b1312bc954b72f59d0c1d7b1192e2f029016012) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/kernel/qjnitypes.h | 74 ++++++++++++++++++- .../kernel/qjnitypes/tst_qjnitypes.cpp | 13 ++++ 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/src/corelib/kernel/qjnitypes.h b/src/corelib/kernel/qjnitypes.h index 5ad63badcd9..f6b486dc93d 100644 --- a/src/corelib/kernel/qjnitypes.h +++ b/src/corelib/kernel/qjnitypes.h @@ -13,16 +13,16 @@ QT_BEGIN_NAMESPACE // QT_TECH_PREVIEW_API #define Q_DECLARE_JNI_TYPE_HELPER(Type) \ -namespace QtJniTypes { \ struct Type##Tag { explicit Type##Tag() = default; }; \ using Type = JObject; \ -} \ // QT_TECH_PREVIEW_API #define Q_DECLARE_JNI_TYPE(Type, Signature) \ +namespace QtJniTypes { \ Q_DECLARE_JNI_TYPE_HELPER(Type) \ +} \ template<> \ -struct QtJniTypes::Traits { \ +struct ::QtJniTypes::Traits { \ static constexpr auto signature() \ { \ constexpr QtJniTypes::CTString sig(Signature); \ @@ -34,8 +34,10 @@ struct QtJniTypes::Traits { \ } \ }; \ -#define Q_DECLARE_JNI_CLASS(Type, Signature) \ +#define Q_DECLARE_JNI_CLASS_2(Type, _) \ Q_DECLARE_JNI_TYPE_HELPER(Type) \ + +#define Q_DECLARE_JNI_CLASS_SPECIALIZATION_2(Type, Signature) \ template<> \ struct QtJniTypes::Traits { \ static constexpr auto className() \ @@ -50,6 +52,70 @@ struct QtJniTypes::Traits { \ } \ }; \ +#define Q_DECLARE_JNI_CLASS_3(NS0, NS1, Type) \ +inline namespace NS0 { \ +inline namespace NS1 { \ +Q_DECLARE_JNI_CLASS_2(Type, Q_UNUSED(0)) \ +} \ +} \ + +#define Q_DECLARE_JNI_CLASS_SPECIALIZATION_3(NS0, NS1, Type) \ + Q_DECLARE_JNI_CLASS_SPECIALIZATION_2(NS0::NS1::Type, #NS0 "/" #NS1 "/" #Type) + +#define Q_DECLARE_JNI_CLASS_4(NS0, NS1, NS2, Type) \ +inline namespace NS0 { \ +Q_DECLARE_JNI_CLASS_3(NS1, NS2, Type) \ +} \ + +#define Q_DECLARE_JNI_CLASS_SPECIALIZATION_4(NS0, NS1, NS2, Type) \ + Q_DECLARE_JNI_CLASS_SPECIALIZATION_2(NS0::NS1::NS2::Type, #NS0 "/" #NS1 "/" #NS2 "/" #Type) + +#define Q_DECLARE_JNI_CLASS_5(NS0, NS1, NS2, NS3, Type) \ +inline namespace NS0 { \ +Q_DECLARE_JNI_CLASS_4(NS1, NS2, NS3, Type) \ +} \ + +#define Q_DECLARE_JNI_CLASS_SPECIALIZATION_5(NS0, NS1, NS2, NS3, Type) \ + Q_DECLARE_JNI_CLASS_SPECIALIZATION_2(NS0::NS1::NS2::NS3::Type, #NS0 "/" #NS1 "/" #NS2 "/" #NS3 "/" #Type) + +#define Q_DECLARE_JNI_CLASS_6(NS0, NS1, NS2, NS3, NS4, Type) \ +inline namespace NS0 { \ +Q_DECLARE_JNI_CLASS_5(NS1, NS2, NS3, NS4, Type) \ +} \ + +#define Q_DECLARE_JNI_CLASS_SPECIALIZATION_6(NS0, NS1, NS2, NS3, NS4, Type) \ + Q_DECLARE_JNI_CLASS_SPECIALIZATION_2(NS0::NS1::NS2::NS3::NS4::Type, #NS0 "/" #NS1 "/" #NS2 "/" #NS3 "/" #NS4 "/" #Type) + +#define Q_DECLARE_JNI_CLASS_7(NS0, NS1, NS2, NS3, NS4, NS5, Type) \ +inline namespace NS0 { \ +Q_DECLARE_JNI_CLASS_6(NS1, NS2, NS3, NS4, NS5, Type) \ +} \ + +#define Q_DECLARE_JNI_CLASS_SPECIALIZATION_7(NS0, NS1, NS2, NS3, NS4, NS5, Type) \ + Q_DECLARE_JNI_CLASS_SPECIALIZATION_2(NS0::NS1::NS2::NS3::NS4::NS5::Type, #NS0 "/" #NS1 "/" #NS2 "/" #NS3 "/" #NS4 "/" #NS5 "/" #Type) + +#define Q_DECLARE_JNI_CLASS_8(NS0, NS1, NS2, NS3, NS4, NS5, NS6, Type) \ +inline namespace NS0 { \ +Q_DECLARE_JNI_CLASS_7(NS1, NS2, NS3, NS4, NS5, NS6, Type) \ +} \ + +#define Q_DECLARE_JNI_CLASS_SPECIALIZATION_8(NS0, NS1, NS2, NS3, NS4, NS5, NS6, Type) \ + Q_DECLARE_JNI_CLASS_SPECIALIZATION_2(NS0::NS1::NS2::NS3::NS4::NS5::NS6::Type, #NS0 "/" #NS1 "/" #NS2 "/" #NS3 "/" #NS4 "/" #NS5 "/" #NS6 "/" #Type) + +#define Q_DECLARE_JNI_CLASS_9(NS0, NS1, NS2, NS3, NS4, NS5, NS6, NS7, Type) \ +inline namespace NS0 { \ +Q_DECLARE_JNI_CLASS_8(NS1, NS2, NS3, NS4, NS5, NS6, NS7, Type) \ +} \ + +#define Q_DECLARE_JNI_CLASS_SPECIALIZATION_9(NS0, NS1, NS2, NS3, NS4, NS5, NS6, NS7, Type) \ + Q_DECLARE_JNI_CLASS_SPECIALIZATION_2(NS0::NS1::NS2::NS3::NS4::NS5::NS6::NS7::Type, #NS0 "/" #NS1 "/" #NS2 "/" #NS3 "/" #NS4 "/" #NS5 "/" #NS6 "/" #NS7 "/" #Type) + +#define Q_DECLARE_JNI_CLASS(...) \ +namespace QtJniTypes { \ +QT_OVERLOADED_MACRO(Q_DECLARE_JNI_CLASS, __VA_ARGS__) \ +} \ +QT_OVERLOADED_MACRO(Q_DECLARE_JNI_CLASS_SPECIALIZATION, __VA_ARGS__) + // Macros for native methods namespace QtJniMethods { diff --git a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp index bf582041f32..38a06bbd311 100644 --- a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp +++ b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp @@ -72,6 +72,19 @@ static_assert(QtJniTypes::Traits::signature() == "[Ljava/l Q_DECLARE_JNI_CLASS(QtTextToSpeech, "org/qtproject/qt/android/speech/QtTextToSpeech") static_assert(QtJniTypes::Traits::className() == "org/qtproject/qt/android/speech/QtTextToSpeech"); +// declaring two types Size in different packages +Q_DECLARE_JNI_CLASS(android, util, Size) +// inline namespaces, so this works +static_assert(QtJniTypes::Traits::className() == "android/util/Size"); + +Q_DECLARE_JNI_CLASS(org, qtproject, Size) +// this would now be ambiguous +// static_assert(QtJniTypes::Traits::className() == "android/util/Size"); + +// but client code can be explicit +static_assert(QtJniTypes::Traits::className() == "android/util/Size"); +static_assert(QtJniTypes::Traits::className() == "org/qtproject/Size"); + static_assert(QtJniTypes::fieldSignature() == "I"); static_assert(QtJniTypes::fieldSignature() == "[I"); static_assert(QtJniTypes::fieldSignature() != "X");