1 /*
2 * Copyright (c) 2022, 2025, 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 * @test
25 * @bug 8194743 8345438 8356551 8349754 8379833
26 * @library /tools/javac/lib
27 * @summary Test valid placements of super()/this() in constructors
28 * @modules jdk.compiler/com.sun.tools.javac.tree
29 * jdk.compiler/com.sun.tools.javac.util
30 * @enablePreview
31 * @run main SuperInitGood
32 */
33
34 import java.util.concurrent.atomic.AtomicReference;
35
36 public class SuperInitGood {
37
38 SuperInitGood(Object obj) {
39 }
40
41 SuperInitGood(int x) {
42 }
43
44 // Default constructor provided by compiler
45 static class Test0 {
46 }
47
48 // No explicit calls to this()/super()
49 static class Test1 {
50 Test1() {
51 }
52
53 Test1(int a) {
54 this.hashCode();
55 }
56 }
57
58 // Explicit calls to this()/super()
59 static class Test2<T> {
60 static int i;
61 Test2() {
62 this(0);
63 }
64 Test2(int i) {
65 Test2.i = i;
66 super();
67 }
68 Test2(T obj) {
69 this(java.util.Objects.hashCode(obj));
70 }
71 public T get() {
72 return null;
73 }
74 }
75
76 // Explicit this()/super() with stuff in front
77 static class Test3 {
78 int x;
79 final int y;
80 final int z;
81
82 Test3() {
83 new Object().hashCode();
84 new Object().hashCode();
85 super();
86 this.x = new Object().hashCode();
87 this.y = new Object().hashCode() % 17;
88 this.z = this.x + this.y;
89 }
90 }
91
92 // Reference within constructor to outer class that's also my superclass
93 class Test5 extends SuperInitGood {
94 Test5(Object obj) {
95 if (obj == null)
96 throw new IllegalArgumentException();
97 super(SuperInitGood.this); // NOT a 'this' reference
98 }
99 }
100
101 // Initialization blocks
102 class Test6 {
103 final long startTime;
104 final int x;
105 {
106 this.x = 12;
107 }
108 Test6() {
109 long now = System.nanoTime();
110 long then = now + 1000000L;
111 while (System.nanoTime() < then) {
112 try {
113 Thread.sleep(1);
114 } catch (InterruptedException e) {
115 Thread.currentThread().interrupt();
116 break;
117 }
118 }
119 super();
120 this.startTime = now;
121 }
122 }
123
124 // Mix up inner classes, proxies, and super() calls
125 // Copied mostly from UnverifiableInitForNestedLocalClassTest.java
126 public static void test7(final String arg) {
127 final String inlined = " inlined ";
128 class LocalClass {
129 String m() {
130 return "LocalClass " + arg + inlined;
131 }
132
133 class SubClass extends LocalClass {
134 @Override
135 String m() {
136 return "SubClass " + arg + inlined;
137 }
138 }
139
140 class SubSubClass extends SubClass {
141 @Override
142 String m() {
143 return "SubSubClass " + arg + inlined;
144 }
145 }
146
147 class AnotherLocal {
148 class AnotherSub extends LocalClass {
149 AnotherSub() {
150 }
151 AnotherSub(int x) {
152 this((char)x);
153 }
154 AnotherSub(char y) {
155 super();
156 }
157 @Override
158 String m() {
159 return "AnotherSub " + arg + inlined;
160 }
161 }
162 }
163 }
164 }
165
166 // Anonymous inner class
167 public static void test8() {
168 new Test2<Byte>(null) {
169 @Override
170 public Byte get() {
171 return (byte)-1;
172 }
173 };
174 }
175
176 // Qualified super() invocation
177 public static class Test9 extends Test5 {
178
179 public Test9(SuperInitGood implicit, Object obj) {
180 obj.hashCode();
181 implicit.super(obj);
182 }
183 }
184
185 // Copied from WhichImplicitThis6
186 public static class Test10 {
187 private int i;
188 public Test10(int i) {}
189 public class Sub extends Test10 {
190 public Sub() {
191 super(i); // i is not inherited, so it is the enclosing i
192 }
193 }
194 }
195
196 // Two constructors where only one invokes super()
197 public static class Test11 {
198 public Test11() {
199 }
200 public Test11(int x) {
201 super();
202 }
203 }
204
205 // Nested version of the previous test
206 public static class Test12 {
207 Test12() {
208 class Sub {
209 public Sub() {
210 }
211 public Sub(int j) {
212 super();
213 }
214 }
215 }
216 }
217
218 // Nested super()'s requiring initialization code appended
219 public static class Test13 extends SuperInitGood {
220 final int x = new Object().hashCode();
221 Test13() {
222 super(new Object() {
223 public void foo() {
224 class Bar {
225 final int y = new Object().hashCode();
226 Bar() {
227 super();
228 }
229 Bar(int ignored) {
230 }
231 }
232 }
233 });
234 }
235 }
236
237 // Initializer in initializer block
238 public static class Test14 {
239 final int x; // initialized in constructor
240 final int y; // initialized in initialization block
241 final int z = 13; // initialized with intializer value
242 public Test14() {
243 this(0);
244 }
245 public Test14(boolean z) {
246 this.x = z ? 1 : 0;
247 }
248 public Test14(int x) {
249 super();
250 this.x = x;
251 }
252 {
253 this.y = -1;
254 }
255 }
256
257 // Qualified super() invocation with superclass instance
258 public static class Test15 {
259
260 final String name;
261
262 public Test15(String name) {
263 this.name = name;
264 }
265
266 public class Test15b extends Test15 {
267
268 public Test15b(String name) {
269 super(name);
270 }
271
272 public String getName() {
273 return Test15.this.name;
274 }
275 }
276 }
277
278 public static class Test15c extends Test15.Test15b {
279 public Test15c(Test15 a, String name) {
280 a.super(name);
281 }
282 }
283
284 // Mixing up outer instances, proxies, and initializers
285 public static class Test16 {
286
287 final String x = String.valueOf(new Object().hashCode());
288
289 public void run() {
290
291 final String y = String.valueOf(new Object().hashCode());
292
293 class Sub {
294
295 final String z;
296
297 Sub(String z, int ignored) {
298 this(z, (float)ignored);
299 }
300
301 Sub(String z, float ignored) {
302 this.z = z;
303 }
304
305 Sub(String z, byte ignored) {
306 super();
307 this.z = z;
308 }
309
310 Sub(String z, char ignored) {
311 this(z, (int)ignored);
312 }
313
314 String x() {
315 return x;
316 }
317
318 String y() {
319 return y;
320 }
321
322 String z() {
323 return z;
324 }
325 }
326
327 final String z = String.valueOf(new Object().hashCode());
328
329 final Sub[] subs = new Sub[] {
330 new Sub(z, 1),
331 new Sub(z, -1),
332 new Sub(z, (float)0),
333 new Sub(z, (byte)0),
334 new Sub(z, (char)0)
335 };
336
337 for (int i = 0; i < subs.length; i++) {
338 //System.err.println("i = " + i);
339 final Sub sub = subs[i];
340 final String subx = sub.x();
341 final String suby = sub.y();
342 final String subz = sub.z();
343 if (!x.equals(subx))
344 throw new RuntimeException("x=" + x + " but sub[" + i + "].x()=" + subx);
345 if (!y.equals(suby))
346 throw new RuntimeException("y=" + y + " but sub[" + i + "].y()=" + suby);
347 if (!z.equals(subz))
348 throw new RuntimeException("z=" + z + " but sub[" + i + "].z()=" + subz);
349 }
350 }
351 }
352
353 // Records
354 public class Test17 {
355
356 record Rectangle(float length, float width) { }
357
358 record StringHolder(String string) {
359 StringHolder {
360 java.util.Objects.requireNonNull(string);
361 }
362 }
363
364 record ValueHolder(int value) {
365 ValueHolder(float x) {
366 if (Float.isNaN(x))
367 throw new IllegalArgumentException();
368 this((int)x);
369 }
370 }
371 }
372
373 // Exceptions thrown by initializer block
374 public static class Test18 extends AtomicReference<Object> {
375
376 {
377 if ((this.get().hashCode() % 3) == 0)
378 throw new MyException();
379 }
380
381 public Test18(Object obj) throws MyException {
382 super(obj);
383 }
384
385 public Test18(boolean fail) throws MyException {
386 Object obj;
387 for (obj = new Object(); true; obj = new Object()) {
388 if (((obj.hashCode() % 3) == 0) != fail)
389 continue;
390 break;
391 }
392 this(obj);
393 }
394
395 public static class MyException extends Exception {
396 }
397 }
398
399 // super()/this() within outer try block but inside inner class
400 public static class Test19 {
401 public Test19(int x) {
402 try {
403 new Test1(x) {
404 @Override
405 public int hashCode() {
406 return x ^ super.hashCode();
407 }
408 };
409 } catch (StackOverflowError e) {
410 // ignore
411 }
412 }
413 }
414
415 // we allow 'this' reference prior to super() for field assignments only
416 public static class Test20 {
417 private int x;
418 public Test20(short x) {
419 x = x;
420 super();
421 }
422 public Test20(int x) {
423 this.x = x;
424 super();
425 }
426 public Test20(char x) {
427 Test20.this.x = x;
428 super();
429 }
430 }
431
432 // allow creating and using local and anonymous classes before super()
433 // they will not have enclosing instances though
434 public static class Test21 {
435 public Test21(int x) {
436 Runnable r = new Runnable() {
437 public void run() {
438 this.hashCode();
439 }
440 };
441 r.run();
442 super();
443 r.run();
444 }
445 public Test21(float x) {
446 class Foo {
447 public void bar() {
448 this.hashCode();
449 }
450 };
451 new Foo().bar();
452 super();
453 new Foo().bar();
454 }
455 }
456
457 // Lambdas within constructors (JDK-8345438)
458 public static class Test22 {
459 public Test22() {
460 Runnable r = () -> System.out.println();
461 super();
462 r.run();
463 }
464 public Test22(int x) {
465 Runnable r = () -> System.out.println();
466 r.run();
467 super();
468 }
469 public Test22(char x) {
470 Runnable r = () -> {
471 class A {
472 A() {
473 return;
474 }
475 A(int x) {
476 Runnable r2 = () -> {
477 return;
478 };
479 this();
480 r2.run();
481 }
482 A(char x) {
483 this(0);
484 }
485 }
486 return;
487 };
488 r.run();
489 super();
490 }
491 }
492
493 // Receiver parameter syntax (JDK-8356551)
494 public static class Test23 {
495 public Test23() {
496 class Local {
497 Local(Test23 Test23.this) {
498 }
499 }
500 super();
501 new Local();
502 }
503 }
504
505 // Test for JDK-8349754
506 public static class Test24 {
507 private int i;
508 class Sub extends Test24 {
509 Sub() {
510 i = 3; // here "i" refers to "Test23.this.i", not "this.i" - so it's OK
511 super();
512 }
513 }
514 }
515
516 public static class Test25 {
517 public Test25(Object o) {}
518
519 class Sub extends Test25 {
520 public Sub() {
521 super(new Object() {
522 void foo() {
523 getClass();
524 }
525 });
526 }
527 }
528 }
529
530 public static class Test26 {
531 Test26(Test26 t) {}
532
533 Test26(String s) {
534 this(new Test26());
535 }
536
537 Test26() {}
538
539 public static void main(String[] args) {
540 new Test26("test");
541 }
542 }
543
544 public static void main(String[] args) {
545 new Test0();
546 new Test1();
547 new Test1(7);
548 new Test2<Byte>();
549 new Test2<>(args);
550 new Test3();
551 new SuperInitGood(3).new Test5(3);
552 new SuperInitGood(3).new Test6();
553 SuperInitGood.test7("foo");
554 SuperInitGood.test8();
555 new Test9(new SuperInitGood(5), "abc");
556 new Test10(7);
557 new Test11(9);
558 new Test12();
559 new Test13();
560 Test14 t14 = new Test14();
561 assert t14.x == 0 && t14.y == -1 && t14.z == 13;
562 t14 = new Test14(7);
563 assert t14.x == 7 && t14.y == -1 && t14.z == 13;
564 new Test15c(new Test15("foo"), "bar");
565 new Test16().run();
566 new Test17.StringHolder("foo");
567 try {
568 new Test17.StringHolder(null);
569 throw new Error();
570 } catch (NullPointerException e) {
571 // expected
572 }
573 try {
574 new Test18(true);
575 assert false : "expected exception";
576 } catch (Test18.MyException e) {
577 // expected
578 }
579 try {
580 new Test18(false);
581 } catch (Test18.MyException e) {
582 assert false : "unexpected exception: " + e;
583 }
584 new Test19(123);
585 new Test20(123);
586 new Test21((int)123);
587 new Test21((float)123);
588 new Test22('x');
589 new Test23();
590 new Test24();
591 new Test25(null);
592 new Test26("");
593 }
594 }