package org.eclipse.jdt.internal.compiler.ast; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor; | |
import org.eclipse.jdt.internal.compiler.impl.*; | |
import org.eclipse.jdt.internal.compiler.codegen.*; | |
import org.eclipse.jdt.internal.compiler.flow.*; | |
import org.eclipse.jdt.internal.compiler.lookup.*; | |
public class SingleNameReference extends NameReference implements OperatorIds { | |
public char[] token; | |
public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor | |
public static final int READ = 0; | |
public static final int WRITE = 1; | |
public SingleNameReference(char[] source, long pos) { | |
super(); | |
token = source; | |
sourceStart = (int) (pos >>> 32); | |
sourceEnd = (int) pos; | |
} | |
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { | |
// compound assignment extra work | |
if (isCompound) { // check the variable part is initialized if blank final | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // reading a field | |
FieldBinding fieldBinding; | |
if ((fieldBinding = (FieldBinding) binding).isFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { | |
if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { | |
currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); | |
// we could improve error msg here telling "cannot use compound assignment on final blank field" | |
} | |
} | |
manageSyntheticReadAccessIfNecessary(currentScope); | |
break; | |
case LOCAL : // reading a local variable | |
// check if assigning a final blank field | |
LocalVariableBinding localBinding; | |
if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { | |
currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); | |
// we could improve error msg here telling "cannot use compound assignment on final local variable" | |
} | |
if (!flowInfo.isFakeReachable()) localBinding.used = true; | |
} | |
} | |
if (assignment.expression != null) { | |
flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); | |
} | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // assigning to a field | |
manageSyntheticWriteAccessIfNecessary(currentScope); | |
// check if assigning a final field | |
FieldBinding fieldBinding; | |
if ((fieldBinding = (FieldBinding) binding).isFinal()) { | |
// inside a context where allowed | |
if (currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { | |
if (flowInfo.isPotentiallyAssigned(fieldBinding)) { | |
currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this); | |
} | |
flowInfo.markAsDefinitelyAssigned(fieldBinding); | |
flowContext.recordSettingFinal(fieldBinding, this); | |
} else { | |
currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this); | |
} | |
} | |
break; | |
case LOCAL : // assigning to a local variable | |
LocalVariableBinding localBinding = (LocalVariableBinding) binding; | |
if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes | |
bits |= FirstAssignmentToLocalMASK; | |
} else { | |
bits &= ~FirstAssignmentToLocalMASK; | |
} | |
if (localBinding.isFinal()) { | |
if ((bits & DepthMASK) == 0) { | |
if (flowInfo.isPotentiallyAssigned(localBinding)) { | |
currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this); | |
} | |
flowContext.recordSettingFinal(localBinding, this); | |
} else { | |
currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this); | |
} | |
} | |
flowInfo.markAsDefinitelyAssigned(localBinding); | |
} | |
manageEnclosingInstanceAccessIfNecessary(currentScope); | |
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) { | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // reading a field | |
if (valueRequired) { | |
manageSyntheticReadAccessIfNecessary(currentScope); | |
} | |
// check if reading a final blank field | |
FieldBinding fieldBinding; | |
if ((fieldBinding = (FieldBinding) binding).isFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { | |
if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { | |
currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); | |
} | |
} | |
break; | |
case LOCAL : // reading a local variable | |
LocalVariableBinding localBinding; | |
if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { | |
currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); | |
} | |
if (!flowInfo.isFakeReachable()) localBinding.used = true; | |
} | |
if (valueRequired) { | |
manageEnclosingInstanceAccessIfNecessary(currentScope); | |
} | |
return flowInfo; | |
} | |
public TypeBinding checkFieldAccess(BlockScope scope) { | |
FieldBinding fieldBinding = (FieldBinding) binding; | |
bits &= ~RestrictiveFlagMASK; // clear bits | |
bits |= FIELD; | |
if (!((FieldBinding) binding).isStatic()) { | |
// must check for the static status.... | |
if (scope.methodScope().isStatic) { | |
scope.problemReporter().staticFieldAccessToNonStaticVariable( | |
this, | |
fieldBinding); | |
constant = NotAConstant; | |
return null; | |
} | |
} | |
constant = FieldReference.getConstantFor(fieldBinding, true, this, 0); | |
if (isFieldUseDeprecated(fieldBinding, scope)) | |
scope.problemReporter().deprecatedField(fieldBinding, this); | |
// 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 | |
if (fieldBinding.declaringClass != null | |
&& fieldBinding.constant == NotAConstant | |
&& !fieldBinding.declaringClass.canBeSeenBy(scope)) | |
binding = new FieldBinding(fieldBinding, scope.enclosingSourceType()); | |
//=============================================== | |
//cycle are forbidden ONLY within the same class...why ?????? (poor javac....) | |
//Cycle can be done using cross class ref but not direct into a same class reference ???? | |
//class A { static int k = B.k+1;} | |
//class B { static int k = A.k+2;} | |
//The k-cycle in this example is valid. | |
//class C { static int k = k + 1 ;} | |
//here it is forbidden ! ???? | |
//but the next one is valid !!! | |
//class C { static int k = C.k + 1;} | |
//notice that the next one is also valid ?!?! | |
//class A { static int k = foo().k+1 ; static A foo(){return new A();}} | |
//for all these reasons, the next piece of code is only here and not | |
//commun for all FieldRef and QualifiedNameRef....(i.e. in the getField(..) API..... | |
//instance field may refer to forward static field, like in | |
//int i = staticI; | |
//static int staticI = 2 ; | |
MethodScope ms = scope.methodScope(); | |
if (ms.enclosingSourceType() == fieldBinding.declaringClass | |
&& ms.fieldDeclarationIndex != ms.NotInFieldDecl | |
&& fieldBinding.id >= ms.fieldDeclarationIndex) { | |
//if the field is static and ms is not .... then it is valid | |
if (!fieldBinding.isStatic() || ms.isStatic) | |
scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType()); | |
} | |
//==================================================== | |
return fieldBinding.type; | |
} | |
public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { | |
// optimizing assignment like: i = i + 1 or i = 1 + i | |
if (assignment.expression.isCompactableOperation()) { | |
BinaryExpression operation = (BinaryExpression) assignment.expression; | |
SingleNameReference variableReference; | |
if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == binding)) { | |
// i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion | |
variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.right, (operation.bits & OperatorMASK) >> OperatorSHIFT, operation.left.implicitConversion /*should be equivalent to no conversion*/, valueRequired); | |
return; | |
} | |
int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT; | |
if ((operation.right instanceof SingleNameReference) | |
&& ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations | |
&& ((variableReference = (SingleNameReference) operation.right).binding == binding) | |
&& (operation.left.constant != NotAConstant) // exclude non constant expressions, since could have side-effect | |
&& ((operation.implicitConversion >> 4) != T_String)) { // exclude string concatenation which would occur backwards | |
// i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion | |
variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.right.implicitConversion /*should be equivalent to no conversion*/, valueRequired); | |
return; | |
} | |
} | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // assigning to a field | |
FieldBinding fieldBinding; | |
if (!(fieldBinding = (FieldBinding) binding).isStatic()) { // need a receiver? | |
if ((bits & DepthMASK) != 0) { | |
Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); | |
if (emulationPath == null) { | |
// internal error, per construction we should have found it | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
codeStream.generateOuterAccess(emulationPath, this, currentScope); | |
} | |
} else { | |
this.generateReceiver(codeStream); | |
} | |
} | |
assignment.expression.generateCode(currentScope, codeStream, true); | |
fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], valueRequired); | |
if (valueRequired) { | |
codeStream.generateImplicitConversion(assignment.implicitConversion); | |
} | |
return; | |
case LOCAL : // assigning to a local variable | |
LocalVariableBinding localBinding = (LocalVariableBinding) binding; | |
if (localBinding.resolvedPosition != -1) { | |
assignment.expression.generateCode(currentScope, codeStream, true); | |
} else { | |
if (assignment.expression.constant != NotAConstant) { | |
// assigning an unused local to a constant value = no actual assignment is necessary | |
if (valueRequired) { | |
codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion); | |
} | |
} else { | |
assignment.expression.generateCode(currentScope, codeStream, true); | |
/* Even though the value may not be required, we force it to be produced, and discard it later | |
on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */ | |
if (valueRequired) { | |
codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion | |
} else { | |
if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { | |
codeStream.pop2(); | |
} else { | |
codeStream.pop(); | |
} | |
} | |
} | |
return; | |
} | |
// normal local assignment (since cannot store in outer local which are final locations) | |
codeStream.store(localBinding, valueRequired); | |
if ((bits & FirstAssignmentToLocalMASK) != 0) { // for local variable debug attributes | |
localBinding.recordInitializationStartPC(codeStream.position); | |
} | |
// implicit conversion | |
if (valueRequired) { | |
codeStream.generateImplicitConversion(assignment.implicitConversion); | |
} | |
} | |
} | |
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { | |
int pc = codeStream.position; | |
if (constant != NotAConstant) { | |
if (valueRequired) { | |
codeStream.generateConstant(constant, implicitConversion); | |
} | |
} else { | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // reading a field | |
FieldBinding fieldBinding; | |
if (valueRequired) { | |
if ((fieldBinding = (FieldBinding) binding).constant == NotAConstant) { // directly use inlined value for constant fields | |
boolean isStatic; | |
if (!(isStatic = fieldBinding.isStatic())) { | |
if ((bits & DepthMASK) != 0) { | |
Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); | |
if (emulationPath == null) { | |
// internal error, per construction we should have found it | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
codeStream.generateOuterAccess(emulationPath, this, currentScope); | |
} | |
} else { | |
generateReceiver(codeStream); | |
} | |
} | |
// managing private access | |
if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { | |
if (isStatic) { | |
codeStream.getstatic(fieldBinding); | |
} else { | |
codeStream.getfield(fieldBinding); | |
} | |
} else { | |
codeStream.invokestatic(syntheticAccessors[READ]); | |
} | |
codeStream.generateImplicitConversion(implicitConversion); | |
} else { // directly use the inlined value | |
codeStream.generateConstant(fieldBinding.constant, implicitConversion); | |
} | |
} | |
break; | |
case LOCAL : // reading a local | |
LocalVariableBinding localBinding = (LocalVariableBinding) binding; | |
if (valueRequired) { | |
// 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); | |
if (path == null) { | |
// emulation was not possible (should not happen per construction) | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
codeStream.generateOuterAccess(path, this, currentScope); | |
} | |
} else { | |
// regular local variable read | |
codeStream.load(localBinding); | |
} | |
codeStream.generateImplicitConversion(implicitConversion); | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
} | |
/* | |
* Regular API for compound assignment, relies on the fact that there is only one reference to the | |
* variable, which carries both synthetic read/write accessors. | |
* The APIs with an extra argument is used whenever there are two references to the same variable which | |
* are optimized in one access: e.g "a = a + 1" optimized into "a++". | |
*/ | |
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { | |
this.generateCompoundAssignment( | |
currentScope, | |
codeStream, | |
syntheticAccessors == null ? null : syntheticAccessors[WRITE], | |
expression, | |
operator, | |
assignmentImplicitConversion, | |
valueRequired); | |
} | |
/* | |
* The APIs with an extra argument is used whenever there are two references to the same variable which | |
* are optimized in one access: e.g "a = a + 1" optimized into "a++". | |
*/ | |
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // assigning to a field | |
FieldBinding fieldBinding; | |
if ((fieldBinding = (FieldBinding) binding).isStatic()) { | |
if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { | |
codeStream.getstatic(fieldBinding); | |
} else { | |
codeStream.invokestatic(syntheticAccessors[READ]); | |
} | |
} else { | |
if ((bits & DepthMASK) != 0) { | |
Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); | |
if (emulationPath == null) { | |
// internal error, per construction we should have found it | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
codeStream.generateOuterAccess(emulationPath, this, currentScope); | |
} | |
} else { | |
codeStream.aload_0(); | |
} | |
codeStream.dup(); | |
if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { | |
codeStream.getfield(fieldBinding); | |
} else { | |
codeStream.invokestatic(syntheticAccessors[READ]); | |
} | |
} | |
break; | |
case LOCAL : // assigning to a local variable (cannot assign to outer local) | |
LocalVariableBinding localBinding = (LocalVariableBinding) binding; | |
Constant assignConstant; | |
int increment; | |
// using incr bytecode if possible | |
switch (localBinding.type.id) { | |
case T_String : | |
codeStream.generateStringAppend(currentScope, this, expression); | |
if (valueRequired) { | |
codeStream.dup(); | |
} | |
codeStream.store(localBinding, false); | |
return; | |
case T_int : | |
if (((assignConstant = expression.constant) != NotAConstant) && ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value | |
switch (operator) { | |
case PLUS : | |
codeStream.iinc(localBinding.resolvedPosition, increment); | |
if (valueRequired) { | |
codeStream.load(localBinding); | |
} | |
return; | |
case MINUS : | |
codeStream.iinc(localBinding.resolvedPosition, -increment); | |
if (valueRequired) { | |
codeStream.load(localBinding); | |
} | |
return; | |
} | |
} | |
default : | |
codeStream.load(localBinding); | |
} | |
} | |
// perform the actual compound operation | |
int operationTypeID; | |
if ((operationTypeID = implicitConversion >> 4) == T_String || operationTypeID == T_Object) { | |
// we enter here if the single name reference is a field of type java.lang.String or if the type of the | |
// operation is java.lang.Object | |
// For example: o = o + ""; // where the compiled type of o is java.lang.Object. | |
codeStream.generateStringAppend(currentScope, null, expression); | |
} else { | |
// 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); | |
} | |
// store the result back into the variable | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // assigning to a field | |
fieldStore(codeStream, (FieldBinding) binding, writeAccessor, valueRequired); | |
return; | |
case LOCAL : // assigning to a local variable | |
LocalVariableBinding localBinding = (LocalVariableBinding) binding; | |
if (valueRequired) { | |
if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { | |
codeStream.dup2(); | |
} else { | |
codeStream.dup(); | |
} | |
} | |
codeStream.store(localBinding, false); | |
} | |
} | |
public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // assigning to a field | |
FieldBinding fieldBinding; | |
if ((fieldBinding = (FieldBinding) binding).isStatic()) { | |
if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { | |
codeStream.getstatic(fieldBinding); | |
} else { | |
codeStream.invokestatic(syntheticAccessors[READ]); | |
} | |
} else { | |
if ((bits & DepthMASK) != 0) { | |
Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); | |
if (emulationPath == null) { | |
// internal error, per construction we should have found it | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
codeStream.generateOuterAccess(emulationPath, this, currentScope); | |
} | |
} else { | |
codeStream.aload_0(); | |
} | |
codeStream.dup(); | |
if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { | |
codeStream.getfield(fieldBinding); | |
} else { | |
codeStream.invokestatic(syntheticAccessors[READ]); | |
} | |
} | |
if (valueRequired) { | |
if (fieldBinding.isStatic()) { | |
if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { | |
codeStream.dup2(); | |
} else { | |
codeStream.dup(); | |
} | |
} else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] | |
if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { | |
codeStream.dup2_x1(); | |
} else { | |
codeStream.dup_x1(); | |
} | |
} | |
} | |
codeStream.generateConstant(postIncrement.expression.constant, implicitConversion); | |
codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id); | |
codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion); | |
fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false); | |
return; | |
case LOCAL : // assigning to a local variable | |
LocalVariableBinding localBinding = (LocalVariableBinding) binding; | |
// using incr bytecode if possible | |
if (localBinding.type == IntBinding) { | |
if (valueRequired) { | |
codeStream.load(localBinding); | |
} | |
if (postIncrement.operator == PLUS) { | |
codeStream.iinc(localBinding.resolvedPosition, 1); | |
} else { | |
codeStream.iinc(localBinding.resolvedPosition, -1); | |
} | |
} else { | |
codeStream.load(localBinding); | |
if (valueRequired){ | |
if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { | |
codeStream.dup2(); | |
} else { | |
codeStream.dup(); | |
} | |
} | |
codeStream.generateConstant(postIncrement.expression.constant, implicitConversion); | |
codeStream.sendOperator(postIncrement.operator, localBinding.type.id); | |
codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion); | |
codeStream.store(localBinding, false); | |
} | |
} | |
} | |
public void generateReceiver(CodeStream codeStream) { | |
codeStream.aload_0(); | |
} | |
public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) { | |
//If inlinable field, forget the access emulation, the code gen will directly target it | |
if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) return; | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : | |
FieldBinding fieldBinding; | |
if ((fieldBinding = (FieldBinding)binding).isStatic() || (fieldBinding.constant != NotAConstant)) return; | |
ReferenceBinding compatibleType = currentScope.enclosingSourceType(); | |
// the declaringClass of the target binding must be compatible with the enclosing | |
// type at <depth> levels outside | |
for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) { | |
compatibleType = compatibleType.enclosingType(); | |
} | |
currentScope.emulateOuterAccess(compatibleType, false); // request cascade of accesses | |
break; | |
case LOCAL : | |
currentScope.emulateOuterAccess((LocalVariableBinding) binding); | |
} | |
} | |
public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope) { | |
//If inlinable field, forget the access emulation, the code gen will directly target it | |
if (constant != NotAConstant) | |
return; | |
if ((bits & FIELD) != 0) { | |
FieldBinding fieldBinding = (FieldBinding) binding; | |
if (((bits & DepthMASK) != 0) | |
&& (fieldBinding.isPrivate() // private access | |
|| (fieldBinding.isProtected() // implicit protected access | |
&& fieldBinding.declaringClass.getPackage() | |
!= currentScope.enclosingSourceType().getPackage()))) { | |
if (syntheticAccessors == null) | |
syntheticAccessors = new MethodBinding[2]; | |
syntheticAccessors[READ] = | |
((SourceTypeBinding)currentScope.enclosingSourceType(). | |
enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)). | |
addSyntheticMethod(fieldBinding, true); | |
currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this); | |
} | |
} | |
} | |
public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope) { | |
if ((bits & FIELD) != 0) { | |
FieldBinding fieldBinding = (FieldBinding) binding; | |
if (((bits & DepthMASK) != 0) | |
&& (fieldBinding.isPrivate() // private access | |
|| (fieldBinding.isProtected() // implicit protected access | |
&& fieldBinding.declaringClass.getPackage() | |
!= currentScope.enclosingSourceType().getPackage()))) { | |
if (syntheticAccessors == null) | |
syntheticAccessors = new MethodBinding[2]; | |
syntheticAccessors[WRITE] = | |
((SourceTypeBinding)currentScope.enclosingSourceType(). | |
enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)). | |
addSyntheticMethod(fieldBinding, false); | |
currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this); | |
} | |
} | |
} | |
public TypeBinding reportError(BlockScope scope) { | |
//=====error cases======= | |
constant = Constant.NotAConstant; | |
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; | |
} | |
public TypeBinding resolveType(BlockScope scope) { | |
// for code gen, harm the restrictiveFlag | |
this.receiverType = scope.enclosingSourceType(); | |
if ((binding = scope.getBinding(token, bits & RestrictiveFlagMASK, this)).isValidBinding()) { | |
switch (bits & RestrictiveFlagMASK) { | |
case VARIABLE : // =========only variable============ | |
case VARIABLE | TYPE : //====both variable and type============ | |
if (binding instanceof VariableBinding) { | |
VariableBinding vb = (VariableBinding) binding; | |
if (binding instanceof LocalVariableBinding) { | |
bits &= ~RestrictiveFlagMASK; // clear bits | |
bits |= LOCAL; | |
constant = vb.constant; | |
if ((!vb.isFinal()) && ((bits & DepthMASK) != 0)) | |
scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)vb, this); | |
return vb.type; | |
} | |
// a field | |
return checkFieldAccess(scope); | |
} | |
// thus it was a type | |
bits &= ~RestrictiveFlagMASK; // clear bits | |
bits |= TYPE; | |
case TYPE : //========only type============== | |
constant = Constant.NotAConstant; | |
//deprecated test | |
if (isTypeUseDeprecated((TypeBinding) binding, scope)) | |
scope.problemReporter().deprecatedType((TypeBinding) binding, this); | |
return (TypeBinding) binding; | |
} | |
} | |
// error scenarii | |
return this.reportError(scope); | |
} | |
public String toStringExpression(){ | |
return new String(token);} | |
public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { | |
visitor.visit(this, scope); | |
visitor.endVisit(this, scope); | |
} | |
public String unboundReferenceErrorName(){ | |
return new String(token);} | |
} |