### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/AssignmentTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AssignmentTest.java,v retrieving revision 1.38 diff -u -r1.38 AssignmentTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/AssignmentTest.java 15 Mar 2007 14:04:30 -0000 1.38 +++ src/org/eclipse/jdt/core/tests/compiler/regression/AssignmentTest.java 30 Mar 2007 15:01:09 -0000 @@ -150,6 +150,117 @@ }, "12"); } +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=151787 +public void test004() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " // correctly passes compilation\n" + + " static class Test1 {\n" + + " private final Object o;\n" + + " \n" + + " Test1() {\n" + + " o = new Object();\n" + + " }\n" + + " }\n" + + " \n" + + " // correctly passes compilation\n" + + " static class Test2 {\n" + + " private final Object o;\n" + + " \n" + + " Test2() {\n" + + " this.o = new Object();\n" + + " }\n" + + " }\n" + + " \n" + + " // correctly fails compilation\n" + + " static class Test3 {\n" + + " private final Object o;\n" + + " \n" + + " Test3() {\n" + + " System.out.println(o); // illegal; o is not definitely assigned\n" + + " o = new Object();\n" + + " }\n" + + " }\n" + + " \n" + + " // correctly passes compilation\n" + + " static class Test4 {\n" + + " private final Object o;\n" + + " \n" + + " Test4() {\n" + + " System.out.println(this.o); // legal\n" + + " o = new Object();\n" + + " }\n" + + " }\n" + + " \n" + + " // incorrectly passes compilation\n" + + " static class Test5 {\n" + + " private final Object o;\n" + + " \n" + + " Test5() {\n" + + " Test5 other = this;\n" + + " other.o = new Object(); // illegal! other.o is not assignable\n" + + " } // error: this.o is not definitely assigned\n" + + " }\n" + + " \n" + + " // flags wrong statement as error\n" + + " static class Test6 {\n" + + " private final Object o;\n" + + " static Test6 initing;\n" + + " \n" + + " Test6() {\n" + + " initing = this;\n" + + " System.out.println(\"greetings\");\n" + + " Test6 other = initing;\n" + + " other.o = new Object(); // illegal! other.o is not assignable\n" + + " o = new Object(); // legal\n" + + " }\n" + + " }\n" + + "}\n", // ================= + }, + "----------\n" + + "1. WARNING in X.java (at line 4)\n" + + " private final Object o;\n" + + " ^\n" + + "The field X.Test1.o is never read locally\n" + + "----------\n" + + "2. WARNING in X.java (at line 13)\n" + + " private final Object o;\n" + + " ^\n" + + "The field X.Test2.o is never read locally\n" + + "----------\n" + + "3. ERROR in X.java (at line 25)\n" + + " System.out.println(o); // illegal; o is not definitely assigned\n" + + " ^\n" + + "The blank final field o may not have been initialized\n" + + "----------\n" + + "4. WARNING in X.java (at line 42)\n" + + " private final Object o;\n" + + " ^\n" + + "The field X.Test5.o is never read locally\n" + + "----------\n" + + "5. ERROR in X.java (at line 44)\n" + + " Test5() {\n" + + " ^^^^^^^\n" + + "The blank final field o may not have been initialized\n" + + "----------\n" + + "6. ERROR in X.java (at line 46)\n" + + " other.o = new Object(); // illegal! other.o is not assignable\n" + + " ^\n" + + "The final field X.Test5.o cannot be assigned\n" + + "----------\n" + + "7. WARNING in X.java (at line 52)\n" + + " private final Object o;\n" + + " ^\n" + + "The field X.Test6.o is never read locally\n" + + "----------\n" + + "8. ERROR in X.java (at line 59)\n" + + " other.o = new Object(); // illegal! other.o is not assignable\n" + + " ^\n" + + "The final field X.Test6.o cannot be assigned\n" + + "----------\n"); +} // final multiple assignment public void test020() { this.runNegativeTest( #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java,v retrieving revision 1.115 diff -u -r1.115 QualifiedNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java 15 Mar 2007 15:49:43 -0000 1.115 +++ compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java 30 Mar 2007 15:01:10 -0000 @@ -11,11 +11,29 @@ package org.eclipse.jdt.internal.compiler.ast; import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; +import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.MethodScope; +import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.TagBits; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; public class QualifiedNameReference extends NameReference { @@ -30,158 +48,96 @@ public TypeBinding genericCast; public TypeBinding[] otherGenericCasts; - public QualifiedNameReference( - char[][] sources, - long[] positions, - int sourceStart, - int sourceEnd) { - super(); - this.tokens = sources; - this.sourcePositions = positions; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; - } - - public FlowInfo analyseAssignment( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo, - Assignment assignment, - boolean isCompound) { - - // determine the rank until which we now we do not need any actual value for the field access - int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length; - boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic(); - boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4; - FieldBinding lastFieldBinding = null; - switch (bits & RestrictiveFlagMASK) { - case Binding.FIELD : // reading a field - lastFieldBinding = (FieldBinding) binding; - if (needValue || complyTo14) { - manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, this.actualReceiverType, 0, flowInfo); - } - if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding - ReferenceBinding declaringClass = lastFieldBinding.declaringClass; - // check if accessing enum static field in initializer - if (declaringClass.isEnum()) { - MethodScope methodScope = currentScope.methodScope(); - SourceTypeBinding sourceType = methodScope.enclosingSourceType(); - if (lastFieldBinding.isStatic() - && (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body - && lastFieldBinding.constant() == Constant.NotAConstant - && !methodScope.isStatic - && methodScope.isInsideInitializerOrConstructor()) { - currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(lastFieldBinding, this); - } - } +public QualifiedNameReference( char[][] tokens, long[] positions, int sourceStart, int sourceEnd) { + this.tokens = tokens; + this.sourcePositions = positions; + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; +} + +public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { + // determine the rank until which we now we do not need any actual value for the field access + int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length; + boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic(); + boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4; + FieldBinding lastFieldBinding = null; + switch (this.bits & ASTNode.RestrictiveFlagMASK) { + case Binding.FIELD : // reading a field + lastFieldBinding = (FieldBinding) this.binding; + if (needValue || complyTo14) { + manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, this.actualReceiverType, 0, flowInfo); + } + if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding + ReferenceBinding declaringClass = lastFieldBinding.declaringClass; + // check if accessing enum static field in initializer + if (declaringClass.isEnum()) { + MethodScope methodScope = currentScope.methodScope(); + SourceTypeBinding sourceType = methodScope.enclosingSourceType(); + if (lastFieldBinding.isStatic() + && (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body + && lastFieldBinding.constant() == Constant.NotAConstant + && !methodScope.isStatic + && methodScope.isInsideInitializerOrConstructor()) { + currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(lastFieldBinding, this); + } } - // check if final blank field - if (lastFieldBinding.isBlankFinal() + } + // check if final blank field + if (lastFieldBinding.isBlankFinal() && this.otherBindings != null // the last field binding is only assigned && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { - if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) { - currentScope.problemReporter().uninitializedBlankFinalField( - lastFieldBinding, - this); - } - } - break; - case Binding.LOCAL : - // first binding is a local variable - LocalVariableBinding localBinding; - if (!flowInfo - .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { - currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); - } - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { - localBinding.useFlag = LocalVariableBinding.USED; - } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { - localBinding.useFlag = LocalVariableBinding.FAKE_USED; - } - checkNPE(currentScope, flowContext, flowInfo, true); - } - - if (needValue) { - manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); - // only for first binding - } - // all intermediate field accesses are read accesses - if (otherBindings != null) { - for (int i = 0; i < otherBindingsCount-1; i++) { - lastFieldBinding = otherBindings[i]; - needValue = !otherBindings[i+1].isStatic(); - if (needValue || complyTo14) { - manageSyntheticAccessIfNecessary( - currentScope, - lastFieldBinding, - i == 0 - ? ((VariableBinding)binding).type - : otherBindings[i-1].type, - i + 1, - flowInfo); - } + if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) { + currentScope.problemReporter().uninitializedBlankFinalField( + lastFieldBinding, + this); + } + } + break; + case Binding.LOCAL : + // first binding is a local variable + LocalVariableBinding localBinding; + if (!flowInfo + .isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) { + currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); + } + if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { + localBinding.useFlag = LocalVariableBinding.USED; + } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { + localBinding.useFlag = LocalVariableBinding.FAKE_USED; + } + checkNPE(currentScope, flowContext, flowInfo, true); + } + + if (needValue) { + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + // only for first binding + } + // all intermediate field accesses are read accesses + if (this.otherBindings != null) { + for (int i = 0; i < otherBindingsCount-1; i++) { + lastFieldBinding = this.otherBindings[i]; + needValue = !this.otherBindings[i+1].isStatic(); + if (needValue || complyTo14) { + manageSyntheticAccessIfNecessary( + currentScope, + lastFieldBinding, + i == 0 + ? ((VariableBinding)this.binding).type + : this.otherBindings[i-1].type, + i + 1, + flowInfo); } - lastFieldBinding = otherBindings[otherBindingsCount-1]; } + lastFieldBinding = this.otherBindings[otherBindingsCount-1]; + } - if (isCompound) { - if (otherBindingsCount == 0 + if (isCompound) { + if (otherBindingsCount == 0 && lastFieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding) && (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) { - currentScope.problemReporter().uninitializedBlankFinalField( - lastFieldBinding, - this); - } - TypeBinding lastReceiverType; - switch (otherBindingsCount) { - case 0 : - lastReceiverType = this.actualReceiverType; - break; - case 1 : - lastReceiverType = ((VariableBinding)this.binding).type; - break; - default: - lastReceiverType = this.otherBindings[otherBindingsCount-2].type; - break; - } - manageSyntheticAccessIfNecessary( - currentScope, - lastFieldBinding, - lastReceiverType, - otherBindingsCount, - flowInfo); - } - - if (assignment.expression != null) { - flowInfo = - assignment - .expression - .analyseCode(currentScope, flowContext, flowInfo) - .unconditionalInits(); - } - - // the last field access is a write access - if (lastFieldBinding.isFinal()) { - // in a context where it can be assigned? - if (lastFieldBinding.isBlankFinal() - && !isCompound - && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding) - && indexOfFirstFieldBinding == 1) { - if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) { - currentScope.problemReporter().duplicateInitializationOfBlankFinalField(lastFieldBinding, this); - } else { - flowContext.recordSettingFinal(lastFieldBinding, this, flowInfo); - } - flowInfo.markAsDefinitelyAssigned(lastFieldBinding); - } else { - currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this); - if (currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend it got assigned - flowInfo.markAsDefinitelyAssigned(lastFieldBinding); - } - } + currentScope.problemReporter().uninitializedBlankFinalField(lastFieldBinding, this); } - // equivalent to valuesRequired[maxOtherBindings] TypeBinding lastReceiverType; switch (otherBindingsCount) { case 0 : @@ -190,131 +146,172 @@ case 1 : lastReceiverType = ((VariableBinding)this.binding).type; break; - default : + default: lastReceiverType = this.otherBindings[otherBindingsCount-2].type; break; } - manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, lastReceiverType, -1 /*write-access*/, flowInfo); - - return flowInfo; + manageSyntheticAccessIfNecessary( + currentScope, + lastFieldBinding, + lastReceiverType, + otherBindingsCount, + flowInfo); } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - - return analyseCode(currentScope, flowContext, flowInfo, true); + if (assignment.expression != null) { + flowInfo = + assignment + .expression + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo, - boolean valueRequired) { - - // determine the rank until which we now we do not need any actual value for the field access - int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length; - - boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic(); - boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4; - switch (bits & RestrictiveFlagMASK) { - case Binding.FIELD : // reading a field - if (needValue || complyTo14) { - manageSyntheticAccessIfNecessary(currentScope, (FieldBinding) binding, this.actualReceiverType, 0, flowInfo); - } - if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding - FieldBinding fieldBinding = (FieldBinding) binding; - ReferenceBinding declaringClass = fieldBinding.declaringClass; - // check if accessing enum static field in initializer - if (declaringClass.isEnum()) { - MethodScope methodScope = currentScope.methodScope(); - SourceTypeBinding sourceType = methodScope.enclosingSourceType(); - if (fieldBinding.isStatic() - && (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body - && fieldBinding.constant() == Constant.NotAConstant - && !methodScope.isStatic - && methodScope.isInsideInitializerOrConstructor()) { - currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this); - } - } - // check if reading a final blank field - if (fieldBinding.isBlankFinal() - && currentScope.allowBlankFinalFieldAssignment(fieldBinding) - && !flowInfo.isDefinitelyAssigned(fieldBinding)) { - currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); - } - } - break; - case Binding.LOCAL : // reading a local variable - LocalVariableBinding localBinding; - if (!flowInfo - .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { - currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); - } - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { - localBinding.useFlag = LocalVariableBinding.USED; - } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { - localBinding.useFlag = LocalVariableBinding.FAKE_USED; - } - checkNPE(currentScope, flowContext, flowInfo, true); + // the last field access is a write access + if (lastFieldBinding.isFinal()) { + // in a context where it can be assigned? + if (otherBindingsCount == 0 + && this.indexOfFirstFieldBinding == 1 + && lastFieldBinding.isBlankFinal() + && !isCompound + && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { + if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) { + currentScope.problemReporter().duplicateInitializationOfBlankFinalField(lastFieldBinding, this); + } else { + flowContext.recordSettingFinal(lastFieldBinding, this, flowInfo); + } + flowInfo.markAsDefinitelyAssigned(lastFieldBinding); + } else { + currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this); + if (otherBindingsCount == 0 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend it got assigned + flowInfo.markAsDefinitelyAssigned(lastFieldBinding); + } } - if (needValue) { - manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); - // only for first binding (if value needed only) - } - if (otherBindings != null) { - for (int i = 0; i < otherBindingsCount; i++) { - needValue = i < otherBindingsCount-1 ? !otherBindings[i+1].isStatic() : valueRequired; - if (needValue || complyTo14) { - TypeBinding lastReceiverType = getGenericCast(i); - if (lastReceiverType == null) { - if (i == 0) { - lastReceiverType = ((VariableBinding)binding).type; - } else { - lastReceiverType = otherBindings[i-1].type; - } + } + // equivalent to valuesRequired[maxOtherBindings] + TypeBinding lastReceiverType; + switch (otherBindingsCount) { + case 0 : + lastReceiverType = this.actualReceiverType; + break; + case 1 : + lastReceiverType = ((VariableBinding)this.binding).type; + break; + default : + lastReceiverType = this.otherBindings[otherBindingsCount-2].type; + break; + } + manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, lastReceiverType, -1 /*write-access*/, flowInfo); + + return flowInfo; +} + +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + return analyseCode(currentScope, flowContext, flowInfo, true); +} + +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + // determine the rank until which we now we do not need any actual value for the field access + int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length; + + boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic(); + boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4; + switch (this.bits & ASTNode.RestrictiveFlagMASK) { + case Binding.FIELD : // reading a field + if (needValue || complyTo14) { + manageSyntheticAccessIfNecessary(currentScope, (FieldBinding) this.binding, this.actualReceiverType, 0, flowInfo); + } + if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding + FieldBinding fieldBinding = (FieldBinding) this.binding; + ReferenceBinding declaringClass = fieldBinding.declaringClass; + // check if accessing enum static field in initializer + if (declaringClass.isEnum()) { + MethodScope methodScope = currentScope.methodScope(); + SourceTypeBinding sourceType = methodScope.enclosingSourceType(); + if (fieldBinding.isStatic() + && (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body + && fieldBinding.constant() == Constant.NotAConstant + && !methodScope.isStatic + && methodScope.isInsideInitializerOrConstructor()) { + currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this); + } + } + // check if reading a final blank field + if (fieldBinding.isBlankFinal() + && currentScope.allowBlankFinalFieldAssignment(fieldBinding) + && !flowInfo.isDefinitelyAssigned(fieldBinding)) { + currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); + } + } + break; + case Binding.LOCAL : // reading a local variable + LocalVariableBinding localBinding; + if (!flowInfo + .isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) { + currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); + } + if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { + localBinding.useFlag = LocalVariableBinding.USED; + } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { + localBinding.useFlag = LocalVariableBinding.FAKE_USED; + } + checkNPE(currentScope, flowContext, flowInfo, true); + } + if (needValue) { + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + // only for first binding (if value needed only) + } + if (this.otherBindings != null) { + for (int i = 0; i < otherBindingsCount; i++) { + needValue = i < otherBindingsCount-1 ? !this.otherBindings[i+1].isStatic() : valueRequired; + if (needValue || complyTo14) { + TypeBinding lastReceiverType = getGenericCast(i); + if (lastReceiverType == null) { + if (i == 0) { + lastReceiverType = ((VariableBinding)this.binding).type; + } else { + lastReceiverType = this.otherBindings[i-1].type; } - manageSyntheticAccessIfNecessary( - currentScope, - otherBindings[i], - lastReceiverType, - i + 1, - flowInfo); } + manageSyntheticAccessIfNecessary( + currentScope, + this.otherBindings[i], + lastReceiverType, + i + 1, + flowInfo); } } - return flowInfo; - } - /** - * Check and/or redirect the field access to the delegate receiver if any - */ - public TypeBinding checkFieldAccess(BlockScope scope) { - FieldBinding fieldBinding = (FieldBinding) binding; - MethodScope methodScope = scope.methodScope(); - // check for forward references - if (this.indexOfFirstFieldBinding == 1 - && methodScope.enclosingSourceType() == fieldBinding.original().declaringClass - && methodScope.lastVisibleFieldID >= 0 - && fieldBinding.id >= methodScope.lastVisibleFieldID - && (!fieldBinding.isStatic() || methodScope.isStatic)) { - scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType()); - } - bits &= ~RestrictiveFlagMASK; // clear bits - bits |= Binding.FIELD; - return getOtherFieldBindings(scope); } + return flowInfo; +} + +/** + * Check and/or redirect the field access to the delegate receiver if any + */ +public TypeBinding checkFieldAccess(BlockScope scope) { + FieldBinding fieldBinding = (FieldBinding) this.binding; + MethodScope methodScope = scope.methodScope(); + // check for forward references + if (this.indexOfFirstFieldBinding == 1 + && methodScope.enclosingSourceType() == fieldBinding.original().declaringClass + && methodScope.lastVisibleFieldID >= 0 + && fieldBinding.id >= methodScope.lastVisibleFieldID + && (!fieldBinding.isStatic() || methodScope.isStatic)) { + scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType()); + } + this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits + this.bits |= Binding.FIELD; + return getOtherFieldBindings(scope); +} -public void checkNPE(BlockScope scope, FlowContext flowContext, - FlowInfo flowInfo, boolean checkString) { +public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, boolean checkString) { // cannot override localVariableBinding because this would project o.m onto o when // analysing assignments - if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) { + if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) { LocalVariableBinding local = (LocalVariableBinding) this.binding; if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0 && - (checkString || local.type.id != T_JavaLangString)) { - if ((this.bits & IsNonNull) == 0) { + (checkString || local.type.id != TypeIds.T_JavaLangString)) { + if ((this.bits & ASTNode.IsNonNull) == 0) { flowContext.recordUsingNullReference(scope, local, this, FlowContext.MAY_NULL, flowInfo); } @@ -326,569 +323,562 @@ } } } - /** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) - */ - public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) { - if (runtimeTimeType == null || compileTimeType == null) - return; - // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast) - FieldBinding field = null; - int length = this.otherBindings == null ? 0 : this.otherBindings.length; - if (length == 0) { - if ((this.bits & Binding.FIELD) != 0 && this.binding != null && this.binding.isValidBinding()) { - field = (FieldBinding) this.binding; - } - } else { - field = this.otherBindings[length-1]; - } - if (field != null) { - FieldBinding originalBinding = field.original(); - TypeBinding originalType = originalBinding.type; - // extra cast needed if method return type has type variable - if (originalBinding != field - && originalType != field.type - && runtimeTimeType.id != T_JavaLangObject - && (originalType.tagBits & TagBits.HasTypeVariable) != 0) { - TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) - ? compileTimeType // unboxing: checkcast before conversion - : runtimeTimeType; - setGenericCast(length, originalType.genericCast(targetType)); - } - } - super.computeConversion(scope, runtimeTimeType, compileTimeType); - } - - public void generateAssignment( - BlockScope currentScope, - CodeStream codeStream, - Assignment assignment, - boolean valueRequired) { - - int pc = codeStream.position; - FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); - codeStream.recordPositionsFrom(pc , this.sourceStart); - assignment.expression.generateCode(currentScope, codeStream, true); - fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired); - // equivalent to valuesRequired[maxOtherBindings] - if (valueRequired) { - codeStream.generateImplicitConversion(assignment.implicitConversion); + +/** + * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) + */ +public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) { + if (runtimeTimeType == null || compileTimeType == null) + return; + // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast) + FieldBinding field = null; + int length = this.otherBindings == null ? 0 : this.otherBindings.length; + if (length == 0) { + if ((this.bits & Binding.FIELD) != 0 && this.binding != null && this.binding.isValidBinding()) { + field = (FieldBinding) this.binding; } + } else { + field = this.otherBindings[length-1]; + } + if (field != null) { + FieldBinding originalBinding = field.original(); + TypeBinding originalType = originalBinding.type; + // extra cast needed if method return type has type variable + if (originalBinding != field + && originalType != field.type + && runtimeTimeType.id != TypeIds.T_JavaLangObject + && (originalType.tagBits & TagBits.HasTypeVariable) != 0) { + TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) + ? compileTimeType // unboxing: checkcast before conversion + : runtimeTimeType; + setGenericCast(length, originalType.genericCast(targetType)); + } } + super.computeConversion(scope, runtimeTimeType, compileTimeType); +} - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (constant != Constant.NotAConstant) { - if (valueRequired) { - codeStream.generateConstant(constant, implicitConversion); - } - } else { - FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); - if (lastFieldBinding != null) { - boolean isStatic = lastFieldBinding.isStatic(); - Constant fieldConstant = lastFieldBinding.constant(); - if (fieldConstant != Constant.NotAConstant) { - if (!isStatic){ - codeStream.invokeObjectGetClass(); - codeStream.pop(); - } - if (valueRequired) { // inline the last field constant - codeStream.generateConstant(fieldConstant, implicitConversion); - } - } else { - boolean isFirst = lastFieldBinding == this.binding - && (this.indexOfFirstFieldBinding == 1 || lastFieldBinding.declaringClass == currentScope.enclosingReceiverType()) - && this.otherBindings == null; // could be dup: next.next.next - TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length); - if (valueRequired - || (!isFirst && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) - || ((implicitConversion & TypeIds.UNBOXING) != 0) - || requiredGenericCast != null) { - int lastFieldPc = codeStream.position; - if (lastFieldBinding.declaringClass == null) { // array length - codeStream.arraylength(); - if (valueRequired) { - codeStream.generateImplicitConversion(implicitConversion); - } else { - // could occur if !valueRequired but compliance >= 1.4 - codeStream.pop(); - } +public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { + int pc = codeStream.position; + FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); + codeStream.recordPositionsFrom(pc , this.sourceStart); + assignment.expression.generateCode(currentScope, codeStream, true); + fieldStore(codeStream, lastFieldBinding, this.syntheticWriteAccessor, valueRequired); + // equivalent to valuesRequired[maxOtherBindings] + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); + } +} + +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (this.constant != Constant.NotAConstant) { + if (valueRequired) { + codeStream.generateConstant(this.constant, this.implicitConversion); + } + } else { + FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); + if (lastFieldBinding != null) { + boolean isStatic = lastFieldBinding.isStatic(); + Constant fieldConstant = lastFieldBinding.constant(); + if (fieldConstant != Constant.NotAConstant) { + if (!isStatic){ + codeStream.invokeObjectGetClass(); + codeStream.pop(); + } + if (valueRequired) { // inline the last field constant + codeStream.generateConstant(fieldConstant, this.implicitConversion); + } + } else { + boolean isFirst = lastFieldBinding == this.binding + && (this.indexOfFirstFieldBinding == 1 || lastFieldBinding.declaringClass == currentScope.enclosingReceiverType()) + && this.otherBindings == null; // could be dup: next.next.next + TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length); + if (valueRequired + || (!isFirst && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) + || ((this.implicitConversion & TypeIds.UNBOXING) != 0) + || requiredGenericCast != null) { + int lastFieldPc = codeStream.position; + if (lastFieldBinding.declaringClass == null) { // array length + codeStream.arraylength(); + if (valueRequired) { + codeStream.generateImplicitConversion(this.implicitConversion); } else { - SyntheticMethodBinding accessor = - syntheticReadAccessors == null - ? null - : syntheticReadAccessors[syntheticReadAccessors.length - 1]; - if (accessor == null) { - if (isStatic) { - codeStream.getstatic(lastFieldBinding); - } else { - codeStream.getfield(lastFieldBinding); - } - } else { - codeStream.invokestatic(accessor); - } - if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast); - if (valueRequired) { - codeStream.generateImplicitConversion(implicitConversion); + // could occur if !valueRequired but compliance >= 1.4 + codeStream.pop(); + } + } else { + SyntheticMethodBinding accessor = + this.syntheticReadAccessors == null + ? null + : this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1]; + if (accessor == null) { + if (isStatic) { + codeStream.getstatic(lastFieldBinding); } else { - boolean isUnboxing = (implicitConversion & TypeIds.UNBOXING) != 0; - // conversion only generated if unboxing - if (isUnboxing) codeStream.generateImplicitConversion(implicitConversion); - switch (isUnboxing ? postConversionType(currentScope).id : lastFieldBinding.type.id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - } + codeStream.getfield(lastFieldBinding); } + } else { + codeStream.invokestatic(accessor); } - - int fieldPosition = (int) (this.sourcePositions[this.sourcePositions.length - 1] >>> 32); - codeStream.recordPositionsFrom(lastFieldPc, fieldPosition); - } else { - if (!isStatic){ - codeStream.invokeObjectGetClass(); // perform null check - codeStream.pop(); + if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast); + if (valueRequired) { + codeStream.generateImplicitConversion(this.implicitConversion); + } else { + boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0; + // conversion only generated if unboxing + if (isUnboxing) codeStream.generateImplicitConversion(this.implicitConversion); + switch (isUnboxing ? postConversionType(currentScope).id : lastFieldBinding.type.id) { + case T_long : + case T_double : + codeStream.pop2(); + break; + default : + codeStream.pop(); + } } - } - } + } + + int fieldPosition = (int) (this.sourcePositions[this.sourcePositions.length - 1] >>> 32); + codeStream.recordPositionsFrom(lastFieldPc, fieldPosition); + } else { + if (!isStatic){ + codeStream.invokeObjectGetClass(); // perform null check + codeStream.pop(); + } + } } } - codeStream.recordPositionsFrom(pc, this.sourceStart); } - public void generateCompoundAssignment( - BlockScope currentScope, - CodeStream codeStream, - Expression expression, - int operator, - int assignmentImplicitConversion, - boolean valueRequired) { - - FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); - SyntheticMethodBinding accessor = - syntheticReadAccessors == null - ? null - : syntheticReadAccessors[syntheticReadAccessors.length - 1]; - if (lastFieldBinding.isStatic()) { - if (accessor == null) { - codeStream.getstatic(lastFieldBinding); - } else { - codeStream.invokestatic(accessor); - } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} + +public void generateCompoundAssignment( + BlockScope currentScope, + CodeStream codeStream, + Expression expression, + int operator, + int assignmentImplicitConversion, + boolean valueRequired) { + + FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); + SyntheticMethodBinding accessor = + this.syntheticReadAccessors == null + ? null + : this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1]; + if (lastFieldBinding.isStatic()) { + if (accessor == null) { + codeStream.getstatic(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + } else { + codeStream.dup(); + if (accessor == null) { + codeStream.getfield(lastFieldBinding); } else { - codeStream.dup(); - if (accessor == null) { - codeStream.getfield(lastFieldBinding); + codeStream.invokestatic(accessor); + } + } + // the last field access is a write access + // perform the actual compound operation + int operationTypeID; + switch(operationTypeID = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) { + case T_JavaLangString : + case T_JavaLangObject : + case T_undefined : + codeStream.generateStringConcatenationAppend(currentScope, null, expression); + break; + default : + TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length); + if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast); + // promote the array reference to the suitable operation type + codeStream.generateImplicitConversion(this.implicitConversion); + // generate the increment value (will by itself be promoted to the operation value) + if (expression == IntLiteral.One) { // prefix operation + codeStream.generateConstant(expression.constant, this.implicitConversion); } else { - codeStream.invokestatic(accessor); + expression.generateCode(currentScope, codeStream, true); } + // perform the operation + codeStream.sendOperator(operator, operationTypeID); + // cast the value back to the array reference type + codeStream.generateImplicitConversion(assignmentImplicitConversion); + } + // actual assignment + fieldStore(codeStream, lastFieldBinding, this.syntheticWriteAccessor, valueRequired); + // equivalent to valuesRequired[maxOtherBindings] +} + +public void generatePostIncrement( + BlockScope currentScope, + CodeStream codeStream, + CompoundAssignment postIncrement, + boolean valueRequired) { + + FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); + SyntheticMethodBinding accessor = + this.syntheticReadAccessors == null + ? null + : this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1]; + if (lastFieldBinding.isStatic()) { + if (accessor == null) { + codeStream.getstatic(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + } else { + codeStream.dup(); + if (accessor == null) { + codeStream.getfield(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); } - // the last field access is a write access - // perform the actual compound operation - int operationTypeID; - switch(operationTypeID = (implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { - case T_JavaLangString : - case T_JavaLangObject : - case T_undefined : - codeStream.generateStringConcatenationAppend(currentScope, null, expression); - break; - default : - TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length); - if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast); - // promote the array reference to the suitable operation type - codeStream.generateImplicitConversion(implicitConversion); - // generate the increment value (will by itself be promoted to the operation value) - if (expression == IntLiteral.One) { // prefix operation - codeStream.generateConstant(expression.constant, implicitConversion); - } else { - expression.generateCode(currentScope, codeStream, true); - } - // perform the operation - codeStream.sendOperator(operator, operationTypeID); - // cast the value back to the array reference type - codeStream.generateImplicitConversion(assignmentImplicitConversion); - } - // actual assignment - fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired); - // equivalent to valuesRequired[maxOtherBindings] } - - public void generatePostIncrement( - BlockScope currentScope, - CodeStream codeStream, - CompoundAssignment postIncrement, - boolean valueRequired) { - - FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); - SyntheticMethodBinding accessor = - syntheticReadAccessors == null - ? null - : syntheticReadAccessors[syntheticReadAccessors.length - 1]; + // duplicate the old field value + if (valueRequired) { if (lastFieldBinding.isStatic()) { - if (accessor == null) { - codeStream.getstatic(lastFieldBinding); + if ((lastFieldBinding.type == TypeBinding.LONG) + || (lastFieldBinding.type == TypeBinding.DOUBLE)) { + codeStream.dup2(); } else { - codeStream.invokestatic(accessor); + codeStream.dup(); } - } else { - codeStream.dup(); - if (accessor == null) { - codeStream.getfield(lastFieldBinding); + } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] + if ((lastFieldBinding.type == TypeBinding.LONG) + || (lastFieldBinding.type == TypeBinding.DOUBLE)) { + codeStream.dup2_x1(); } else { - codeStream.invokestatic(accessor); + codeStream.dup_x1(); } } - // duplicate the old field value - if (valueRequired) { - if (lastFieldBinding.isStatic()) { - if ((lastFieldBinding.type == TypeBinding.LONG) - || (lastFieldBinding.type == TypeBinding.DOUBLE)) { - codeStream.dup2(); + } + TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length); + if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast); + + codeStream.generateImplicitConversion(this.implicitConversion); + codeStream.generateConstant( + postIncrement.expression.constant, + this.implicitConversion); + codeStream.sendOperator(postIncrement.operator, this.implicitConversion & TypeIds.COMPILE_TYPE_MASK); + codeStream.generateImplicitConversion( + postIncrement.preAssignImplicitConversion); + fieldStore(codeStream, lastFieldBinding, this.syntheticWriteAccessor, false); +} + +/* + * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code + * for a read or write access. + */ +public FieldBinding generateReadSequence(BlockScope currentScope, CodeStream codeStream) { + // determine the rank until which we now we do not need any actual value for the field access + int otherBindingsCount = this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length; + boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic(); + FieldBinding lastFieldBinding = null; + TypeBinding lastGenericCast = null; + boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4; + + switch (this.bits & ASTNode.RestrictiveFlagMASK) { + case Binding.FIELD : + lastFieldBinding = (FieldBinding) this.codegenBinding; + lastGenericCast = this.genericCast; + // if first field is actually constant, we can inline it + if (lastFieldBinding.constant() != Constant.NotAConstant) { + break; + } + if ((needValue && !lastFieldBinding.isStatic()) || lastGenericCast != null) { + int pc = codeStream.position; + if ((this.bits & ASTNode.DepthMASK) != 0) { + ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); + Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); + codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); } else { - codeStream.dup(); + generateReceiver(codeStream); } - } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] - if ((lastFieldBinding.type == TypeBinding.LONG) - || (lastFieldBinding.type == TypeBinding.DOUBLE)) { - codeStream.dup2_x1(); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + break; + case Binding.LOCAL : // reading the first local variable + if (!needValue) break; // no value needed + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + // regular local variable read + Constant localConstant = localBinding.constant(); + if (localConstant != Constant.NotAConstant) { + codeStream.generateConstant(localConstant, 0); + // no implicit conversion + } else { + // outer local? + if ((this.bits & ASTNode.DepthMASK) != 0) { + // outer local can be reached either through a synthetic arg or a synthetic field + VariableBinding[] path = currentScope.getEmulationPath(localBinding); + codeStream.generateOuterAccess(path, this, localBinding, currentScope); } else { - codeStream.dup_x1(); + codeStream.load(localBinding); } } - } - TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length); - if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast); - - codeStream.generateImplicitConversion(implicitConversion); - codeStream.generateConstant( - postIncrement.expression.constant, - implicitConversion); - codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK); - codeStream.generateImplicitConversion( - postIncrement.preAssignImplicitConversion); - fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, false); - } - - /* - * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code - * for a read or write access. - */ - public FieldBinding generateReadSequence(BlockScope currentScope, CodeStream codeStream) { - - // determine the rank until which we now we do not need any actual value for the field access - int otherBindingsCount = this.otherCodegenBindings == null ? 0 : otherCodegenBindings.length; - boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic(); - FieldBinding lastFieldBinding = null; - TypeBinding lastGenericCast = null; - boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4; - - switch (bits & RestrictiveFlagMASK) { - case Binding.FIELD : - lastFieldBinding = (FieldBinding) this.codegenBinding; - lastGenericCast = this.genericCast; - // if first field is actually constant, we can inline it - if (lastFieldBinding.constant() != Constant.NotAConstant) { - break; - } - if ((needValue && !lastFieldBinding.isStatic()) || lastGenericCast != null) { - int pc = codeStream.position; - if ((bits & DepthMASK) != 0) { - ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); - Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); - codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); - } else { - generateReceiver(codeStream); + } + + // all intermediate field accesses are read accesses + // only the last field binding is a write access + int positionsLength = this.sourcePositions.length; + if (this.otherCodegenBindings != null) { + for (int i = 0; i < otherBindingsCount; i++) { + int pc = codeStream.position; + FieldBinding nextField = this.otherCodegenBindings[i]; + TypeBinding nextGenericCast = this.otherGenericCasts == null ? null : this.otherGenericCasts[i]; + if (lastFieldBinding != null) { + needValue = !nextField.isStatic(); + Constant fieldConstant = lastFieldBinding.constant(); + if (fieldConstant != Constant.NotAConstant) { + if (i > 0 && !lastFieldBinding.isStatic()) { + codeStream.invokeObjectGetClass(); // perform null check + codeStream.pop(); } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - break; - case Binding.LOCAL : // reading the first local variable - if (!needValue) break; // no value needed - LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; - // regular local variable read - Constant localConstant = localBinding.constant(); - if (localConstant != Constant.NotAConstant) { - codeStream.generateConstant(localConstant, 0); - // no implicit conversion - } else { - // outer local? - if ((bits & DepthMASK) != 0) { - // outer local can be reached either through a synthetic arg or a synthetic field - VariableBinding[] path = currentScope.getEmulationPath(localBinding); - codeStream.generateOuterAccess(path, this, localBinding, currentScope); - } else { - codeStream.load(localBinding); + if (needValue) { + codeStream.generateConstant(fieldConstant, 0); } - } - } - - // all intermediate field accesses are read accesses - // only the last field binding is a write access - int positionsLength = this.sourcePositions.length; - if (this.otherCodegenBindings != null) { - for (int i = 0; i < otherBindingsCount; i++) { - int pc = codeStream.position; - FieldBinding nextField = this.otherCodegenBindings[i]; - TypeBinding nextGenericCast = this.otherGenericCasts == null ? null : this.otherGenericCasts[i]; - if (lastFieldBinding != null) { - needValue = !nextField.isStatic(); - Constant fieldConstant = lastFieldBinding.constant(); - if (fieldConstant != Constant.NotAConstant) { - if (i > 0 && !lastFieldBinding.isStatic()) { - codeStream.invokeObjectGetClass(); // perform null check - codeStream.pop(); - } - if (needValue) { - codeStream.generateConstant(fieldConstant, 0); - } - } else { - if (needValue || (i > 0 && complyTo14) || lastGenericCast != null) { - MethodBinding accessor = syntheticReadAccessors == null ? null : syntheticReadAccessors[i]; - if (accessor == null) { - if (lastFieldBinding.isStatic()) { - codeStream.getstatic(lastFieldBinding); - } else { - codeStream.getfield(lastFieldBinding); - } + } else { + if (needValue || (i > 0 && complyTo14) || lastGenericCast != null) { + MethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[i]; + if (accessor == null) { + if (lastFieldBinding.isStatic()) { + codeStream.getstatic(lastFieldBinding); } else { - codeStream.invokestatic(accessor); + codeStream.getfield(lastFieldBinding); } - if (lastGenericCast != null) codeStream.checkcast(lastGenericCast); - if (!needValue) codeStream.pop(); } else { - if (this.codegenBinding == lastFieldBinding) { - if (lastFieldBinding.isStatic()){ - // if no valueRequired, still need possible side-effects of invocation, if field belongs to different class - if (((FieldBinding)binding).original().declaringClass != this.actualReceiverType.erasure()) { - MethodBinding accessor = syntheticReadAccessors == null ? null : syntheticReadAccessors[i]; - if (accessor == null) { - codeStream.getstatic(lastFieldBinding); - } else { - codeStream.invokestatic(accessor); - } - codeStream.pop(); - } - } - } else if (!lastFieldBinding.isStatic()){ - codeStream.invokeObjectGetClass(); // perform null check - codeStream.pop(); - } - } - if ((positionsLength - otherBindingsCount + i - 1) >= 0) { - int fieldPosition = (int) (this.sourcePositions[positionsLength - otherBindingsCount + i - 1] >>>32); - codeStream.recordPositionsFrom(pc, fieldPosition); + codeStream.invokestatic(accessor); } + if (lastGenericCast != null) codeStream.checkcast(lastGenericCast); + if (!needValue) codeStream.pop(); + } else { + if (this.codegenBinding == lastFieldBinding) { + if (lastFieldBinding.isStatic()){ + // if no valueRequired, still need possible side-effects of invocation, if field belongs to different class + if (((FieldBinding)this.binding).original().declaringClass != this.actualReceiverType.erasure()) { + MethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[i]; + if (accessor == null) { + codeStream.getstatic(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + codeStream.pop(); + } + } + } else if (!lastFieldBinding.isStatic()){ + codeStream.invokeObjectGetClass(); // perform null check + codeStream.pop(); + } + } + if ((positionsLength - otherBindingsCount + i - 1) >= 0) { + int fieldPosition = (int) (this.sourcePositions[positionsLength - otherBindingsCount + i - 1] >>>32); + codeStream.recordPositionsFrom(pc, fieldPosition); } } - lastFieldBinding = nextField; - lastGenericCast = nextGenericCast; } + lastFieldBinding = nextField; + lastGenericCast = nextGenericCast; } - return lastFieldBinding; } - public void generateReceiver(CodeStream codeStream) { - codeStream.aload_0(); + return lastFieldBinding; +} + +public void generateReceiver(CodeStream codeStream) { + codeStream.aload_0(); +} + +/** + * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() + */ +public TypeBinding[] genericTypeArguments() { + return null; +} + +// get the matching codegenBinding +protected FieldBinding getCodegenBinding(int index) { + if (index == 0){ + return (FieldBinding)this.codegenBinding; + } else { + return this.otherCodegenBindings[index-1]; } - /** - * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() - */ - public TypeBinding[] genericTypeArguments() { - return null; +} + +// get the matching generic cast +protected TypeBinding getGenericCast(int index) { + if (index == 0){ + return this.genericCast; + } else { + if (this.otherGenericCasts == null) return null; + return this.otherGenericCasts[index-1]; } +} - // get the matching codegenBinding - protected FieldBinding getCodegenBinding(int index) { - if (index == 0){ - return (FieldBinding)this.codegenBinding; +public TypeBinding getOtherFieldBindings(BlockScope scope) { + // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid) + int length = this.tokens.length; + FieldBinding field; + if ((this.bits & Binding.FIELD) != 0) { + field = (FieldBinding) this.binding; + if (!field.isStatic()) { + //must check for the static status.... + if (this.indexOfFirstFieldBinding > 1 //accessing to a field using a type as "receiver" is allowed only with static field + || scope.methodScope().isStatic) { // the field is the first token of the qualified reference.... + scope.problemReporter().staticFieldAccessToNonStaticVariable(this, field); + return null; + } } else { - return this.otherCodegenBindings[index-1]; - } + // indirect static reference ? + if (this.indexOfFirstFieldBinding > 1 + && field.declaringClass != this.actualReceiverType + && field.declaringClass.canBeSeenBy(scope)) { + scope.problemReporter().indirectAccessToStaticField(this, field); + } + } + // only last field is actually a write access if any + if (isFieldUseDeprecated(field, scope, (this.bits & ASTNode.IsStrictlyAssigned) != 0 && this.indexOfFirstFieldBinding == length)) + scope.problemReporter().deprecatedField(field, this); + } else { + field = null; + } + TypeBinding type = ((VariableBinding) this.binding).type; + int index = this.indexOfFirstFieldBinding; + if (index == length) { // restrictiveFlag == FIELD + this.constant = ((FieldBinding) this.binding).constant(); + // perform capture conversion if read access + return (type != null && (this.bits & ASTNode.IsStrictlyAssigned) == 0) + ? type.capture(scope, this.sourceEnd) + : type; } + // allocation of the fieldBindings array and its respective constants + int otherBindingsLength = length - index; + this.otherCodegenBindings = this.otherBindings = new FieldBinding[otherBindingsLength]; + this.otherDepths = new int[otherBindingsLength]; - // get the matching generic cast - protected TypeBinding getGenericCast(int index) { - if (index == 0){ - return this.genericCast; - } else { - if (this.otherGenericCasts == null) return null; - return this.otherGenericCasts[index-1]; - } - } + // fill the first constant (the one of the binding) + this.constant = ((VariableBinding) this.binding).constant(); + // save first depth, since will be updated by visibility checks of other bindings + int firstDepth = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT; + // iteration on each field + while (index < length) { + char[] token = this.tokens[index]; + if (type == null) + return null; // could not resolve type prior to this point + + this.bits &= ~ASTNode.DepthMASK; // flush previous depth if any + FieldBinding previousField = field; + field = scope.getField(type.capture(scope, (int)this.sourcePositions[index]), token, this); + int place = index - this.indexOfFirstFieldBinding; + this.otherBindings[place] = field; + this.otherDepths[place] = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT; + if (field.isValidBinding()) { + // set generic cast of for previous field (if any) + if (previousField != null) { + TypeBinding fieldReceiverType = type; + TypeBinding receiverErasure = type.erasure(); + if (receiverErasure instanceof ReferenceBinding) { + if (receiverErasure.findSuperTypeWithSameErasure(field.declaringClass) == null) { + fieldReceiverType = field.declaringClass; // handle indirect inheritance thru variable secondary bound + } + } + FieldBinding originalBinding = previousField.original(); + if ((originalBinding.type.tagBits & TagBits.HasTypeVariable) != 0 && fieldReceiverType.id != TypeIds.T_JavaLangObject) { + setGenericCast(index-1,originalBinding.type.genericCast(fieldReceiverType)); // type cannot be base-type even in boxing case + } + } + // only last field is actually a write access if any + if (isFieldUseDeprecated(field, scope, (this.bits & ASTNode.IsStrictlyAssigned) !=0 && index+1 == length)) { + scope.problemReporter().deprecatedField(field, this); + } + // constant propagation can only be performed as long as the previous one is a constant too. + if (this.constant != Constant.NotAConstant) { + this.constant = field.constant(); + } - public TypeBinding getOtherFieldBindings(BlockScope scope) { - // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid) - int length = tokens.length; - FieldBinding field; - if ((bits & Binding.FIELD) != 0) { - field = (FieldBinding) this.binding; - if (!field.isStatic()) { - //must check for the static status.... - if (indexOfFirstFieldBinding > 1 //accessing to a field using a type as "receiver" is allowed only with static field - || scope.methodScope().isStatic) { // the field is the first token of the qualified reference.... - scope.problemReporter().staticFieldAccessToNonStaticVariable(this, field); - return null; - } - } else { + if (field.isStatic()) { + // static field accessed through receiver? legal but unoptimal (optional warning) + scope.problemReporter().nonStaticAccessToStaticField(this, field); // indirect static reference ? - if (indexOfFirstFieldBinding > 1 - && field.declaringClass != actualReceiverType - && field.declaringClass.canBeSeenBy(scope)) { + if (field.declaringClass != type) { scope.problemReporter().indirectAccessToStaticField(this, field); } } - // only last field is actually a write access if any - if (isFieldUseDeprecated(field, scope, (this.bits & IsStrictlyAssigned) != 0 && indexOfFirstFieldBinding == length)) - scope.problemReporter().deprecatedField(field, this); + type = field.type; + index++; } else { - field = null; + this.constant = Constant.NotAConstant; //don't fill other constants slots... + scope.problemReporter().invalidField(this, field, index, type); + setDepth(firstDepth); + return null; } - TypeBinding type = ((VariableBinding) binding).type; - int index = indexOfFirstFieldBinding; - if (index == length) { // restrictiveFlag == FIELD - this.constant = ((FieldBinding) binding).constant(); - // perform capture conversion if read access - return (type != null && (this.bits & IsStrictlyAssigned) == 0) - ? type.capture(scope, this.sourceEnd) - : type; - } - // allocation of the fieldBindings array and its respective constants - int otherBindingsLength = length - index; - otherCodegenBindings = otherBindings = new FieldBinding[otherBindingsLength]; - otherDepths = new int[otherBindingsLength]; - - // fill the first constant (the one of the binding) - this.constant = ((VariableBinding) binding).constant(); - // save first depth, since will be updated by visibility checks of other bindings - int firstDepth = (bits & DepthMASK) >> DepthSHIFT; - // iteration on each field - while (index < length) { - char[] token = tokens[index]; - if (type == null) - return null; // could not resolve type prior to this point - - bits &= ~DepthMASK; // flush previous depth if any - FieldBinding previousField = field; - field = scope.getField(type.capture(scope, (int)this.sourcePositions[index]), token, this); - int place = index - indexOfFirstFieldBinding; - otherBindings[place] = field; - otherDepths[place] = (bits & DepthMASK) >> DepthSHIFT; - if (field.isValidBinding()) { - // set generic cast of for previous field (if any) - if (previousField != null) { - TypeBinding fieldReceiverType = type; - TypeBinding receiverErasure = type.erasure(); - if (receiverErasure instanceof ReferenceBinding) { - if (receiverErasure.findSuperTypeWithSameErasure(field.declaringClass) == null) { - fieldReceiverType = field.declaringClass; // handle indirect inheritance thru variable secondary bound - } - } - FieldBinding originalBinding = previousField.original(); - if ((originalBinding.type.tagBits & TagBits.HasTypeVariable) != 0 && fieldReceiverType.id != T_JavaLangObject) { - setGenericCast(index-1,originalBinding.type.genericCast(fieldReceiverType)); // type cannot be base-type even in boxing case - } - } - // only last field is actually a write access if any - if (isFieldUseDeprecated(field, scope, (this.bits & IsStrictlyAssigned) !=0 && index+1 == length)) { - scope.problemReporter().deprecatedField(field, this); - } - // constant propagation can only be performed as long as the previous one is a constant too. - if (this.constant != Constant.NotAConstant) { - this.constant = field.constant(); - } + } + setDepth(firstDepth); + type = (this.otherBindings[otherBindingsLength - 1]).type; + // perform capture conversion if read access + return (type != null && (this.bits & ASTNode.IsStrictlyAssigned) == 0) + ? type.capture(scope, this.sourceEnd) + : type; +} - if (field.isStatic()) { - // static field accessed through receiver? legal but unoptimal (optional warning) - scope.problemReporter().nonStaticAccessToStaticField(this, field); - // indirect static reference ? - if (field.declaringClass != type) { - scope.problemReporter().indirectAccessToStaticField(this, field); - } - } - type = field.type; - index++; - } else { - constant = Constant.NotAConstant; //don't fill other constants slots... - scope.problemReporter().invalidField(this, field, index, type); - setDepth(firstDepth); - return null; - } - } - setDepth(firstDepth); - type = (otherBindings[otherBindingsLength - 1]).type; - // perform capture conversion if read access - return (type != null && (this.bits & IsStrictlyAssigned) == 0) - ? type.capture(scope, this.sourceEnd) - : type; +public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { + //If inlinable field, forget the access emulation, the code gen will directly target it + if (((this.bits & ASTNode.DepthMASK) == 0) || (this.constant != Constant.NotAConstant)) { + return; + } + if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) { + currentScope.emulateOuterAccess((LocalVariableBinding) this.binding); } + } +} - public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { - //If inlinable field, forget the access emulation, the code gen will directly target it - if (((bits & DepthMASK) == 0) || (constant != Constant.NotAConstant)) { - return; - } - if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) { - currentScope.emulateOuterAccess((LocalVariableBinding) binding); - } - } +/** + * index is <0 to denote write access emulation + */ +public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FieldBinding fieldBinding, TypeBinding lastReceiverType, int index, FlowInfo flowInfo) { + if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return; + // index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings', index < 0 denotes a write access (to last binding) + if (fieldBinding.constant() != Constant.NotAConstant) + return; + + // if field from parameterized type got found, use the original field at codegen time + FieldBinding originalField = fieldBinding.original(); + if (originalField != fieldBinding) { + setCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index, originalField); } - /** - * index is <0 to denote write access emulation - */ - public void manageSyntheticAccessIfNecessary( - BlockScope currentScope, - FieldBinding fieldBinding, - TypeBinding lastReceiverType, - int index, - FlowInfo flowInfo) { - - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return; - // index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings', index < 0 denotes a write access (to last binding) - if (fieldBinding.constant() != Constant.NotAConstant) + + if (fieldBinding.isPrivate()) { // private access + FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index); + if (someCodegenBinding.declaringClass != currentScope.enclosingSourceType()) { + setSyntheticAccessor(fieldBinding, index, + ((SourceTypeBinding) someCodegenBinding.declaringClass).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/)); + currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/); return; - - // if field from parameterized type got found, use the original field at codegen time - FieldBinding originalField = fieldBinding.original(); - if (originalField != fieldBinding) { - setCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index, originalField); } + } else if (fieldBinding.isProtected()){ + int depth = (index == 0 || (index < 0 && this.otherDepths == null)) + ? (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT + : this.otherDepths[index < 0 ? this.otherDepths.length-1 : index-1]; - if (fieldBinding.isPrivate()) { // private access + // implicit protected access + if (depth > 0 && (fieldBinding.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage())) { FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index); - if (someCodegenBinding.declaringClass != currentScope.enclosingSourceType()) { - setSyntheticAccessor(fieldBinding, index, - ((SourceTypeBinding) someCodegenBinding.declaringClass).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/)); - currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/); - return; - } - } else if (fieldBinding.isProtected()){ - int depth = (index == 0 || (index < 0 && this.otherDepths == null)) - ? (bits & DepthMASK) >> DepthSHIFT - : otherDepths[index < 0 ? otherDepths.length-1 : index-1]; - - // implicit protected access - if (depth > 0 && (fieldBinding.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage())) { - FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index); - setSyntheticAccessor(fieldBinding, index, - ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/)); - currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/); - return; - } - } - // if the binding declaring class is not visible, need special action - // for runtime compatibility on 1.2 VMs : change the declaring class of the binding - // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type - // and not from Object or implicit static field access. - if (fieldBinding.declaringClass != lastReceiverType - && !lastReceiverType.isArrayType() - && fieldBinding.declaringClass != null // array.length - && fieldBinding.constant() == Constant.NotAConstant) { - CompilerOptions options = currentScope.compilerOptions(); - if ((options.targetJDK >= ClassFileConstants.JDK1_2 - && (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(index <= 1 && indexOfFirstFieldBinding == 1 && fieldBinding.isStatic())) - && fieldBinding.declaringClass.id != T_JavaLangObject) // no change for Object fields + setSyntheticAccessor(fieldBinding, index, + ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/)); + currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type + // and not from Object or implicit static field access. + if (fieldBinding.declaringClass != lastReceiverType + && !lastReceiverType.isArrayType() + && fieldBinding.declaringClass != null // array.length + && fieldBinding.constant() == Constant.NotAConstant) { + CompilerOptions options = currentScope.compilerOptions(); + if ((options.targetJDK >= ClassFileConstants.JDK1_2 + && (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(index <= 1 && this.indexOfFirstFieldBinding == 1 && fieldBinding.isStatic())) + && fieldBinding.declaringClass.id != TypeIds.T_JavaLangObject) // no change for Object fields || !fieldBinding.declaringClass.canBeSeenBy(currentScope)) { setCodegenBinding( @@ -896,210 +886,209 @@ currentScope.enclosingSourceType().getUpdatedFieldBinding( getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index), (ReferenceBinding)lastReceiverType.erasure())); - } - } - } + } + } +} public int nullStatus(FlowInfo flowInfo) { return FlowInfo.UNKNOWN; } - public Constant optimizedBooleanConstant() { - - switch (this.resolvedType.id) { - case T_boolean : - case T_JavaLangBoolean : - if (this.constant != Constant.NotAConstant) return this.constant; - switch (bits & RestrictiveFlagMASK) { - case Binding.FIELD : // reading a field - if (this.otherBindings == null) - return ((FieldBinding)this.binding).constant(); - // fall thru - case Binding.LOCAL : // reading a local variable - return this.otherBindings[this.otherBindings.length-1].constant(); - } +public Constant optimizedBooleanConstant() { + switch (this.resolvedType.id) { + case T_boolean : + case T_JavaLangBoolean : + if (this.constant != Constant.NotAConstant) return this.constant; + switch (this.bits & ASTNode.RestrictiveFlagMASK) { + case Binding.FIELD : // reading a field + if (this.otherBindings == null) + return ((FieldBinding)this.binding).constant(); + // fall thru + case Binding.LOCAL : // reading a local variable + return this.otherBindings[this.otherBindings.length-1].constant(); } - return Constant.NotAConstant; } + return Constant.NotAConstant; +} - /** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope) - */ - public TypeBinding postConversionType(Scope scope) { - TypeBinding convertedType = this.resolvedType; - TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length); - if (requiredGenericCast != null) - convertedType = requiredGenericCast; - int runtimeType = (this.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4; - switch (runtimeType) { - case T_boolean : - convertedType = TypeBinding.BOOLEAN; - break; - case T_byte : - convertedType = TypeBinding.BYTE; - break; - case T_short : - convertedType = TypeBinding.SHORT; - break; - case T_char : - convertedType = TypeBinding.CHAR; - break; - case T_int : - convertedType = TypeBinding.INT; - break; - case T_float : - convertedType = TypeBinding.FLOAT; - break; - case T_long : - convertedType = TypeBinding.LONG; - break; - case T_double : - convertedType = TypeBinding.DOUBLE; - break; - default : - } - if ((this.implicitConversion & BOXING) != 0) { - convertedType = scope.environment().computeBoxingType(convertedType); - } - return convertedType; +/** + * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope) + */ +public TypeBinding postConversionType(Scope scope) { + TypeBinding convertedType = this.resolvedType; + TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length); + if (requiredGenericCast != null) + convertedType = requiredGenericCast; + int runtimeType = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; + switch (runtimeType) { + case T_boolean : + convertedType = TypeBinding.BOOLEAN; + break; + case T_byte : + convertedType = TypeBinding.BYTE; + break; + case T_short : + convertedType = TypeBinding.SHORT; + break; + case T_char : + convertedType = TypeBinding.CHAR; + break; + case T_int : + convertedType = TypeBinding.INT; + break; + case T_float : + convertedType = TypeBinding.FLOAT; + break; + case T_long : + convertedType = TypeBinding.LONG; + break; + case T_double : + convertedType = TypeBinding.DOUBLE; + break; + default : + } + if ((this.implicitConversion & TypeIds.BOXING) != 0) { + convertedType = scope.environment().computeBoxingType(convertedType); } - - public StringBuffer printExpression(int indent, StringBuffer output) { - - for (int i = 0; i < tokens.length; i++) { - if (i > 0) output.append('.'); - output.append(tokens[i]); - } - return output; + return convertedType; +} + +public StringBuffer printExpression(int indent, StringBuffer output) { + for (int i = 0; i < this.tokens.length; i++) { + if (i > 0) output.append('.'); + output.append(this.tokens[i]); } - - /** - * Normal field binding did not work, try to bind to a field of the delegate receiver. - */ - public TypeBinding reportError(BlockScope scope) { - if (binding instanceof ProblemFieldBinding) { - scope.problemReporter().invalidField(this, (FieldBinding) binding); - } else if (binding instanceof ProblemReferenceBinding) { - scope.problemReporter().invalidType(this, (TypeBinding) binding); - } else { - scope.problemReporter().unresolvableReference(this, binding); - } - return null; + return output; +} + +/** + * Normal field binding did not work, try to bind to a field of the delegate receiver. + */ +public TypeBinding reportError(BlockScope scope) { + if (this.binding instanceof ProblemFieldBinding) { + scope.problemReporter().invalidField(this, (FieldBinding) this.binding); + } else if (this.binding instanceof ProblemReferenceBinding) { + scope.problemReporter().invalidType(this, (TypeBinding) this.binding); + } else { + scope.problemReporter().unresolvableReference(this, this.binding); } - public TypeBinding resolveType(BlockScope scope) { - // field and/or local are done before type lookups - // the only available value for the restrictiveFlag BEFORE - // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField - this.actualReceiverType = scope.enclosingReceiverType(); - constant = Constant.NotAConstant; - if ((this.codegenBinding = this.binding = scope.getBinding(tokens, bits & RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) { - switch (bits & RestrictiveFlagMASK) { - case Binding.VARIABLE : //============only variable=========== - case Binding.TYPE | Binding.VARIABLE : - if (binding instanceof LocalVariableBinding) { - if (!((LocalVariableBinding) binding).isFinal() && ((bits & DepthMASK) != 0)) - scope.problemReporter().cannotReferToNonFinalOuterLocal( - (LocalVariableBinding) binding, - this); - bits &= ~RestrictiveFlagMASK; // clear bits - bits |= Binding.LOCAL; - return this.resolvedType = getOtherFieldBindings(scope); + return null; +} + +public TypeBinding resolveType(BlockScope scope) { + // field and/or local are done before type lookups + // the only available value for the restrictiveFlag BEFORE + // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField + this.actualReceiverType = scope.enclosingReceiverType(); + this.constant = Constant.NotAConstant; + if ((this.codegenBinding = this.binding = scope.getBinding(this.tokens, this.bits & ASTNode.RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) { + switch (this.bits & ASTNode.RestrictiveFlagMASK) { + case Binding.VARIABLE : //============only variable=========== + case Binding.TYPE | Binding.VARIABLE : + if (this.binding instanceof LocalVariableBinding) { + if (!((LocalVariableBinding) this.binding).isFinal() && ((this.bits & ASTNode.DepthMASK) != 0)) + scope.problemReporter().cannotReferToNonFinalOuterLocal( + (LocalVariableBinding) this.binding, + this); + this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits + this.bits |= Binding.LOCAL; + return this.resolvedType = getOtherFieldBindings(scope); + } + if (this.binding instanceof FieldBinding) { + FieldBinding fieldBinding = (FieldBinding) this.binding; + MethodScope methodScope = scope.methodScope(); + // check for forward references + if (this.indexOfFirstFieldBinding == 1 + && methodScope.enclosingSourceType() == fieldBinding.original().declaringClass + && methodScope.lastVisibleFieldID >= 0 + && fieldBinding.id >= methodScope.lastVisibleFieldID + && (!fieldBinding.isStatic() || methodScope.isStatic)) { + scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType()); } - if (binding instanceof FieldBinding) { - FieldBinding fieldBinding = (FieldBinding) binding; - MethodScope methodScope = scope.methodScope(); - // check for forward references - if (this.indexOfFirstFieldBinding == 1 - && methodScope.enclosingSourceType() == fieldBinding.original().declaringClass - && methodScope.lastVisibleFieldID >= 0 - && fieldBinding.id >= methodScope.lastVisibleFieldID - && (!fieldBinding.isStatic() || methodScope.isStatic)) { - scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType()); - } - if (!fieldBinding.isStatic() - && this.indexOfFirstFieldBinding == 1 - && scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) { - scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding); - } - bits &= ~RestrictiveFlagMASK; // clear bits - bits |= Binding.FIELD; - + if (!fieldBinding.isStatic() + && this.indexOfFirstFieldBinding == 1 + && scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) { + scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding); + } + this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits + this.bits |= Binding.FIELD; + // // check for deprecated receiver type // // deprecation check for receiver type if not first token // if (indexOfFirstFieldBinding > 1) { // if (isTypeUseDeprecated(this.actualReceiverType, scope)) // scope.problemReporter().deprecatedType(this.actualReceiverType, this); // } - - return this.resolvedType = getOtherFieldBindings(scope); - } - // thus it was a type - bits &= ~RestrictiveFlagMASK; // clear bits - bits |= Binding.TYPE; - case Binding.TYPE : //=============only type ============== - TypeBinding type = (TypeBinding) binding; + + return this.resolvedType = getOtherFieldBindings(scope); + } + // thus it was a type + this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits + this.bits |= Binding.TYPE; + case Binding.TYPE : //=============only type ============== + TypeBinding type = (TypeBinding) this.binding; // if (isTypeUseDeprecated(type, scope)) // scope.problemReporter().deprecatedType(type, this); - type = scope.environment().convertToRawType(type); - return this.resolvedType = type; - } + type = scope.environment().convertToRawType(type); + return this.resolvedType = type; } - //========error cases=============== - return this.resolvedType = this.reportError(scope); } + //========error cases=============== + return this.resolvedType = this.reportError(scope); +} - // set the matching codegenBinding and generic cast - protected void setCodegenBinding(int index, FieldBinding someCodegenBinding) { - - if (index == 0){ - this.codegenBinding = someCodegenBinding; - } else { - int length = this.otherBindings.length; - if (this.otherCodegenBindings == this.otherBindings){ - System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[length], 0, length); - } - this.otherCodegenBindings[index-1] = someCodegenBinding; - } - } +// set the matching codegenBinding and generic cast +protected void setCodegenBinding(int index, FieldBinding someCodegenBinding) { + if (index == 0){ + this.codegenBinding = someCodegenBinding; + } else { + int length = this.otherBindings.length; + if (this.otherCodegenBindings == this.otherBindings){ + System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[length], 0, length); + } + this.otherCodegenBindings[index-1] = someCodegenBinding; + } +} - public void setFieldIndex(int index) { - this.indexOfFirstFieldBinding = index; - } - - // set the matching codegenBinding and generic cast - protected void setGenericCast(int index, TypeBinding someGenericCast) { +public void setFieldIndex(int index) { + this.indexOfFirstFieldBinding = index; +} - if (index == 0){ - this.genericCast = someGenericCast; - } else { - if (this.otherGenericCasts == null) { - this.otherGenericCasts = new TypeBinding[this.otherBindings.length]; - } - this.otherGenericCasts[index-1] = someGenericCast; - } - } - - // set the matching synthetic accessor - protected void setSyntheticAccessor(FieldBinding fieldBinding, int index, SyntheticMethodBinding syntheticAccessor) { - if (index < 0) { // write-access ? - syntheticWriteAccessor = syntheticAccessor; - } else { - if (syntheticReadAccessors == null) { - syntheticReadAccessors = new SyntheticMethodBinding[otherBindings == null ? 1 : otherBindings.length + 1]; - } - syntheticReadAccessors[index] = syntheticAccessor; +// set the matching codegenBinding and generic cast +protected void setGenericCast(int index, TypeBinding someGenericCast) { + if (index == 0){ + this.genericCast = someGenericCast; + } else { + if (this.otherGenericCasts == null) { + this.otherGenericCasts = new TypeBinding[this.otherBindings.length]; } - } + this.otherGenericCasts[index-1] = someGenericCast; + } +} - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - public void traverse(ASTVisitor visitor, ClassScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - public String unboundReferenceErrorName() { - return new String(tokens[0]); - } +// set the matching synthetic accessor +protected void setSyntheticAccessor(FieldBinding fieldBinding, int index, SyntheticMethodBinding syntheticAccessor) { + if (index < 0) { // write-access ? + this.syntheticWriteAccessor = syntheticAccessor; + } else { + if (this.syntheticReadAccessors == null) { + this.syntheticReadAccessors = new SyntheticMethodBinding[this.otherBindings == null ? 1 : this.otherBindings.length + 1]; + } + this.syntheticReadAccessors[index] = syntheticAccessor; + } +} + +public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} + +public void traverse(ASTVisitor visitor, ClassScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} + +public String unboundReferenceErrorName() { + return new String(this.tokens[0]); +} }