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 : java.type:"java.lang.String" = var.load %2;
110                 %5 : java.type:"LocalClassTest::$3Foo" = new %0 %4 @java.ref:"LocalClassTest::$3Foo::(LocalClassTest, java.lang.String)";
111                 %6 : java.type:"java.lang.String" = invoke %5 @java.ref:"LocalClassTest::$3Foo::m():java.lang.String";
112                 return %6;
113             };
114             """)
115     String testLocalCaptureParamAndField(String s) {
116         final String localConst = "Hello!";
117         class Foo {
118             String m() { return localConst + s + nonConstString + CONST_STRING; }
119         }
120         return new Foo().m();
121     }
122 
123     @Reflect
124     @IR("""
125             func @"testAnonCaptureParamAndField" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
126                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
127                 %3 : java.type:"java.lang.String" = constant @"Hello!";
128                 %4 : java.type:"java.lang.String" = var.load %2;
129                 %5 : java.type:"LocalClassTest::$3" = new %0 %4 @java.ref:"LocalClassTest::$3::(LocalClassTest, java.lang.String)";
130                 %6 : java.type:"java.lang.String" = invoke %5 @java.ref:"LocalClassTest::$3::m():java.lang.String";
131                 return %6;
132             };
133             """)
134     String testAnonCaptureParamAndField(String s) {
135         final String localConst = "Hello!";
136         return new Object() {
137             String m() { return localConst + s + nonConstString + CONST_STRING; }
138         }.m();
139     }
140 
141     @Reflect
142     @IR("""
143             func @"testLocalDependency" (%0 : java.type:"LocalClassTest", %1 : java.type:"int", %2 : java.type:"int")java.type:"void" -> {
144                 %3 : Var<java.type:"int"> = var %1 @"s";
145                 %4 : Var<java.type:"int"> = var %2 @"i";
146                 %5 : java.type:"int" = var.load %3;
147                 %6 : java.type:"int" = var.load %4;
148                 %7 : java.type:"LocalClassTest::$1Bar" = new %0 %5 %6 @java.ref:"LocalClassTest::$1Bar::(LocalClassTest, int, int)";
149                 return;
150             };
151             """)
152     void testLocalDependency(int s, int i) {
153         class Foo {
154             int i() { return i; }
155         }
156         class Bar {
157             int s() { return s; }
158             Foo foo() { return new Foo(); }
159         }
160         new Bar();
161     }
162 
163     @Reflect
164     @IR("""
165             func @"testAnonDependency" (%0 : java.type:"LocalClassTest", %1 : java.type:"int", %2 : java.type:"int")java.type:"void" -> {
166                 %3 : Var<java.type:"int"> = var %1 @"s";
167                 %4 : Var<java.type:"int"> = var %2 @"i";
168                 %5 : java.type:"int" = var.load %3;
169                 %6 : java.type:"int" = var.load %4;
170                 %7 : java.type:"LocalClassTest::$4" = new %0 %5 %6 @java.ref:"LocalClassTest::$4::(LocalClassTest, int, int)";
171                 return;
172             };
173             """)
174     void testAnonDependency(int s, int i) {
175         class Foo {
176             int i() { return i; }
177         }
178         new Object() {
179             int s() { return s; }
180             Foo foo() { return new Foo(); }
181         };
182     }
183 
184     class Inner { }
185 
186     @Reflect
187     @IR("""
188             func @"testImplicitInner" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
189                 %1 : java.type:"java.util.function.Supplier<LocalClassTest::Inner>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::Inner" -> {
190                     %2 : java.type:"LocalClassTest::Inner" = new %0 @java.ref:"LocalClassTest::Inner::(LocalClassTest)";
191                     return %2;
192                 };
193                 %3 : Var<java.type:"java.util.function.Supplier<LocalClassTest::Inner>"> = var %1 @"aNew";
194                 return;
195             };
196             """)
197     void testImplicitInner() {
198         Supplier<Inner> aNew = (@Reflect Supplier<Inner>) () -> new Inner();
199     }
200 
201     @Reflect
202     @IR("""
203             func @"testExplicitInner" (%0 : java.type:"LocalClassTest", %1 : java.type:"LocalClassTest")java.type:"void" -> {
204                 %2 : Var<java.type:"LocalClassTest"> = var %1 @"test";
205                 %3 : java.type:"java.util.function.Supplier<LocalClassTest::Inner>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::Inner" -> {
206                     %4 : java.type:"LocalClassTest" = var.load %2;
207                     %5 : java.type:"java.lang.Object" = invoke %4 @java.ref:"java.util.Objects::requireNonNull(java.lang.Object):java.lang.Object";
208                     %6 : java.type:"LocalClassTest::Inner" = new %4 @java.ref:"LocalClassTest::Inner::(LocalClassTest)";
209                     return %6;
210                 };
211                 %7 : Var<java.type:"java.util.function.Supplier<LocalClassTest::Inner>"> = var %3 @"aNew";
212                 return;
213             };
214             """)
215     void testExplicitInner(LocalClassTest test) {
216         Supplier<Inner> aNew = (@Reflect Supplier<Inner>) () -> test.new Inner();
217     }
218 
219     @Reflect
220     @IR("""
221             func @"testLocalInMethod" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
222                 %1 : java.type:"java.util.function.Supplier<LocalClassTest::$1L>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::$1L" -> {
223                     %2 : java.type:"LocalClassTest::$1L" = new %0 @java.ref:"LocalClassTest::$1L::(LocalClassTest)";
224                     return %2;
225                 };
226                 %3 : Var<java.type:"java.util.function.Supplier<LocalClassTest::$1L>"> = var %1 @"aNew";
227                 return;
228             };
229             """)
230     void testLocalInMethod() {
231         class L { }
232         Supplier<L> aNew = (@Reflect Supplier<L>) () -> new L();
233     }
234 
235     @Reflect
236     @IR("""
237             func @"testLocalInLambda" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
238                 %1 : java.type:"java.util.function.Supplier<java.lang.Object>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Object" -> {
239                     %2 : java.type:"LocalClassTest::$2L" = new %0 @java.ref:"LocalClassTest::$2L::(LocalClassTest)";
240                     return %2;
241                 };
242                 %3 : Var<java.type:"java.util.function.Supplier<java.lang.Object>"> = var %1 @"aNew";
243                 return;
244             };
245             """)
246     void testLocalInLambda() {
247         Supplier<Object> aNew = (@Reflect Supplier<Object>) () -> {
248             class L { }
249             return new L();
250         };
251     }
252 
253     @Reflect
254     @IR("""
255             func @"testLocalInMethodWithCaptures" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
256                 %1 : java.type:"java.lang.String" = constant @"Foo";
257                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
258                 %3 : java.type:"java.util.function.Supplier<LocalClassTest::$3L>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::$3L" -> {
259                     %4 : java.type:"java.lang.String" = var.load %2;
260                     %5 : java.type:"LocalClassTest::$3L" = new %0 %4 @java.ref:"LocalClassTest::$3L::(LocalClassTest, java.lang.String)";
261                     return %5;
262                 };
263                 %6 : Var<java.type:"java.util.function.Supplier<LocalClassTest::$3L>"> = var %3 @"aNew";
264                 return;
265             };
266             """)
267     void testLocalInMethodWithCaptures() {
268         String s = "Foo";
269         class L {
270             String s() {
271                 return s;
272             }
273         }
274         Supplier<L> aNew = (@Reflect Supplier<L>) () -> new L();
275     }
276 
277     @Reflect
278     @IR("""
279             func @"testLocalInLambdaWithCaptures" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
280                 %1 : java.type:"java.lang.String" = constant @"Foo";
281                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
282                 %3 : java.type:"java.util.function.Supplier<java.lang.Object>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Object" -> {
283                     %4 : java.type:"java.lang.String" = var.load %2;
284                     %5 : java.type:"LocalClassTest::$4L" = new %0 %4 @java.ref:"LocalClassTest::$4L::(LocalClassTest, java.lang.String)";
285                     return %5;
286                 };
287                 %6 : Var<java.type:"java.util.function.Supplier<java.lang.Object>"> = var %3 @"aNew";
288                 return;
289             };
290             """)
291     void testLocalInLambdaWithCaptures() {
292         String s = "Foo";
293         Supplier<Object> aNew = (@Reflect Supplier<Object>) () -> {
294             class L {
295                 String s() {
296                     return s;
297                 }
298             }
299             return new L();
300         };
301     }
302 
303     @Reflect
304     @IR("""
305             func @"testAnonInLambda" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
306                 %1 : java.type:"java.util.function.Supplier<java.lang.Object>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Object" -> {
307                     %2 : java.type:"LocalClassTest::$5" = new %0 @java.ref:"LocalClassTest::$5::(LocalClassTest)";
308                     return %2;
309                 };
310                 %3 : Var<java.type:"java.util.function.Supplier<java.lang.Object>"> = var %1 @"so";
311                 return;
312             };
313             """)
314     void testAnonInLambda() {
315         Supplier<Object> so = () -> new Object() { };
316     }
317 }