1 /*
  2  * Copyright (c) 2024, 2026, 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 /*
 25  * @test
 26  * @summary Smoke test for code reflection with local class creation expressions.
 27  * @modules jdk.incubator.code
 28  * @build LocalClassTest
 29  * @build CodeReflectionTester
 30  * @run main CodeReflectionTester LocalClassTest
 31  */
 32 
 33 import jdk.incubator.code.Reflect;
 34 
 35 import java.util.function.Supplier;
 36 
 37 public class LocalClassTest {
 38 
 39     final static String CONST_STRING = "Hello!";
 40     String nonConstString = "Hello!";
 41 
 42     @Reflect
 43     @IR("""
 44             func @"testLocalNoCapture" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
 45                 %1 : java.type:"LocalClassTest::$1Foo" = new %0 @java.ref:"LocalClassTest::$1Foo::(LocalClassTest)";
 46                 invoke %1 @java.ref:"LocalClassTest::$1Foo::m():void";
 47                 return;
 48             };
 49             """)
 50     void testLocalNoCapture() {
 51         class Foo {
 52             void m() { }
 53         }
 54         new Foo().m();
 55     }
 56 
 57     @Reflect
 58     @IR("""
 59             func @"testAnonNoCapture" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
 60                 %1 : java.type:"LocalClassTest::$1" = new %0 @java.ref:"LocalClassTest::$1::(LocalClassTest)";
 61                 invoke %1 @java.ref:"LocalClassTest::$1::m():void";
 62                 return;
 63             };
 64             """)
 65     void testAnonNoCapture() {
 66         new Object() {
 67             void m() { }
 68         }.m();
 69     }
 70 
 71     @Reflect
 72     @IR("""
 73             func @"testLocalCaptureParam" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
 74                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
 75                 %3 : java.type:"java.lang.String" = var.load %2;
 76                 %4 : java.type:"LocalClassTest::$2Foo" = new %0 %3 @java.ref:"LocalClassTest::$2Foo::(LocalClassTest, java.lang.String)";
 77                 %5 : java.type:"java.lang.String" = invoke %4 @java.ref:"LocalClassTest::$2Foo::m():java.lang.String";
 78                 return %5;
 79             };
 80             """)
 81     String testLocalCaptureParam(String s) {
 82         class Foo {
 83             String m() { return s; }
 84         }
 85         return new Foo().m();
 86     }
 87 
 88     @Reflect
 89     @IR("""
 90             func @"testAnonCaptureParam" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
 91                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
 92                 %3 : java.type:"java.lang.String" = var.load %2;
 93                 %4 : java.type:"LocalClassTest::$2" = new %0 %3 @java.ref:"LocalClassTest::$2::(LocalClassTest, java.lang.String)";
 94                 %5 : java.type:"java.lang.String" = invoke %4 @java.ref:"LocalClassTest::$2::m():java.lang.String";
 95                 return %5;
 96             };
 97             """)
 98     String testAnonCaptureParam(String s) {
 99         return new Object() {
100             String m() { return s; }
101         }.m();
102     }
103 
104     @Reflect
105     @IR("""
106             func @"testLocalCaptureParamAndField" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
107                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
108                 %3 : java.type:"java.lang.String" = constant @"Hello!";
109                 %4 : Var<java.type:"java.lang.String"> = var %3 @"localConst";
110                 %5 : java.type:"java.lang.String" = var.load %2;
111                 %6 : java.type:"LocalClassTest::$3Foo" = new %0 %5 @java.ref:"LocalClassTest::$3Foo::(LocalClassTest, java.lang.String)";
112                 %7 : java.type:"java.lang.String" = invoke %6 @java.ref:"LocalClassTest::$3Foo::m():java.lang.String";
113                 return %7;
114             };
115             """)
116     String testLocalCaptureParamAndField(String s) {
117         final String localConst = "Hello!";
118         class Foo {
119             String m() { return localConst + s + nonConstString + CONST_STRING; }
120         }
121         return new Foo().m();
122     }
123 
124     @Reflect
125     @IR("""
126             func @"testAnonCaptureParamAndField" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
127                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
128                 %3 : java.type:"java.lang.String" = constant @"Hello!";
129                 %4 : Var<java.type:"java.lang.String"> = var %3 @"localConst";
130                 %5 : java.type:"java.lang.String" = var.load %2;
131                 %6 : java.type:"LocalClassTest::$3" = new %0 %5 @java.ref:"LocalClassTest::$3::(LocalClassTest, java.lang.String)";
132                 %7 : java.type:"java.lang.String" = invoke %6 @java.ref:"LocalClassTest::$3::m():java.lang.String";
133                 return %7;
134             };
135             """)
136     String testAnonCaptureParamAndField(String s) {
137         final String localConst = "Hello!";
138         return new Object() {
139             String m() { return localConst + s + nonConstString + CONST_STRING; }
140         }.m();
141     }
142 
143     @Reflect
144     @IR("""
145             func @"testLocalDependency" (%0 : java.type:"LocalClassTest", %1 : java.type:"int", %2 : java.type:"int")java.type:"void" -> {
146                 %3 : Var<java.type:"int"> = var %1 @"s";
147                 %4 : Var<java.type:"int"> = var %2 @"i";
148                 %5 : java.type:"int" = var.load %3;
149                 %6 : java.type:"int" = var.load %4;
150                 %7 : java.type:"LocalClassTest::$1Bar" = new %0 %5 %6 @java.ref:"LocalClassTest::$1Bar::(LocalClassTest, int, int)";
151                 return;
152             };
153             """)
154     void testLocalDependency(int s, int i) {
155         class Foo {
156             int i() { return i; }
157         }
158         class Bar {
159             int s() { return s; }
160             Foo foo() { return new Foo(); }
161         }
162         new Bar();
163     }
164 
165     @Reflect
166     @IR("""
167             func @"testAnonDependency" (%0 : java.type:"LocalClassTest", %1 : java.type:"int", %2 : java.type:"int")java.type:"void" -> {
168                 %3 : Var<java.type:"int"> = var %1 @"s";
169                 %4 : Var<java.type:"int"> = var %2 @"i";
170                 %5 : java.type:"int" = var.load %3;
171                 %6 : java.type:"int" = var.load %4;
172                 %7 : java.type:"LocalClassTest::$4" = new %0 %5 %6 @java.ref:"LocalClassTest::$4::(LocalClassTest, int, int)";
173                 return;
174             };
175             """)
176     void testAnonDependency(int s, int i) {
177         class Foo {
178             int i() { return i; }
179         }
180         new Object() {
181             int s() { return s; }
182             Foo foo() { return new Foo(); }
183         };
184     }
185 
186     class Inner { }
187 
188     @Reflect
189     @IR("""
190             func @"testImplicitInner" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
191                 %1 : java.type:"java.util.function.Supplier<LocalClassTest::Inner>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::Inner" -> {
192                     %2 : java.type:"LocalClassTest::Inner" = new %0 @java.ref:"LocalClassTest::Inner::(LocalClassTest)";
193                     return %2;
194                 };
195                 %3 : Var<java.type:"java.util.function.Supplier<LocalClassTest::Inner>"> = var %1 @"aNew";
196                 return;
197             };
198             """)
199     void testImplicitInner() {
200         Supplier<Inner> aNew = (@Reflect Supplier<Inner>) () -> new Inner();
201     }
202 
203     @Reflect
204     @IR("""
205             func @"testExplicitInner" (%0 : java.type:"LocalClassTest", %1 : java.type:"LocalClassTest")java.type:"void" -> {
206                 %2 : Var<java.type:"LocalClassTest"> = var %1 @"test";
207                 %3 : java.type:"java.util.function.Supplier<LocalClassTest::Inner>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::Inner" -> {
208                     %4 : java.type:"LocalClassTest" = var.load %2;
209                     %5 : java.type:"LocalClassTest::Inner" = new %4 @java.ref:"LocalClassTest::Inner::(LocalClassTest)";
210                     return %5;
211                 };
212                 %6 : Var<java.type:"java.util.function.Supplier<LocalClassTest::Inner>"> = var %3 @"aNew";
213                 return;
214             };
215             """)
216     void testExplicitInner(LocalClassTest test) {
217         Supplier<Inner> aNew = (@Reflect Supplier<Inner>) () -> test.new Inner();
218     }
219 
220     @Reflect
221     @IR("""
222             func @"testLocalInMethod" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
223                 %1 : java.type:"java.util.function.Supplier<LocalClassTest::$1L>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::$1L" -> {
224                     %2 : java.type:"LocalClassTest::$1L" = new %0 @java.ref:"LocalClassTest::$1L::(LocalClassTest)";
225                     return %2;
226                 };
227                 %3 : Var<java.type:"java.util.function.Supplier<LocalClassTest::$1L>"> = var %1 @"aNew";
228                 return;
229             };
230             """)
231     void testLocalInMethod() {
232         class L { }
233         Supplier<L> aNew = (@Reflect Supplier<L>) () -> new L();
234     }
235 
236     @Reflect
237     @IR("""
238             func @"testLocalInLambda" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
239                 %1 : java.type:"java.util.function.Supplier<java.lang.Object>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Object" -> {
240                     %2 : java.type:"LocalClassTest::$2L" = new %0 @java.ref:"LocalClassTest::$2L::(LocalClassTest)";
241                     return %2;
242                 };
243                 %3 : Var<java.type:"java.util.function.Supplier<java.lang.Object>"> = var %1 @"aNew";
244                 return;
245             };
246             """)
247     void testLocalInLambda() {
248         Supplier<Object> aNew = (@Reflect Supplier<Object>) () -> {
249             class L { }
250             return new L();
251         };
252     }
253 
254     @Reflect
255     @IR("""
256             func @"testLocalInMethodWithCaptures" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
257                 %1 : java.type:"java.lang.String" = constant @"Foo";
258                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
259                 %3 : java.type:"java.util.function.Supplier<LocalClassTest::$3L>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::$3L" -> {
260                     %4 : java.type:"java.lang.String" = var.load %2;
261                     %5 : java.type:"LocalClassTest::$3L" = new %0 %4 @java.ref:"LocalClassTest::$3L::(LocalClassTest, java.lang.String)";
262                     return %5;
263                 };
264                 %6 : Var<java.type:"java.util.function.Supplier<LocalClassTest::$3L>"> = var %3 @"aNew";
265                 return;
266             };
267             """)
268     void testLocalInMethodWithCaptures() {
269         String s = "Foo";
270         class L {
271             String s() {
272                 return s;
273             }
274         }
275         Supplier<L> aNew = (@Reflect Supplier<L>) () -> new L();
276     }
277 
278     @Reflect
279     @IR("""
280             func @"testLocalInLambdaWithCaptures" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
281                 %1 : java.type:"java.lang.String" = constant @"Foo";
282                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
283                 %3 : java.type:"java.util.function.Supplier<java.lang.Object>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Object" -> {
284                     %4 : java.type:"java.lang.String" = var.load %2;
285                     %5 : java.type:"LocalClassTest::$4L" = new %0 %4 @java.ref:"LocalClassTest::$4L::(LocalClassTest, java.lang.String)";
286                     return %5;
287                 };
288                 %6 : Var<java.type:"java.util.function.Supplier<java.lang.Object>"> = var %3 @"aNew";
289                 return;
290             };
291             """)
292     void testLocalInLambdaWithCaptures() {
293         String s = "Foo";
294         Supplier<Object> aNew = (@Reflect Supplier<Object>) () -> {
295             class L {
296                 String s() {
297                     return s;
298                 }
299             }
300             return new L();
301         };
302     }
303 
304     @Reflect
305     @IR("""
306             func @"testAnonInLambda" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
307                 %1 : java.type:"java.util.function.Supplier<java.lang.Object>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Object" -> {
308                     %2 : java.type:"LocalClassTest::$5" = new %0 @java.ref:"LocalClassTest::$5::(LocalClassTest)";
309                     return %2;
310                 };
311                 %3 : Var<java.type:"java.util.function.Supplier<java.lang.Object>"> = var %1 @"so";
312                 return;
313             };
314             """)
315     void testAnonInLambda() {
316         Supplier<Object> so = () -> new Object() { };
317     }
318 }