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 } --- EOF ---