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.
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 * @bug 8324873
27 * @summary Test valid placements of super()/this() in constructors
28 * @enablePreview
29 */
30
31 import java.util.ArrayList;
32 import java.util.List;
33
34 public value class ValueClassSuperInitGood {
35
36 ValueClassSuperInitGood(Object obj) {
37 }
38
39 ValueClassSuperInitGood(int x) {
40 }
41
42 // Default constructor provided by compiler
43 static value class Test0 {
44 }
45
46 // No explicit calls to this()/super()
47 static abstract value class Test1 {
48 Test1() {
49 }
50 Test1(int a) {
51 super();
52 this.hashCode();
53 }
54 }
55
56 // Explicit calls to this()/super()
57 static abstract value class Test2<T> {
58 static int i;
59 Test2() {
60 this(0);
61 }
62 Test2(int i) {
63 Test2.i = i;
64 super();
65 }
66 Test2(T obj) {
67 this(java.util.Objects.hashCode(obj));
68 }
69 public T get() {
70 return null;
71 }
72 }
73
74 // Explicit this()/super() with stuff in front
75 static value class Test3 {
76 int x;
77 final int y;
78 final int z;
79
80 Test3() {
81 new Object().hashCode();
82 new Object().hashCode();
83 this.x = new Object().hashCode();
84 this.y = new Object().hashCode() % 17;
85 this.z = this.x + this.y;
86 super();
87 }
88 }
89
90 static abstract value class Test5Abstract {
91 Test5Abstract(Object obj) {}
92 }
93
94 // Reference within constructor to outer class that's also my superclass
95 abstract value class Test5 extends Test5Abstract {
96 Test5(Object obj) {
97 if (obj == null)
98 throw new IllegalArgumentException();
99 super(ValueClassSuperInitGood.this); // NOT a 'this' reference
100 }
101 }
102
103 // Initialization blocks
104 value class Test6 {
105 final long startTime;
106 List<String> l = new ArrayList<>();
107 {
108 l.add("");
109 }
110 Test6() {
111 long now = System.nanoTime();
112 long then = now + 1000000L;
113 while (System.nanoTime() < then) {
114 try {
115 Thread.sleep(1);
116 } catch (InterruptedException e) {
117 Thread.currentThread().interrupt();
118 break;
119 }
120 }
121 this.startTime = now;
122 super();
123 }
124 }
125
126 // Mix up inner classes, proxies, and super() calls
127 // Copied mostly from UnverifiableInitForNestedLocalClassTest.java
128 public static void test7(final String arg) {
129 final String inlined = " inlined ";
130 abstract value class LocalClass {
131 String m() {
132 return "LocalClass " + arg + inlined;
133 }
134
135 abstract value class SubClass extends LocalClass {
136 @Override
137 String m() {
138 return "SubClass " + arg + inlined;
139 }
140 }
141
142 value class SubSubClass extends SubClass {
143 @Override
144 String m() {
145 return "SubSubClass " + arg + inlined;
146 }
147 }
148
149 value class AnotherLocal {
150 value class AnotherSub extends LocalClass {
151 AnotherSub() {
152 }
153 AnotherSub(int x) {
154 this((char)x);
155 }
156 AnotherSub(char y) {
157 super();
158 }
159 @Override
160 String m() {
161 return "AnotherSub " + arg + inlined;
162 }
163 }
164 }
165 }
166 }
167
168 // Anonymous inner class
169 public static void test8() {
170 new Test2<Byte>(null) {
171 @Override
172 public Byte get() {
173 return (byte)-1;
174 }
175 };
176 }
177
178 // Qualified super() invocation
179 public static value class Test9 extends Test5 {
180
181 public Test9(ValueClassSuperInitGood implicit, Object obj) {
182 obj.hashCode();
183 implicit.super(obj);
184 }
185 }
186
187 // Copied from WhichImplicitThis6
188 public static abstract value class Test10 {
189 private int i;
190 public Test10(int i) { this.i = i; }
191 public value class Sub extends Test10 {
192 public Sub() {
193 super(i); // i is not inherited, so it is the enclosing i
194 }
195 }
196 }
197
198 // Two constructors where only one invokes super()
199 public static value class Test11 {
200 public Test11() {
201 }
202 public Test11(int x) {
203 super();
204 }
205 }
206
207 // Nested version of the previous test
208 public static value class Test12 {
209 Test12() {
210 class Sub {
211 public Sub() {
212 }
213 public Sub(int j) {
214 super();
215 }
216 }
217 }
218 }
219
220 // Nested super()'s requiring initialization code appended
221 public static value class Test13 extends Test5Abstract {
222 final int x = new Object().hashCode();
223 Test13() {
224 super(new Object() {
225 public void foo() {
226 class Bar {
227 final int y = new Object().hashCode();
228 Bar() {
229 super();
230 }
231 Bar(int ignored) {
232 }
233 }
234 }
235 });
236 }
237 }
238
239 // Qualified super() invocation with superclass instance
240 public static abstract value class Test15 {
241
242 final String name;
243
244 public Test15(String name) {
245 this.name = name;
246 }
247
248 public abstract value class Test15b extends Test15 {
249
250 public Test15b(String name) {
251 super(name);
252 }
253
254 public String getName() {
255 return Test15.this.name;
256 }
257 }
258 }
259
260 public static value class Test15c extends Test15.Test15b {
261 public Test15c(Test15 a, String name) {
262 a.super(name);
263 }
264 }
265
266 // Mixing up outer instances, proxies, and initializers
267 public static value class Test16 {
268
269 final String x = String.valueOf(new Object().hashCode());
270
271 public void run() {
272
273 final String y = String.valueOf(new Object().hashCode());
274
275 class Sub {
276
277 final String z;
278
279 Sub(String z, int ignored) {
280 this(z, (float)ignored);
281 }
282
283 Sub(String z, float ignored) {
284 this.z = z;
285 }
286
287 Sub(String z, byte ignored) {
288 super();
289 this.z = z;
290 }
291
292 Sub(String z, char ignored) {
293 this(z, (int)ignored);
294 }
295
296 String x() {
297 return x;
298 }
299
300 String y() {
301 return y;
302 }
303
304 String z() {
305 return z;
306 }
307 }
308
309 final String z = String.valueOf(new Object().hashCode());
310
311 final Sub[] subs = new Sub[] {
312 new Sub(z, 1),
313 new Sub(z, -1),
314 new Sub(z, (float)0),
315 new Sub(z, (byte)0),
316 new Sub(z, (char)0)
317 };
318
319 for (int i = 0; i < subs.length; i++) {
320 //System.err.println("i = " + i);
321 final Sub sub = subs[i];
322 final String subx = sub.x();
323 final String suby = sub.y();
324 final String subz = sub.z();
325 if (!x.equals(subx))
326 throw new RuntimeException("x=" + x + " but sub[" + i + "].x()=" + subx);
327 if (!y.equals(suby))
328 throw new RuntimeException("y=" + y + " but sub[" + i + "].y()=" + suby);
329 if (!z.equals(subz))
330 throw new RuntimeException("z=" + z + " but sub[" + i + "].z()=" + subz);
331 }
332 }
333 }
334
335 // Records
336 public value class Test17 {
337
338 record Rectangle(float length, float width) { }
339
340 record StringHolder(String string) {
341 StringHolder {
342 java.util.Objects.requireNonNull(string);
343 }
344 }
345
346 record ValueHolder(int value) {
347 ValueHolder(float x) {
348 if (Float.isNaN(x))
349 throw new IllegalArgumentException();
350 this((int)x);
351 }
352 }
353 }
354
355 static abstract value class AR<V> implements java.io.Serializable {
356 public AR(V initialValue) {
357 }
358
359 public AR() {
360 }
361
362 public final V get() {
363 return null;
364 }
365 }
366
367 // super()/this() within outer try block but inside inner class
368 public static value class Test19 {
369 public Test19(int x) {
370 try {
371 new Test1(x) {
372 @Override
373 public int hashCode() {
374 return x ^ super.hashCode();
375 }
376 };
377 } catch (StackOverflowError e) {
378 // ignore
379 }
380 }
381 }
382
383 public static value class Test20 {
384 private final int[] data1 = new int[10];
385 private final int[] data2 = new int[10];
386 private final int[] data3 = new int[10];
387 Test20() {
388 for (int i = 0; i < data1.length; i++) {
389 data1[i] = i; // OK we are assigning to an array component
390 this.data2[i] = i; // OK we are assigning to an array component
391 Test20.this.data3[i] = i; // OK we are assigning to an array component
392 }
393 }
394 }
395
396 public static void main(String[] args) {
397 new Test0();
398 new Test1() {};
399 new Test1(7) {};
400 new Test2<Byte>() {};
401 new Test2<>(args) {};
402 new Test3();
403 new ValueClassSuperInitGood(3).new Test5(3) {};
404 new ValueClassSuperInitGood(3).new Test6();
405 ValueClassSuperInitGood.test7("foo");
406 ValueClassSuperInitGood.test8();
407 new Test9(new ValueClassSuperInitGood(5), "abc");
408 new Test10(7) {};
409 new Test11(9);
410 new Test12();
411 new Test13();
412 new Test15c(new Test15("foo"){}, "bar");
413 new Test16().run();
414 new Test17.StringHolder("foo");
415 try {
416 new Test17.StringHolder(null);
417 throw new Error();
418 } catch (NullPointerException e) {
419 // expected
420 }
421 new Test19(123);
422 new Test20();
423 }
424 }