1 /*
  2  * Copyright (c) 2024, 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.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 /*
 27  * @test
 28  * @ignore Reflection on the contents of local classes is not supported.
 29  * @summary Smoke test for code reflection with local class creation expressions.
 30  * @modules jdk.incubator.code
 31  * @build LocalClassTest
 32  * @build CodeReflectionTester
 33  * @run main CodeReflectionTester LocalClassTest
 34  */
 35 
 36 import jdk.incubator.code.Reflect;
 37 
 38 import java.util.function.Supplier;
 39 
 40 public class LocalClassTest {
 41 
 42     final static String CONST_STRING = "Hello!";
 43     String nonConstString = "Hello!";
 44 
 45     @Reflect
 46     @IR("""
 47             func @"testLocalNoCapture" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
 48                 %1 : java.type:"LocalClassTest::$1Foo" = new %0 @java.ref:"LocalClassTest::$1Foo::(LocalClassTest)";
 49                 invoke %1 @java.ref:"LocalClassTest::$1Foo::m():void";
 50                 return;
 51             };
 52             """)
 53     void testLocalNoCapture() {
 54         class Foo {
 55             void m() { }
 56         }
 57         new Foo().m();
 58     }
 59 
 60     @Reflect
 61     @IR("""
 62             func @"testAnonNoCapture" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
 63                 %1 : java.type:"LocalClassTest::$1" = new %0 @java.ref:"LocalClassTest::$1::(LocalClassTest)";
 64                 invoke %1 @java.ref:"LocalClassTest::$1::m():void";
 65                 return;
 66             };
 67             """)
 68     void testAnonNoCapture() {
 69         new Object() {
 70             void m() { }
 71         }.m();
 72     }
 73 
 74     @Reflect
 75     @IR("""
 76             func @"testLocalCaptureParam" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
 77                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
 78                 %3 : java.type:"java.lang.String" = var.load %2;
 79                 %4 : java.type:"LocalClassTest::$2Foo" = new %0 %3 @java.ref:"LocalClassTest::$2Foo::(LocalClassTest, java.lang.String)";
 80                 %5 : java.type:"java.lang.String" = invoke %4 @java.ref:"LocalClassTest::$2Foo::m():java.lang.String";
 81                 return %5;
 82             };
 83             """)
 84     String testLocalCaptureParam(String s) {
 85         class Foo {
 86             String m() { return s; }
 87         }
 88         return new Foo().m();
 89     }
 90 
 91     @Reflect
 92     @IR("""
 93             func @"testAnonCaptureParam" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
 94                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
 95                 %3 : java.type:"java.lang.String" = var.load %2;
 96                 %4 : java.type:"LocalClassTest::$2" = new %0 %3 @java.ref:"LocalClassTest::$2::(LocalClassTest, java.lang.String)";
 97                 %5 : java.type:"java.lang.String" = invoke %4 @java.ref:"LocalClassTest::$2::m():java.lang.String";
 98                 return %5;
 99             };
100             """)
101     String testAnonCaptureParam(String s) {
102         return new Object() {
103             String m() { return s; }
104         }.m();
105     }
106 
107     @Reflect
108     @IR("""
109             func @"testLocalCaptureParamAndField" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
110                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
111                 %3 : java.type:"java.lang.String" = constant @"Hello!";
112                 %4 : Var<java.type:"java.lang.String"> = var %3 @"localConst";
113                 %5 : java.type:"java.lang.String" = var.load %2;
114                 %6 : java.type:"LocalClassTest::$3Foo" = new %0 %5 @java.ref:"LocalClassTest::$3Foo::(LocalClassTest, java.lang.String)";
115                 %7 : java.type:"java.lang.String" = invoke %6 @java.ref:"LocalClassTest::$3Foo::m():java.lang.String";
116                 return %7;
117             };
118             """)
119     String testLocalCaptureParamAndField(String s) {
120         final String localConst = "Hello!";
121         class Foo {
122             String m() { return localConst + s + nonConstString + CONST_STRING; }
123         }
124         return new Foo().m();
125     }
126 
127     @Reflect
128     @IR("""
129             func @"testAnonCaptureParamAndField" (%0 : java.type:"LocalClassTest", %1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
130                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
131                 %3 : java.type:"java.lang.String" = constant @"Hello!";
132                 %4 : Var<java.type:"java.lang.String"> = var %3 @"localConst";
133                 %5 : java.type:"java.lang.String" = var.load %2;
134                 %6 : java.type:"LocalClassTest::$3" = new %0 %5 @java.ref:"LocalClassTest::$3::(LocalClassTest, java.lang.String)";
135                 %7 : java.type:"java.lang.String" = invoke %6 @java.ref:"LocalClassTest::$3::m():java.lang.String";
136                 return %7;
137             };
138             """)
139     String testAnonCaptureParamAndField(String s) {
140         final String localConst = "Hello!";
141         return new Object() {
142             String m() { return localConst + s + nonConstString + CONST_STRING; }
143         }.m();
144     }
145 
146     @Reflect
147     @IR("""
148             func @"testLocalDependency" (%0 : java.type:"LocalClassTest", %1 : java.type:"int", %2 : java.type:"int")java.type:"void" -> {
149                 %3 : Var<java.type:"int"> = var %1 @"s";
150                 %4 : Var<java.type:"int"> = var %2 @"i";
151                 %5 : java.type:"int" = var.load %3;
152                 %6 : java.type:"int" = var.load %4;
153                 %7 : java.type:"LocalClassTest::$1Bar" = new %0 %5 %6 @java.ref:"LocalClassTest::$1Bar::(LocalClassTest, int, int)";
154                 return;
155             };
156             """)
157     void testLocalDependency(int s, int i) {
158         class Foo {
159             int i() { return i; }
160         }
161         class Bar {
162             int s() { return s; }
163             Foo foo() { return new Foo(); }
164         }
165         new Bar();
166     }
167 
168     @Reflect
169     @IR("""
170             func @"testAnonDependency" (%0 : java.type:"LocalClassTest", %1 : java.type:"int", %2 : java.type:"int")java.type:"void" -> {
171                 %3 : Var<java.type:"int"> = var %1 @"s";
172                 %4 : Var<java.type:"int"> = var %2 @"i";
173                 %5 : java.type:"int" = var.load %3;
174                 %6 : java.type:"int" = var.load %4;
175                 %7 : java.type:"LocalClassTest::$4" = new %0 %5 %6 @java.ref:"LocalClassTest::$4::(LocalClassTest, int, int)";
176                 return;
177             };
178             """)
179     void testAnonDependency(int s, int i) {
180         class Foo {
181             int i() { return i; }
182         }
183         new Object() {
184             int s() { return s; }
185             Foo foo() { return new Foo(); }
186         };
187     }
188 
189     class Inner { }
190 
191     @Reflect
192     @IR("""
193             func @"testImplicitInner" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
194                 %1 : java.type:"java.util.function.Supplier<LocalClassTest::Inner>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::Inner" -> {
195                     %2 : java.type:"LocalClassTest::Inner" = new %0 @java.ref:"LocalClassTest::Inner::(LocalClassTest)";
196                     return %2;
197                 };
198                 %3 : Var<java.type:"java.util.function.Supplier<LocalClassTest::Inner>"> = var %1 @"aNew";
199                 return;
200             };
201             """)
202     void testImplicitInner() {
203         Supplier<Inner> aNew = (@Reflect Supplier<Inner>) () -> new Inner();
204     }
205 
206     @Reflect
207     @IR("""
208             func @"testExplicitInner" (%0 : java.type:"LocalClassTest", %1 : java.type:"LocalClassTest")java.type:"void" -> {
209                 %2 : Var<java.type:"LocalClassTest"> = var %1 @"test";
210                 %3 : java.type:"java.util.function.Supplier<LocalClassTest::Inner>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::Inner" -> {
211                     %4 : java.type:"LocalClassTest" = var.load %2;
212                     %5 : java.type:"LocalClassTest::Inner" = new %4 @java.ref:"LocalClassTest::Inner::(LocalClassTest)";
213                     return %5;
214                 };
215                 %6 : Var<java.type:"java.util.function.Supplier<LocalClassTest::Inner>"> = var %3 @"aNew";
216                 return;
217             };
218             """)
219     void testExplicitInner(LocalClassTest test) {
220         Supplier<Inner> aNew = (@Reflect Supplier<Inner>) () -> test.new Inner();
221     }
222 
223     @Reflect
224     @IR("""
225             func @"testLocalInMethod" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
226                 %1 : java.type:"java.util.function.Supplier<LocalClassTest::$1L>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::$1L" -> {
227                     %2 : java.type:"LocalClassTest::$1L" = new %0 @java.ref:"LocalClassTest::$1L::(LocalClassTest)";
228                     return %2;
229                 };
230                 %3 : Var<java.type:"java.util.function.Supplier<LocalClassTest::$1L>"> = var %1 @"aNew";
231                 return;
232             };
233             """)
234     void testLocalInMethod() {
235         class L { }
236         Supplier<L> aNew = (@Reflect Supplier<L>) () -> new L();
237     }
238 
239     @Reflect
240     @IR("""
241             func @"testLocalInLambda" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
242                 %1 : java.type:"java.util.function.Supplier<java.lang.Object>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Object" -> {
243                     %2 : java.type:"LocalClassTest::$2L" = new %0 @java.ref:"LocalClassTest::$2L::(LocalClassTest)";
244                     return %2;
245                 };
246                 %3 : Var<java.type:"java.util.function.Supplier<java.lang.Object>"> = var %1 @"aNew";
247                 return;
248             };
249             """)
250     void testLocalInLambda() {
251         Supplier<Object> aNew = (@Reflect Supplier<Object>) () -> {
252             class L { }
253             return new L();
254         };
255     }
256 
257     @Reflect
258     @IR("""
259             func @"testLocalInMethodWithCaptures" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
260                 %1 : java.type:"java.lang.String" = constant @"Foo";
261                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
262                 %3 : java.type:"java.util.function.Supplier<LocalClassTest::$3L>" = lambda @lambda.isReflectable=true ()java.type:"LocalClassTest::$3L" -> {
263                     %4 : java.type:"java.lang.String" = var.load %2;
264                     %5 : java.type:"LocalClassTest::$3L" = new %0 %4 @java.ref:"LocalClassTest::$3L::(LocalClassTest, java.lang.String)";
265                     return %5;
266                 };
267                 %6 : Var<java.type:"java.util.function.Supplier<LocalClassTest::$3L>"> = var %3 @"aNew";
268                 return;
269             };
270             """)
271     void testLocalInMethodWithCaptures() {
272         String s = "Foo";
273         class L {
274             String s() {
275                 return s;
276             }
277         }
278         Supplier<L> aNew = (@Reflect Supplier<L>) () -> new L();
279     }
280 
281     @Reflect
282     @IR("""
283             func @"testLocalInLambdaWithCaptures" (%0 : java.type:"LocalClassTest")java.type:"void" -> {
284                 %1 : java.type:"java.lang.String" = constant @"Foo";
285                 %2 : Var<java.type:"java.lang.String"> = var %1 @"s";
286                 %3 : java.type:"java.util.function.Supplier<java.lang.Object>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Object" -> {
287                     %4 : java.type:"java.lang.String" = var.load %2;
288                     %5 : java.type:"LocalClassTest::$4L" = new %0 %4 @java.ref:"LocalClassTest::$4L::(LocalClassTest, java.lang.String)";
289                     return %5;
290                 };
291                 %6 : Var<java.type:"java.util.function.Supplier<java.lang.Object>"> = var %3 @"aNew";
292                 return;
293             };
294             """)
295     void testLocalInLambdaWithCaptures() {
296         String s = "Foo";
297         Supplier<Object> aNew = (@Reflect Supplier<Object>) () -> {
298             class L {
299                 String s() {
300                     return s;
301                 }
302             }
303             return new L();
304         };
305     }
306 }