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