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