1 /*
2 * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 import jdk.incubator.code.dialect.java.JavaOp.InvokeOp.InvokeKind;
25 import jdk.incubator.code.dialect.java.MethodRef;
26 import org.junit.jupiter.api.Test;
27
28 import java.lang.invoke.MethodHandle;
29 import java.lang.invoke.MethodHandles;
30 import java.lang.invoke.MethodHandles.Lookup;
31 import java.lang.invoke.MethodType;
32 import java.lang.reflect.Method;
33 import java.lang.reflect.Modifier;
34 import java.util.List;
35
36 import static org.junit.jupiter.api.Assertions.assertEquals;
37 import static org.junit.jupiter.api.Assertions.assertThrows;
38
39 /*
40 * @test
41 * @modules jdk.incubator.code
42 * @run junit TestMethodResolution
43 */
44 public class TestMethodResolution {
45 public static class C {
46 static public int s_x() { return 42; }
47 public int x() { return 42; }
48 long y() { return 42L; };
49 static long s_y() { return 42L; };
50 }
51
52 public static class C_Sub extends C { }
53
54 @Test
55 public void testClassDeclaredMethodsPrivateLookup() throws ReflectiveOperationException {
56 lookupInternal(C.class, C.class, MethodHandles.lookup());
57 }
58
59 @Test
60 public void testClassDeclaredMethodsPublicLookup() throws ReflectiveOperationException {
61 lookupInternal(C.class, C.class, publicLookup());
62 }
63
64 @Test
65 public void testClassInheritedMethodsPrivateLookup() throws ReflectiveOperationException {
66 lookupInternal(C_Sub.class, C.class, MethodHandles.lookup());
67 }
68
69 @Test
70 public void testClassInheritedMethodsPublicLookup() throws ReflectiveOperationException {
71 lookupInternal(C_Sub.class, C.class, publicLookup());
72 }
73
74 public interface I {
75 int x();
76 default int xd() {
77 return 42;
78 }
79 static int s_x() { return 42; }
80 }
81
82 public interface I_Sub extends I { }
83
84 public static abstract class CI_Sub implements I_Sub { }
85
86 @Test
87 public void testInterfaceDeclaredMethodsPublicLookup() throws ReflectiveOperationException {
88 lookupInternal(I.class, I.class, publicLookup());
89 }
90
91 @Test
92 public void testInterfaceInheritedMethodsPublicLookup() throws ReflectiveOperationException {
93 lookupInternal(I_Sub.class, I.class, publicLookup());
94 }
95
96 // @Test
97 // public void testClassInterfaceInheritedMethodsPublicLookup() throws ReflectiveOperationException {
98 // lookupInternal(CI_Sub.class, I.class, publicLookup());
99 // }
100 // @@@: this is commented for now -- revealDirect seems to have issues when cracking interface methods from subclasses
101
102 static void lookupInternal(Class<?> refC, Class<?> cl, Lookup lookup) throws ReflectiveOperationException {
103 for (Method m : cl.getDeclaredMethods()) {
104 MethodRef methodRef = MethodRef.method(refC, m.getName(), MethodType.methodType(m.getReturnType(), m.getParameterTypes()));
105 boolean implLookup = (lookup.lookupModes() & Lookup.ORIGINAL) != 0;
106 boolean intfMethodSub = cl.isInterface() && Modifier.isStatic(m.getModifiers()) && !cl.equals(refC);
107 if (!intfMethodSub && (Modifier.isPublic(m.getModifiers()) || implLookup)) {
108 Method resolvedM = methodRef.resolveToMethod(lookup);
109 assertEquals(m, resolvedM);
110 final List<InvokeKind> kinds = kindsToTest(m, implLookup);
111 for (InvokeKind kind : kinds) {
112 MethodHandle resolvedMH = methodRef.resolveToHandle(lookup.in(refC), kind);
113 Method targetM = lookup.revealDirect(resolvedMH).reflectAs(Method.class, lookup);
114 assertEquals(targetM, m);
115 }
116 } else {
117 assertThrows(ReflectiveOperationException.class, () -> methodRef.resolveToMethod(lookup));
118 }
119 }
120 }
121
122 static List<InvokeKind> kindsToTest(Method m, boolean implLookup) {
123 if (Modifier.isStatic(m.getModifiers())) {
124 return List.of(InvokeKind.STATIC);
125 } else if (implLookup) {
126 return List.of(InvokeKind.INSTANCE, InvokeKind.SUPER);
127 } else {
128 return List.of(InvokeKind.INSTANCE);
129 }
130 }
131
132 static Lookup publicLookup() {
133 return MethodHandles.publicLookup().in(TestMethodResolution.class);
134 }
135 }