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  * @ignore Reflection on the contents of local classes is not supported.
 27  * @summary Smoke test for code reflection with local class creation expressions.
 28  * @modules jdk.incubator.code
 29  * @build LocalClassTest
 30  * @build CodeReflectionTester
 31  * @run main CodeReflectionTester LocalClassTest
 32  */
 33 
 34 import jdk.incubator.code.Reflect;
 35 
 36 import java.util.function.Supplier;
 37 
 38 public class LocalClassTest {
 39 
 40     final static String CONST_STRING = "Hello!";
 41     String nonConstString = "Hello!";
 42 
 43     @Reflect
 44     @IR("""
 45             func @"testLocalNoCapture" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
 46                 %1 : java.type:"LocalClassTest::$1Foo" = new %0 @java.ref:"LocalClassTest::$1Foo::(LocalClassTest)";
 47                 invoke %1 @java.ref:"LocalClassTest::$1Foo::m():void";
 48                 return;
 49             };
 50             """)
 51     void testLocalNoCapture() {
 52         class Foo {
 53             void m() { }
 54         }
 55         new Foo().m();
 56     }
 57 
 58     @Reflect
 59     @IR("""
 60             func @"testAnonNoCapture" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
 61                 %1 : java.type:"LocalClassTest::$1" = new %0 @java.ref:"LocalClassTest::$1::(LocalClassTest)";
 62                 invoke %1 @java.ref:"LocalClassTest::$1::m():void";
 63                 return;
 64             };
 65             """)
 66     void testAnonNoCapture() {
 67         new Object() {
 68             void m() { }
 69         }.m();
 70     }
 71 
 72     @Reflect
 73     @IR("""
 74             func @"testLocalCaptureParam" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
 75                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
 76                 %3 : java.type:"java.lang.String" = var.load %2;
 77                 %4 : java.type:"LocalClassTest::$2Foo" = new %0 %3 @java.ref:"LocalClassTest::$2Foo::(LocalClassTest, java.lang.String)";
 78                 %5 : java.type:"java.lang.String" = invoke %4 @java.ref:"LocalClassTest::$2Foo::m():java.lang.String";
 79                 return %5;
 80             };
 81             """)
 82     String testLocalCaptureParam(String s) {
 83         class Foo {
 84             String m() { return s; }
 85         }
 86         return new Foo().m();
 87     }
 88 
 89     @Reflect
 90     @IR("""
 91             func @"testAnonCaptureParam" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
 92                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
 93                 %3 : java.type:"java.lang.String" = var.load %2;
 94                 %4 : java.type:"LocalClassTest::$2" = new %0 %3 @java.ref:"LocalClassTest::$2::(LocalClassTest, java.lang.String)";
 95                 %5 : java.type:"java.lang.String" = invoke %4 @java.ref:"LocalClassTest::$2::m():java.lang.String";
 96                 return %5;
 97             };
 98             """)
 99     String testAnonCaptureParam(String s) {
100         return new Object() {
101             String m() { return s; }
102         }.m();
103     }
104 
105     @Reflect
106     @IR("""
107             func @"testLocalCaptureParamAndField" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
108                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
109                 %3 : java.type:"java.lang.String" = constant @"Hello!";
110                 %4 : Var<java.type:"java.lang.String"> = var %3 @"localConst";
111                 %5 : java.type:"java.lang.String" = var.load %2;
112                 %6 : java.type:"LocalClassTest::$3Foo" = new %0 %5 @java.ref:"LocalClassTest::$3Foo::(LocalClassTest, java.lang.String)";
113                 %7 : java.type:"java.lang.String" = invoke %6 @java.ref:"LocalClassTest::$3Foo::m():java.lang.String";
114                 return %7;
115             };
116             """)
117     String testLocalCaptureParamAndField(String s) {
118         final String localConst = "Hello!";
119         class Foo {
120             String m() { return localConst + s + nonConstString + CONST_STRING; }
121         }
122         return new Foo().m();
123     }
124 
125     @Reflect
126     @IR("""
127             func @"testAnonCaptureParamAndField" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
128                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
129                 %3 : java.type:"java.lang.String" = constant @"Hello!";
130                 %4 : Var<java.type:"java.lang.String"> = var %3 @"localConst";
131                 %5 : java.type:"java.lang.String" = var.load %2;
132                 %6 : java.type:"LocalClassTest::$3" = new %0 %5 @java.ref:"LocalClassTest::$3::(LocalClassTest, java.lang.String)";
133                 %7 : java.type:"java.lang.String" = invoke %6 @java.ref:"LocalClassTest::$3::m():java.lang.String";
134                 return %7;
135             };
136             """)
137     String testAnonCaptureParamAndField(String s) {
138         final String localConst = "Hello!";
139         return new Object() {
140             String m() { return localConst + s + nonConstString + CONST_STRING; }
141         }.m();
142     }
143 
144     @Reflect
145     @IR("""
146             func @"testLocalDependency" (%0 : java.type:"LocalClassTest", %1 : java.type:"int", %2 : java.type:"int")java.type:"void" -> {
147                 %3 : Var<java.type:"int"> = var %1 @"s";
148                 %4 : Var<java.type:"int"> = var %2 @"i";
149                 %5 : java.type:"int" = var.load %3;
150                 %6 : java.type:"int" = var.load %4;
151                 %7 : java.type:"LocalClassTest::$1Bar" = new %0 %5 %6 @java.ref:"LocalClassTest::$1Bar::(LocalClassTest, int, int)";
152                 return;
153             };
154             """)
155     void testLocalDependency(int s, int i) {
156         class Foo {
157             int i() { return i; }
158         }
159         class Bar {
160             int s() { return s; }
161             Foo foo() { return new Foo(); }
162         }
163         new Bar();
164     }
165 
166     @Reflect
167     @IR("""
168             func @"testAnonDependency" (%0 : java.type:"LocalClassTest", %1 : java.type:"int", %2 : java.type:"int")java.type:"void" -> {
169                 %3 : Var<java.type:"int"> = var %1 @"s";
170                 %4 : Var<java.type:"int"> = var %2 @"i";
171                 %5 : java.type:"int" = var.load %3;
172                 %6 : java.type:"int" = var.load %4;
173                 %7 : java.type:"LocalClassTest::$4" = new %0 %5 %6 @java.ref:"LocalClassTest::$4::(LocalClassTest, int, int)";
174                 return;
175             };
176             """)
177     void testAnonDependency(int s, int i) {
178         class Foo {
179             int i() { return i; }
180         }
181         new Object() {
182             int s() { return s; }
183             Foo foo() { return new Foo(); }
184         };
185     }
186 
187     class Inner { }
188 
189     @Reflect
190     @IR("""
191             func @"testImplicitInner" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
192                 %1 : java.type:"java.util.function.Supplier<LocalClassTest::Inner>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::Inner" -> {
193                     %2 : java.type:"LocalClassTest::Inner" = new %0 @java.ref:"LocalClassTest::Inner::(LocalClassTest)";
194                     return %2;
195                 };
196                 %3 : Var<java.type:"java.util.function.Supplier<LocalClassTest::Inner>"> = var %1 @"aNew";
197                 return;
198             };
199             """)
200     void testImplicitInner() {
201         Supplier<Inner> aNew = (@Reflect Supplier<Inner>) () -> new Inner();
202     }
203 
204     @Reflect
205     @IR("""
206             func @"testExplicitInner" (%0 : java.type:"LocalClassTest", %1 : java.type:"LocalClassTest")java.type:"void" -> {
207                 %2 : Var<java.type:"LocalClassTest"> = var %1 @"test";
208                 %3 : java.type:"java.util.function.Supplier<LocalClassTest::Inner>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::Inner" -> {
209                     %4 : java.type:"LocalClassTest" = var.load %2;
210                     %5 : java.type:"LocalClassTest::Inner" = new %4 @java.ref:"LocalClassTest::Inner::(LocalClassTest)";
211                     return %5;
212                 };
213                 %6 : 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 }