Skip to content

Commit bc76e39

Browse files
authored
Fix double field initializations with prologues (#4714)
Fixes #4696
1 parent 33dd1ac commit bc76e39

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ private void internalGenerateCode(ClassScope classScope, ClassFile classFile) {
561561
if (!this.compilationResult.hasErrors() && (codeStream.stackDepth != 0 || codeStream.operandStack.size() != 0)) {
562562
this.scope.problemReporter().operandStackSizeInappropriate(this);
563563
}
564-
if (lateConstructorCall == statement) {
564+
if (lateConstructorCall == statement && lateConstructorCall.accessMode != ExplicitConstructorCall.This) {
565565
// with JEP 492 (Flexible Constructor Bodies) involved field inits are generated only *after* the explicit constructor
566566
generateFieldInitializations(declaringType, codeStream, initializerScope);
567567
}

org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SuperAfterStatementsTest.java

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3512,5 +3512,82 @@ class TestClass<T extends Object> {
35123512
"""
35133513
});
35143514
}
3515+
// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4696
3516+
public void testIssue4696a() {
3517+
runConformTest(new String[] {
3518+
"EcjBugRepro.java",
3519+
"""
3520+
import java.util.HashMap;
3521+
import java.util.Map;
3522+
3523+
public class EcjBugRepro {
3524+
3525+
// 1. Field with implicit initializer
3526+
private final Map<String, String> data = new HashMap<>();
3527+
3528+
// Constructor 1: Uses Java 25 Pre-construction context + Chaining
3529+
public EcjBugRepro(int check) {
3530+
if (check < 0) throw new IllegalArgumentException(); // Pre-construction statement
3531+
this("delegated"); // Chaining
3532+
// ERROR: ECJ seems to re-run 'data = new HashMap()' here, wiping the map
3533+
}
3534+
3535+
// Constructor 2: Standard
3536+
public EcjBugRepro(String val) {
3537+
super();
3538+
// Field init runs here (Correct)
3539+
data.put("key", val);
3540+
System.out.println("Constructor 2: Added item. Size: " + data.size());
3541+
}
3542+
3543+
public static void main(String[] args) {
3544+
// Trigger via Constructor 1
3545+
EcjBugRepro instance = new EcjBugRepro(1);
3546+
3547+
if (instance.data.isEmpty()) {
3548+
System.err.println("FAILURE: Map is empty! Field was re-initialized.");
3549+
} else {
3550+
System.out.println("Success: Map size is " + instance.data.size());
3551+
}
3552+
}
3553+
}
3554+
"""
3555+
},
3556+
"Constructor 2: Added item. Size: 1\n" +
3557+
"Success: Map size is 1");
3558+
}
3559+
public void testIssue4696b() {
3560+
runConformTest(new String[] {
3561+
"Problem.java",
3562+
"""
3563+
public class Problem {
3564+
private int counter = 0;
3565+
3566+
Problem(int counter) {
3567+
this.counter = counter;
3568+
System.out.println("counter=" + this.counter);
3569+
}
3570+
3571+
Problem(boolean b) {
3572+
if (b) {
3573+
System.out.println("constructor called");
3574+
}
3575+
this(1);
3576+
}
3577+
3578+
private Problem() {
3579+
this(true);
3580+
}
3581+
3582+
public static void main(String[] args) {
3583+
System.out.println(new Problem().counter);
3584+
}
3585+
}
3586+
"""
3587+
},
3588+
"constructor called\n" +
3589+
"counter=1\n" +
3590+
"1");
3591+
}
35153592
}
35163593

0 commit comments

Comments
 (0)