diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java index 1f965d163ef..c6dd5e5abc4 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java @@ -321,7 +321,7 @@ public void resolve(BlockScope scope) { if (methodDeclaration == null || !methodDeclaration.isConstructor() || (((ConstructorDeclaration) methodDeclaration).constructorCall != this - && !scope.isInsideEarlyConstructionContext(null, true))) { + && !scope.isInsideEarlyConstructionContext(null, false))) { if (!(methodDeclaration instanceof CompactConstructorDeclaration)) {// already flagged for CCD scope.problemReporter().invalidExplicitConstructorCall(this); } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FieldReference.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FieldReference.java index 12f2caacc5c..fb77f45592b 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FieldReference.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FieldReference.java @@ -752,7 +752,7 @@ public TypeBinding resolveType(BlockScope scope) { } } else { if ((this.bits & ASTNode.IsStrictlyAssigned) == 0 - && this.actualReceiverType != null && scope.isInsideEarlyConstructionContext(this.actualReceiverType, true) + && this.actualReceiverType != null && scope.isInsideEarlyConstructionContext(this.actualReceiverType, false) && (this.receiver instanceof ThisReference thisReference && thisReference.isImplicitThis())) { // explicit thisReference error flagging taken care in ThisReference scope.problemReporter().errorExpressionInPreConstructorContext(this); } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java index d2c1a7a411d..ef1936932d7 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java @@ -1020,7 +1020,7 @@ public TypeBinding resolveType(BlockScope scope) { this.bits |= NeedReceiverGenericCast; } } - if (this.actualReceiverType != null && scope.isInsideEarlyConstructionContext(this.actualReceiverType, true) && + if (this.actualReceiverType != null && scope.isInsideEarlyConstructionContext(this.actualReceiverType, false) && (this.receiver instanceof ThisReference thisReference && thisReference.isImplicitThis())) { scope.problemReporter().errorExpressionInPreConstructorContext(this); } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java index 4dcea48e0f1..5b0f5d7fdf3 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java @@ -1102,7 +1102,7 @@ public TypeBinding resolveType(BlockScope scope) { } } else { boolean inStaticContext = scope.methodScope().isStatic; - if (scope.isInsideEarlyConstructionContext(fieldBinding.declaringClass, true)) + if (scope.isInsideEarlyConstructionContext(fieldBinding.declaringClass, false)) scope.problemReporter().errorExpressionInPreConstructorContext(this); if (this.indexOfFirstFieldBinding == 1) { if (scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java index 3042ec2f472..e1104f0e148 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java @@ -78,7 +78,7 @@ public TypeBinding resolveType(BlockScope scope) { ReferenceBinding enclosingReceiverType = scope.enclosingReceiverType(); // interface-qualified this selects a default method in a super interface, // but here we are only interested in supers of *enclosing instances*: - if (enclosingReceiverType != null && !enclosingReceiverType.isInterface() && scope.isInsideEarlyConstructionContext(enclosingReceiverType, true)) + if (enclosingReceiverType != null && !enclosingReceiverType.isInterface() && scope.isInsideEarlyConstructionContext(enclosingReceiverType, false)) scope.problemReporter().errorExpressionInPreConstructorContext(this); return this.resolvedType = (this.currentCompatibleType.isInterface() ? this.currentCompatibleType diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java index 826fa94f20c..702407b596a 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java @@ -129,7 +129,7 @@ else if (scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK16) { if (ms.isStatic) ms.problemReporter().errorThisSuperInStatic(this); } - if (scope.isInsideEarlyConstructionContext(this.resolvedType, true)) { + if (scope.isInsideEarlyConstructionContext(this.resolvedType, false)) { scope.problemReporter().errorExpressionInPreConstructorContext(this); } MethodScope methodScope = scope.namedMethodScope(); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java index e74307f66a3..5d6e623f816 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java @@ -248,7 +248,7 @@ public TypeBinding checkFieldAccess(BlockScope scope) { if (scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) { scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding); } - if (this.actualReceiverType != null && scope.isInsideEarlyConstructionContext(this.actualReceiverType, true)) { + if (this.actualReceiverType != null && scope.isInsideEarlyConstructionContext(this.actualReceiverType, false)) { scope.problemReporter().errorExpressionInPreConstructorContext(this); } // must check for the static status.... diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java index 9350f90e9c1..92c320e7133 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java @@ -5699,8 +5699,10 @@ public boolean isInsideEarlyConstructionContext(TypeBinding targetClass, boolean if (currentEnclosing.insideEarlyConstructionContext) return true; } - if (!considerEnclosings || currentTarget.isStatic()) + if (!considerEnclosings + || (currentTarget instanceof ReferenceBinding currentRefBind && !currentRefBind.hasEnclosingInstanceContext())) { break; + } currentTarget = currentTarget.enclosingType(); } currentEnclosing = currentEnclosing.parent.classScope(); diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SuperAfterStatementsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SuperAfterStatementsTest.java index 9a319eb48c9..89505827b3c 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SuperAfterStatementsTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SuperAfterStatementsTest.java @@ -396,6 +396,39 @@ void m() { """; runner.runNegativeTest(); } + public void test007d() { + // early construction context of far outer, while inners happily use 'this' + Runner runner = new Runner(false); + runner.testFiles = new String[] { + "X.java", + """ + class X { + X() { + class E { + E() { + this.i = new Inner(); + this.i.j++; + } + class Inner { + int j = 3;; + void m() { + E.this.i = this; + } + } + Inner i; + } + super(); + System.out.print(new E().i.j); + } + public static void main(String... args) { + new X(); + } + } + """ + }; + runner.expectedOutputString = "4"; + runner.runConformTest(); + } // an illegal access does not need to contain a this or super keyword: public void test008() { runNegativeTest(new String[] { @@ -428,6 +461,32 @@ class A { "You are using a preview language feature that may or may not be supported in a future release\n" + "----------\n"); } + public void test008_OK() { + // early construction context of outer + runConformTest(new String[] { + "A.java", + """ + class A { + A() { + class Local { + int i; + int getI() { return i; } + Local() { + i++; + System.out.print(getI()); + } + } + new Local(); + super(); + } + public static void main(String... args) { + new A(); + } + } + """ + }, + "1"); + } //an expression involving this does not refer to the current instance but, // rather, to the enclosing instance of an inner class: public void test009_NOK() { @@ -535,6 +594,31 @@ class Inner {} "You are using a preview language feature that may or may not be supported in a future release\n" + "----------\n"); } + public void test011_nested() { + runConformTest(new String[] { + "Outer.java", + """ + class Outer { + Outer() { + class Local { + class Inner { } + Local() { + Object o = new Inner(); // No Error - enclosing Local is not in early construction + System.out.print(o.getClass().getName()); + } + }; + Local l = new Local(); + Local.Inner i = l.new Inner(); + super(); + } + public static void main(String... args) { + new Outer(); + } + } + """ + }, + "Outer$1Local$Inner"); + } /* in a pre-construction context, class instance creation expressions that declare * anonymous classes cannot have the newly created object as the implicit enclosing * instance