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