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