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:"java.lang.Object" = invoke %4 @java.ref:"java.util.Objects::requireNonNull(java.lang.Object):java.lang.Object";
210                     %6 : java.type:"LocalClassTest::Inner" = new %5 @java.ref:"LocalClassTest::Inner::(LocalClassTest)";
211                     return %6;
212                 };
213                 %7 : Var<java.type:"java.util.function.Supplier<LocalClassTest::Inner>"> = var %3 @"aNew";
214                 return;
215             };
216             """)
217     void testExplicitInner(LocalClassTest test) {
218         Supplier<Inner> aNew = (@Reflect Supplier<Inner>) () -> test.new Inner();
219     }
220 
221     @Reflect
222     @IR("""
223             func @"testLocalInMethod" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
224                 %1 : java.type:"java.util.function.Supplier<LocalClassTest::$1L>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::$1L" -> {
225                     %2 : java.type:"LocalClassTest::$1L" = new %0 @java.ref:"LocalClassTest::$1L::(LocalClassTest)";
226                     return %2;
227                 };
228                 %3 : Var<java.type:"java.util.function.Supplier<LocalClassTest::$1L>"> = var %1 @"aNew";
229                 return;
230             };
231             """)
232     void testLocalInMethod() {
233         class L { }
234         Supplier<L> aNew = (@Reflect Supplier<L>) () -> new L();
235     }
236 
237     @Reflect
238     @IR("""
239             func @"testLocalInLambda" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
240                 %1 : java.type:"java.util.function.Supplier<java.lang.Object>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Object" -> {
241                     %2 : java.type:"LocalClassTest::$2L" = new %0 @java.ref:"LocalClassTest::$2L::(LocalClassTest)";
242                     return %2;
243                 };
244                 %3 : Var<java.type:"java.util.function.Supplier<java.lang.Object>"> = var %1 @"aNew";
245                 return;
246             };
247             """)
248     void testLocalInLambda() {
249         Supplier<Object> aNew = (@Reflect Supplier<Object>) () -> {
250             class L { }
251             return new L();
252         };
253     }
254 
255     @Reflect
256     @IR("""
257             func @"testLocalInMethodWithCaptures" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
258                 %1 : java.type:"java.lang.String" = constant @"Foo";
259                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
260                 %3 : java.type:"java.util.function.Supplier<LocalClassTest::$3L>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::$3L" -> {
261                     %4 : java.type:"java.lang.String" = var.load %2;
262                     %5 : java.type:"LocalClassTest::$3L" = new %0 %4 @java.ref:"LocalClassTest::$3L::(LocalClassTest, java.lang.String)";
263                     return %5;
264                 };
265                 %6 : Var<java.type:"java.util.function.Supplier<LocalClassTest::$3L>"> = var %3 @"aNew";
266                 return;
267             };
268             """)
269     void testLocalInMethodWithCaptures() {
270         String s = "Foo";
271         class L {
272             String s() {
273                 return s;
274             }
275         }
276         Supplier<L> aNew = (@Reflect Supplier<L>) () -> new L();
277     }
278 
279     @Reflect
280     @IR("""
281             func @"testLocalInLambdaWithCaptures" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
282                 %1 : java.type:"java.lang.String" = constant @"Foo";
283                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
284                 %3 : java.type:"java.util.function.Supplier<java.lang.Object>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Object" -> {
285                     %4 : java.type:"java.lang.String" = var.load %2;
286                     %5 : java.type:"LocalClassTest::$4L" = new %0 %4 @java.ref:"LocalClassTest::$4L::(LocalClassTest, java.lang.String)";
287                     return %5;
288                 };
289                 %6 : Var<java.type:"java.util.function.Supplier<java.lang.Object>"> = var %3 @"aNew";
290                 return;
291             };
292             """)
293     void testLocalInLambdaWithCaptures() {
294         String s = "Foo";
295         Supplier<Object> aNew = (@Reflect Supplier<Object>) () -> {
296             class L {
297                 String s() {
298                     return s;
299                 }
300             }
301             return new L();
302         };
303     }
304 
305     @Reflect
306     @IR("""
307             func @"testAnonInLambda" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
308                 %1 : java.type:"java.util.function.Supplier<java.lang.Object>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Object" -> {
309                     %2 : java.type:"LocalClassTest::$5" = new %0 @java.ref:"LocalClassTest::$5::(LocalClassTest)";
310                     return %2;
311                 };
312                 %3 : Var<java.type:"java.util.function.Supplier<java.lang.Object>"> = var %1 @"so";
313                 return;
314             };
315             """)
316     void testAnonInLambda() {
317         Supplier<Object> so = () -> new Object() { };
318     }
319 }