JNI: Fix error with overload resolution when passing string types

The variadic templates are supposed to be removed from the
overload set when any of the parameters is a literal string type,
as otherwise we get conflicts with the legacy overload taking
class names and signatures as const char *. The detection of
a literal string types was missing a few specializations, so that
we ended up with the wrong overload being called, and class
names getting interpreted as method names instead.

Add the missing specializations, and add more test coverage
for using the old overloads.

Task-number: QTBUG-122235
Change-Id: I5488f2009c8f62d74fac6754844f57cf64011414
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
Reviewed-by: Rami Potinkara <rami.potinkara@qt.io>
Reviewed-by: Lauri Pohjanheimo <lauri.pohjanheimo@qt.io>
(cherry picked from commit 10afa38aa44231b3617984fdbca66d9699e2825f)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Volker Hilsheimer 2024-03-04 18:33:07 +01:00 committed by Qt Cherry-pick Bot
parent 7c74a2af73
commit f26e0996c7
4 changed files with 73 additions and 1 deletions

View File

@ -134,9 +134,12 @@ struct CTString
// Helper types that allow us to disable variadic overloads that would conflict // Helper types that allow us to disable variadic overloads that would conflict
// with overloads that take a const char*. // with overloads that take a const char*.
template<typename T, size_t N = 0> struct IsStringType : std::false_type {}; template<typename T, size_t N = 0> struct IsStringType : std::false_type {};
template<> struct IsStringType<const char*, 0> : std::true_type {}; template<> struct IsStringType<const char *, 0> : std::true_type {};
template<> struct IsStringType<const char *&, 0> : std::true_type {};
template<size_t N> struct IsStringType<CTString<N>> : std::true_type {}; template<size_t N> struct IsStringType<CTString<N>> : std::true_type {};
template<size_t N> struct IsStringType<const char[N]> : std::true_type {}; template<size_t N> struct IsStringType<const char[N]> : std::true_type {};
template<size_t N> struct IsStringType<const char(&)[N]> : std::true_type {};
template<size_t N> struct IsStringType<char[N]> : std::true_type {};
template <typename T> template <typename T>
struct Traits { struct Traits {

View File

@ -127,6 +127,9 @@ public class QtJniObjectTestClass
public static String staticStringMethod() { return A_STRING_OBJECT; } public static String staticStringMethod() { return A_STRING_OBJECT; }
public String stringMethod() { return staticStringMethod(); } public String stringMethod() { return staticStringMethod(); }
// --------------------------------------------------------------------------------------------
public static String staticEchoMethod(String value) { return value; }
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
public static Throwable staticThrowableMethod() { return A_THROWABLE_OBJECT; } public static Throwable staticThrowableMethod() { return A_THROWABLE_OBJECT; }
public Throwable throwableMethod() { return staticThrowableMethod(); } public Throwable throwableMethod() { return staticThrowableMethod(); }

View File

@ -117,6 +117,7 @@ private slots:
void callback_data(); void callback_data();
void callback(); void callback();
void callStaticOverloadResolution();
void cleanupTestCase(); void cleanupTestCase();
}; };
@ -2009,6 +2010,19 @@ void tst_QJniObject::callback()
QCOMPARE(result, int(parameterType)); QCOMPARE(result, int(parameterType));
} }
// Make sure the new callStaticMethod overload taking a class, return type,
// and argument as template parameters, doesn't break overload resolution
// and that the class name doesn't get interpreted as the function name.
void tst_QJniObject::callStaticOverloadResolution()
{
const QString value = u"Hello World"_s;
QJniObject str = QJniObject::fromString(value);
const auto result = QJniObject::callStaticMethod<jstring, jstring>(
QtJniTypes::Traits<TestClass>::className(),
"staticEchoMethod", str.object<jstring>()).toString();
QCOMPARE(result, value);
}
QTEST_MAIN(tst_QJniObject) QTEST_MAIN(tst_QJniObject)
#include "tst_qjniobject.moc" #include "tst_qjniobject.moc"

View File

@ -22,6 +22,7 @@ private slots:
void initTestCase(); void initTestCase();
void nativeMethod(); void nativeMethod();
void construct(); void construct();
void stringTypeCantBeArgument();
}; };
struct QtJavaWrapper {}; struct QtJavaWrapper {};
@ -227,6 +228,57 @@ void tst_QJniTypes::construct()
QCOMPARE(str3.toString(), text); QCOMPARE(str3.toString(), text);
} }
template <typename ...Arg>
static constexpr bool isValidArgument(Arg &&...) noexcept
{
return QtJniTypes::ValidSignatureTypesDetail<q20::remove_cvref_t<Arg>...>;
}
enum class Overload
{
ClassNameAndMethod,
OnlyMethod,
};
template <typename Ret, typename ...Args
#ifndef Q_QDOC
, QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
#endif
>
static constexpr auto callStaticMethod(const char *className, const char *methodName, Args &&...)
{
Q_UNUSED(className);
Q_UNUSED(methodName);
return Overload::ClassNameAndMethod;
}
template <typename Klass, typename Ret, typename ...Args
#ifndef Q_QDOC
, QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
#endif
>
static constexpr auto callStaticMethod(const char *methodName, Args &&...)
{
Q_UNUSED(methodName);
return Overload::OnlyMethod;
}
void tst_QJniTypes::stringTypeCantBeArgument()
{
const char *methodName = "staticEchoMethod";
static_assert(!isValidArgument(QtJniTypes::Traits<QtJniTypes::JavaType>::className()));
static_assert(!isValidArgument("someFunctionName"));
static_assert(!isValidArgument(methodName));
static_assert(!isValidArgument(QtJniTypes::Traits<QtJniTypes::JavaType>::className(),
"someFunctionName", methodName, 42));
static_assert(callStaticMethod<jstring, jint>("class name", "method name", 42)
== Overload::ClassNameAndMethod);
static_assert(callStaticMethod<QtJniTypes::JavaType, jint>("method name", 42)
== Overload::OnlyMethod);
}
QTEST_MAIN(tst_QJniTypes) QTEST_MAIN(tst_QJniTypes)
#include "tst_qjnitypes.moc" #include "tst_qjnitypes.moc"