From 9d99307ac6d2554a661ae58f1b7d018f6e5d8f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20P=C3=B6hler?= Date: Wed, 15 Apr 2026 16:39:59 +0200 Subject: [PATCH 1/3] ADD: Testcase where methods with vararg is wrongly prefered over methods with the same argument types but without vararg argument --- .../javascript/tests/NativeJavaMethodTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/src/test/java/org/mozilla/javascript/tests/NativeJavaMethodTest.java b/tests/src/test/java/org/mozilla/javascript/tests/NativeJavaMethodTest.java index cb0e44c833d..762059822b0 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/NativeJavaMethodTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/NativeJavaMethodTest.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mozilla.javascript.Context; @@ -42,6 +43,14 @@ public void f2(String s1, String s2, String... sN) { public void fN(String s1, String s2, String... sN) { captured.add("N." + sN.length); } + + public void f3(Map m, String... sN) { + captured.add("3.N"); + } + + public void f3(Map m, Class c, String... sN) { + captured.add("3.C.N"); + } } private static void expect(List expected, String... lines) { @@ -107,6 +116,14 @@ void overload() { "d.f1('x', '3');"); } + @Test + void overloadClass() { + expect( + Arrays.asList("3.N", "3.C.N"), + "d.f3({'foo':'bar'}, 'baz');", + "d.f3({'foo':'bar'}, java.lang.String, 'baz');"); + } + @Test void varArg() { expect( From c4010f4685385a0e861b07115587298116a6ed9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20P=C3=B6hler?= Date: Wed, 15 Apr 2026 16:50:35 +0200 Subject: [PATCH 2/3] FIX: Prefer non-vararg methods when choosing which method to call --- .../src/main/java/org/mozilla/javascript/NativeJavaMethod.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java b/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java index 22df95d339c..10c0456ce3c 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java @@ -464,6 +464,9 @@ private static int preferSignature( break; } } + if (totalPreference == PREFERENCE_EQUAL && member1.isVarArgs() != member2.isVarArgs()) { + return member1.isVarArgs() ? PREFERENCE_SECOND_ARG : PREFERENCE_FIRST_ARG; + } return totalPreference; } From 1988e11f2238684fb1383dc9412a5f2fbdfb4ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20P=C3=B6hler?= Date: Mon, 27 Apr 2026 08:36:59 +0200 Subject: [PATCH 3/3] Refactor testcase to not use MethodDummy directly and enforce method misordering by the JVM through inheritance --- .../tests/NativeJavaMethodTest.java | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/tests/src/test/java/org/mozilla/javascript/tests/NativeJavaMethodTest.java b/tests/src/test/java/org/mozilla/javascript/tests/NativeJavaMethodTest.java index 762059822b0..a037e274585 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/NativeJavaMethodTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/NativeJavaMethodTest.java @@ -3,7 +3,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; +import java.util.function.Supplier; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mozilla.javascript.Context; @@ -17,8 +17,11 @@ */ public class NativeJavaMethodTest { - public static class MethodDummy { + public abstract static class CaptureDummy { public final List captured = new ArrayList<>(); + } + + public static class MethodDummy extends CaptureDummy { public void f1(String s) { captured.add("1"); @@ -43,31 +46,52 @@ public void f2(String s1, String s2, String... sN) { public void fN(String s1, String s2, String... sN) { captured.add("N." + sN.length); } + } + + public abstract static class NonVarArgParent extends CaptureDummy { + public void someMethod(int i) { + captured.add("NonVarArgParent.someMethod"); + } + } + + public static class VarArgAtSubclass extends NonVarArgParent { + public void someMethod(int i, int... extra) { + captured.add("VarArgAtSubclass.someMethod"); + } + } - public void f3(Map m, String... sN) { - captured.add("3.N"); + public abstract static class VarArgParent extends CaptureDummy { + public void someMethod(int i, int... extra) { + captured.add("VarArgParent.someMethod"); } + } - public void f3(Map m, Class c, String... sN) { - captured.add("3.C.N"); + public static class VarArgAtParent extends VarArgParent { + public void someMethod(int i) { + captured.add("VarArgAtParent.someMethod"); } } - private static void expect(List expected, String... lines) { + public static void expect(List expected, String... lines) { + expect(expected, MethodDummy::new, lines); + } + + public static void expect( + List expected, Supplier beanSupplier, String... lines) { Utils.runWithAllModes( cx -> { - final var methodDummy = new MethodDummy(); - final var scope = initContext(cx, methodDummy); + final var bean = beanSupplier.get(); + final var scope = initContext(cx, bean); cx.evaluateString( scope, String.join("\n", lines), "NativeJavaMethodTest.js", 0, null); - Assertions.assertEquals(expected, methodDummy.captured); + Assertions.assertEquals(expected, bean.captured); return null; }); } - private static ScopeObject initContext(Context cx, MethodDummy methodDummy) { + private static ScopeObject initContext(Context cx, CaptureDummy methodDummy) { cx.setLanguageVersion(Context.VERSION_ES6); final var scope = cx.initStandardObjects(); ScriptableObject.putProperty(scope, "d", Context.javaToJS(methodDummy, scope)); @@ -117,11 +141,18 @@ void overload() { } @Test - void overloadClass() { + void overloadMethodOrdering() { + expect( + List.of("NonVarArgParent.someMethod", "VarArgAtSubclass.someMethod"), + VarArgAtSubclass::new, + "d.someMethod(1);", + "d.someMethod(1, 2);"); + expect( - Arrays.asList("3.N", "3.C.N"), - "d.f3({'foo':'bar'}, 'baz');", - "d.f3({'foo':'bar'}, java.lang.String, 'baz');"); + List.of("VarArgAtParent.someMethod", "VarArgParent.someMethod"), + VarArgAtParent::new, + "d.someMethod(1);", + "d.someMethod(1, 2);"); } @Test