package org.eclipse.jdt.internal.compiler.ast;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.eclipse.jdt.internal.compiler.codegen.Opcodes;
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.MissingTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
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.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.AbortMethod;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
public class SingleNameReference extends NameReference implements OperatorIds {
public static final int READ = 0;
public static final int WRITE = 1;
public char[] token;
public MethodBinding[] syntheticAccessors;
public TypeBinding genericCast;
public boolean isLabel;
public SingleNameReference(char[] source, long pos) {
super();
this.token = source;
this.sourceStart = (int) (pos >>> 32);
this.sourceEnd = (int) pos;
}
@Override
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
boolean isReachable = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
if (isCompound) {
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.FIELD :
FieldBinding fieldBinding = (FieldBinding) this.binding;
if (fieldBinding.isBlankFinal()
&& currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) {
FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(fieldBinding.declaringClass.original(), flowInfo);
if (!fieldInits.isDefinitelyAssigned(fieldBinding)) {
currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
}
}
manageSyntheticAccessIfNecessary(currentScope, flowInfo, true );
break;
case Binding.LOCAL :
LocalVariableBinding localBinding;
if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
currentScope.problemReporter().uninitializedLocalVariable(localBinding, this, currentScope);
}
if (localBinding.useFlag != LocalVariableBinding.USED) {
if (isReachable && (this.implicitConversion & TypeIds.UNBOXING) != 0) {
localBinding.useFlag = LocalVariableBinding.USED;
} else {
if (localBinding.useFlag <= LocalVariableBinding.UNUSED)
localBinding.useFlag--;
}
}
}
}
if (assignment.expression != null) {
flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
}
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.FIELD :
manageSyntheticAccessIfNecessary(currentScope, flowInfo, false );
FieldBinding fieldBinding = (FieldBinding) this.binding;
if (fieldBinding.isFinal()) {
if (!isCompound && fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
if (flowInfo.isPotentiallyAssigned(fieldBinding)) {
currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this);
} else {
flowContext.recordSettingFinal(fieldBinding, this, flowInfo);
}
flowInfo.markAsDefinitelyAssigned(fieldBinding);
} else {
currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
}
} else if (!isCompound && (fieldBinding.isNonNull() || fieldBinding.type.isTypeVariable())
&& TypeBinding.equalsEquals(fieldBinding.declaringClass, currentScope.enclosingReceiverType())) {
flowInfo.markAsDefinitelyAssigned(fieldBinding);
}
break;
case Binding.LOCAL :
LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
final boolean isFinal = localBinding.isFinal();
if (!flowInfo.isDefinitelyAssigned(localBinding)){
this.bits |= ASTNode.FirstAssignmentToLocal;
} else {
this.bits &= ~ASTNode.FirstAssignmentToLocal;
}
if (flowInfo.isPotentiallyAssigned(localBinding) || (this.bits & ASTNode.IsCapturedOuterLocal) != 0) {
localBinding.tagBits &= ~TagBits.IsEffectivelyFinal;
if (!isFinal && (this.bits & ASTNode.IsCapturedOuterLocal) != 0) {
currentScope.problemReporter().cannotReferToNonEffectivelyFinalOuterLocal(localBinding, this);
}
}
if (! isFinal && (localBinding.tagBits & TagBits.IsEffectivelyFinal) != 0 && (localBinding.tagBits & TagBits.IsArgument) == 0) {
flowContext.recordSettingFinal(localBinding, this, flowInfo);
} else if (isFinal) {
if ((this.bits & ASTNode.DepthMASK) == 0) {
if ((isReachable && isCompound) || !localBinding.isBlankFinal()){
currentScope.problemReporter().cannotAssignToFinalLocal(localBinding, this);
} else if (flowInfo.isPotentiallyAssigned(localBinding)) {
currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this);
} else if ((this.bits & ASTNode.IsCapturedOuterLocal) != 0) {
currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this);
} else {
flowContext.recordSettingFinal(localBinding, this, flowInfo);
}
} else {
currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this);
}
}
else if ((localBinding.tagBits & TagBits.IsArgument) != 0) {
currentScope.problemReporter().parameterAssignment(localBinding, this);
}
flowInfo.markAsDefinitelyAssigned(localBinding);
}
manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
return flowInfo;
}
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
return analyseCode(currentScope, flowContext, flowInfo, true);
}
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.FIELD :
if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
manageSyntheticAccessIfNecessary(currentScope, flowInfo, true );
}
FieldBinding fieldBinding = (FieldBinding) this.binding;
if (fieldBinding.isBlankFinal() && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) {
FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(fieldBinding.declaringClass.original(), flowInfo);
if (!fieldInits.isDefinitelyAssigned(fieldBinding)) {
currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
}
}
break;
case Binding.LOCAL :
LocalVariableBinding localBinding;
if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
currentScope.problemReporter().uninitializedLocalVariable(localBinding, this, currentScope);
}
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
localBinding.useFlag = LocalVariableBinding.USED;
} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
localBinding.useFlag = LocalVariableBinding.FAKE_USED;
}
}
if (valueRequired) {
manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
}
return flowInfo;
}
public TypeBinding checkFieldAccess(BlockScope scope) {
FieldBinding fieldBinding = (FieldBinding) this.binding;
this.constant = fieldBinding.constant(scope);
this.bits &= ~ASTNode.RestrictiveFlagMASK;
this.bits |= Binding.FIELD;
MethodScope methodScope = scope.methodScope();
if (fieldBinding.isStatic()) {
ReferenceBinding declaringClass = fieldBinding.declaringClass;
if (declaringClass.isEnum() && !scope.isModuleScope()) {
SourceTypeBinding sourceType = scope.enclosingSourceType();
if (this.constant == Constant.NotAConstant
&& !methodScope.isStatic
&& (TypeBinding.equalsEquals(sourceType, declaringClass) || TypeBinding.equalsEquals(sourceType.superclass, declaringClass))
&& methodScope.isInsideInitializerOrConstructor()) {
scope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this);
}
}
} else {
if (scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding);
}
if (methodScope.isStatic) {
scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding);
return fieldBinding.type;
} else {
scope.tagAsAccessingEnclosingInstanceStateOf(fieldBinding.declaringClass, false );
}
}
if (isFieldUseDeprecated(fieldBinding, scope, this.bits))
scope.problemReporter().deprecatedField(fieldBinding, this);
if ((this.bits & ASTNode.IsStrictlyAssigned) == 0
&& TypeBinding.equalsEquals(methodScope.enclosingSourceType(), fieldBinding.original().declaringClass)
&& methodScope.lastVisibleFieldID >= 0
&& fieldBinding.id >= methodScope.lastVisibleFieldID
&& (!fieldBinding.isStatic() || methodScope.isStatic)) {
scope.problemReporter().forwardReference(this, 0, fieldBinding);
this.bits |= ASTNode.IgnoreNoEffectAssignCheck;
}
return fieldBinding.type;
}
@Override
public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) {
if (!super.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck)) {
CompilerOptions compilerOptions = scope.compilerOptions();
if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) {
if (this.binding instanceof FieldBinding) {
return checkNullableFieldDereference(scope, (FieldBinding) this.binding, ((long)this.sourceStart<<32)+this.sourceEnd, flowContext, ttlForFieldCheck);
}
}
}
return false;
}
@Override
public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
if (runtimeTimeType == null || compileTimeType == null)
return;
if (this.binding != null && this.binding.isValidBinding()) {
TypeBinding originalType = null;
if ((this.bits & Binding.FIELD) != 0) {
FieldBinding field = (FieldBinding) this.binding;
FieldBinding originalBinding = field.original();
originalType = originalBinding.type;
} else if ((this.bits & Binding.LOCAL) != 0) {
LocalVariableBinding local = (LocalVariableBinding) this.binding;
originalType = local.type;
}
if (originalType != null && originalType.leafComponentType().isTypeVariable()) {
TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType())
? compileTimeType
: runtimeTimeType;
this.genericCast = originalType.genericCast(scope.boxing(targetType));
if (this.genericCast instanceof ReferenceBinding) {
ReferenceBinding referenceCast = (ReferenceBinding) this.genericCast;
if (!referenceCast.canBeSeenBy(scope)) {
scope.problemReporter().invalidType(this,
new ProblemReferenceBinding(
CharOperation.splitOn('.', referenceCast.shortReadableName()),
referenceCast,
ProblemReasons.NotVisible));
}
}
}
}
super.computeConversion(scope, runtimeTimeType, compileTimeType);
}
@Override
public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
if (assignment.expression.isCompactableOperation()) {
BinaryExpression operation = (BinaryExpression) assignment.expression;
int operator = (operation.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT;
SingleNameReference variableReference;
if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == this.binding)) {
variableReference.generateCompoundAssignment(currentScope, codeStream, this.syntheticAccessors == null ? null : this.syntheticAccessors[SingleNameReference.WRITE], operation.right, operator, operation.implicitConversion, valueRequired);
if (valueRequired) {
codeStream.generateImplicitConversion(assignment.implicitConversion);
}
return;
}
if ((operation.right instanceof SingleNameReference)
&& ((operator == OperatorIds.PLUS) || (operator == OperatorIds.MULTIPLY))
&& ((variableReference = (SingleNameReference) operation.right).binding == this.binding)
&& (operation.left.constant != Constant.NotAConstant)
&& (((operation.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) != TypeIds.T_JavaLangString)
&& (((operation.right.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) != TypeIds.T_JavaLangString)) {
variableReference.generateCompoundAssignment(currentScope, codeStream, this.syntheticAccessors == null ? null : this.syntheticAccessors[SingleNameReference.WRITE], operation.left, operator, operation.implicitConversion, valueRequired);
if (valueRequired) {
codeStream.generateImplicitConversion(assignment.implicitConversion);
}
return;
}
}
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.FIELD :
int pc = codeStream.position;
FieldBinding codegenBinding = ((FieldBinding) this.binding).original();
if (!codegenBinding.isStatic()) {
if ((this.bits & ASTNode.DepthMASK) != 0) {
ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT);
Object[] emulationPath = currentScope.getEmulationPath(targetType, true , false);
codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
} else {
generateReceiver(codeStream);
}
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
assignment.expression.generateCode(currentScope, codeStream, true);
fieldStore(currentScope, codeStream, codegenBinding, this.syntheticAccessors == null ? null : this.syntheticAccessors[SingleNameReference.WRITE], this.actualReceiverType, true , valueRequired);
if (valueRequired) {
codeStream.generateImplicitConversion(assignment.implicitConversion);
}
return;
case Binding.LOCAL :
LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
if (localBinding.resolvedPosition != -1) {
assignment.expression.generateCode(currentScope, codeStream, true);
} else {
if (assignment.expression.constant != Constant.NotAConstant) {
if (valueRequired) {
codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion);
}
} else {
assignment.expression.generateCode(currentScope, codeStream, true);
if (valueRequired) {
codeStream.generateImplicitConversion(assignment.implicitConversion);
} else {
switch(localBinding.type.id) {
case TypeIds.T_long :
case TypeIds.T_double :
codeStream.pop2();
break;
default :
codeStream.pop();
break;
}
}
}
return;
}
if (localBinding.type.isArrayType()
&& ((assignment.expression instanceof CastExpression)
&& (((CastExpression)assignment.expression).innermostCastedExpression().resolvedType == TypeBinding.NULL))){
codeStream.checkcast(localBinding.type);
}
codeStream.store(localBinding, valueRequired);
if ((this.bits & ASTNode.FirstAssignmentToLocal) != 0) {
localBinding.recordInitializationStartPC(codeStream.position);
}
if (valueRequired) {
codeStream.generateImplicitConversion(assignment.implicitConversion);
}
}
}
@Override
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);
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
return;
} else {
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.FIELD :
FieldBinding codegenField = ((FieldBinding) this.binding).original();
Constant fieldConstant = codegenField.constant();
if (fieldConstant != Constant.NotAConstant) {
if (valueRequired) {
codeStream.generateConstant(fieldConstant, this.implicitConversion);
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
return;
}
if (codegenField.isStatic()) {
if (!valueRequired
&& TypeBinding.equalsEquals(((FieldBinding)this.binding).original().declaringClass, this.actualReceiverType.erasure())
&& ((this.implicitConversion & TypeIds.UNBOXING) == 0)
&& this.genericCast == null) {
codeStream.recordPositionsFrom(pc, this.sourceStart);
return;
}
if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) {
TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true );
codeStream.fieldAccess(Opcodes.OPC_getstatic, codegenField, constantPoolDeclaringClass);
} else {
codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null );
}
} else {
if (!valueRequired
&& (this.implicitConversion & TypeIds.UNBOXING) == 0
&& this.genericCast == null) {
codeStream.recordPositionsFrom(pc, this.sourceStart);
return;
}
if ((this.bits & ASTNode.DepthMASK) != 0) {
ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT);
Object[] emulationPath = currentScope.getEmulationPath(targetType, true , false);
codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
} else {
generateReceiver(codeStream);
}
if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) {
TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true );
codeStream.fieldAccess(Opcodes.OPC_getfield, codegenField, constantPoolDeclaringClass);
} else {
codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null );
}
}
break;
case Binding.LOCAL :
LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
if (localBinding.resolvedPosition == -1) {
if (valueRequired) {
localBinding.useFlag = LocalVariableBinding.USED;
throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null);
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
return;
}
if (!valueRequired && (this.implicitConversion & TypeIds.UNBOXING) == 0) {
codeStream.recordPositionsFrom(pc, this.sourceStart);
return;
}
if ((this.bits & ASTNode.IsCapturedOuterLocal) != 0) {
checkEffectiveFinality(localBinding, currentScope);
VariableBinding[] path = currentScope.getEmulationPath(localBinding);
codeStream.generateOuterAccess(path, this, localBinding, currentScope);
} else {
codeStream.load(localBinding);
}
break;
default:
codeStream.recordPositionsFrom(pc, this.sourceStart);
return;
}
}
if (this.genericCast != null) codeStream.checkcast(this.genericCast);
if (valueRequired) {
codeStream.generateImplicitConversion(this.implicitConversion);
} else {
boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0;
if (isUnboxing) codeStream.generateImplicitConversion(this.implicitConversion);
switch (isUnboxing ? postConversionType(currentScope).id : this.resolvedType.id) {
case T_long :
case T_double :
codeStream.pop2();
break;
default :
codeStream.pop();
}
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
}
@Override
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.LOCAL:
LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
Reference.reportOnlyUselesslyReadLocal(currentScope, localBinding, valueRequired);
break;
case Binding.FIELD:
reportOnlyUselesslyReadPrivateField(currentScope, (FieldBinding)this.binding, valueRequired);
}
this.generateCompoundAssignment(
currentScope,
codeStream,
this.syntheticAccessors == null ? null : this.syntheticAccessors[SingleNameReference.WRITE],
expression,
operator,
assignmentImplicitConversion,
valueRequired);
}
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.FIELD :
FieldBinding codegenField = ((FieldBinding) this.binding).original();
if (codegenField.isStatic()) {
if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) {
TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true );
codeStream.fieldAccess(Opcodes.OPC_getstatic, codegenField, constantPoolDeclaringClass);
} else {
codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null );
}
} else {
if ((this.bits & ASTNode.DepthMASK) != 0) {
ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT);
Object[] emulationPath = currentScope.getEmulationPath(targetType, true , false);
codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
} else {
codeStream.aload_0();
}
codeStream.dup();
if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) {
TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true );
codeStream.fieldAccess(Opcodes.OPC_getfield, codegenField, constantPoolDeclaringClass);
} else {
codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null );
}
}
break;
case Binding.LOCAL :
LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
Constant assignConstant;
switch (localBinding.type.id) {
case T_JavaLangString :
codeStream.generateStringConcatenationAppend(currentScope, this, expression);
if (valueRequired) {
codeStream.dup();
}
codeStream.store(localBinding, false);
return;
case T_int :
assignConstant = expression.constant;
if (localBinding.resolvedPosition == -1) {
if (valueRequired) {
localBinding.useFlag = LocalVariableBinding.USED;
throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null);
} else if (assignConstant == Constant.NotAConstant) {
expression.generateCode(currentScope, codeStream, false);
}
return;
}
if ((assignConstant != Constant.NotAConstant)
&& (assignConstant.typeID() != TypeIds.T_float)
&& (assignConstant.typeID() != TypeIds.T_double)) {
switch (operator) {
case PLUS :
int increment = assignConstant.intValue();
if (increment != (short) increment) break;
codeStream.iinc(localBinding.resolvedPosition, increment);
if (valueRequired) {
codeStream.load(localBinding);
}
return;
case MINUS :
increment = -assignConstant.intValue();
if (increment != (short) increment) break;
codeStream.iinc(localBinding.resolvedPosition, increment);
if (valueRequired) {
codeStream.load(localBinding);
}
return;
}
}
default :
if (localBinding.resolvedPosition == -1) {
assignConstant = expression.constant;
if (valueRequired) {
localBinding.useFlag = LocalVariableBinding.USED;
throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null);
} else if (assignConstant == Constant.NotAConstant) {
expression.generateCode(currentScope, codeStream, false);
}
return;
}
codeStream.load(localBinding);
}
}
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 :
if (this.genericCast != null)
codeStream.checkcast(this.genericCast);
codeStream.generateImplicitConversion(this.implicitConversion);
if (expression == IntLiteral.One){
codeStream.generateConstant(expression.constant, this.implicitConversion);
} else {
expression.generateCode(currentScope, codeStream, true);
}
codeStream.sendOperator(operator, operationTypeID);
codeStream.generateImplicitConversion(assignmentImplicitConversion);
}
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.FIELD :
FieldBinding codegenField = ((FieldBinding) this.binding).original();
fieldStore(currentScope, codeStream, codegenField, writeAccessor, this.actualReceiverType, true , valueRequired);
return;
case Binding.LOCAL :
LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
if (valueRequired) {
switch (localBinding.type.id) {
case TypeIds.T_long :
case TypeIds.T_double :
codeStream.dup2();
break;
default:
codeStream.dup();
break;
}
}
codeStream.store(localBinding, false);
}
}
@Override
public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.FIELD :
FieldBinding fieldBinding = (FieldBinding)this.binding;
reportOnlyUselesslyReadPrivateField(currentScope, fieldBinding, valueRequired);
FieldBinding codegenField = fieldBinding.original();
if (codegenField.isStatic()) {
if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) {
TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true );
codeStream.fieldAccess(Opcodes.OPC_getstatic, codegenField, constantPoolDeclaringClass);
} else {
codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null );
}
} else {
if ((this.bits & ASTNode.DepthMASK) != 0) {
ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT);
Object[] emulationPath = currentScope.getEmulationPath(targetType, true , false);
codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
} else {
codeStream.aload_0();
}
codeStream.dup();
if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) {
TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true );
codeStream.fieldAccess(Opcodes.OPC_getfield, codegenField, constantPoolDeclaringClass);
} else {
codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null );
}
}
TypeBinding operandType;
if (this.genericCast != null) {
codeStream.checkcast(this.genericCast);
operandType = this.genericCast;
} else {
operandType = codegenField.type;
}
if (valueRequired) {
if (codegenField.isStatic()) {
switch (operandType.id) {
case TypeIds.T_long :
case TypeIds.T_double :
codeStream.dup2();
break;
default:
codeStream.dup();
break;
}
} else {
switch (operandType.id) {
case TypeIds.T_long :
case TypeIds.T_double :
codeStream.dup2_x1();
break;
default:
codeStream.dup_x1();
break;
}
}
}
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(currentScope, codeStream, codegenField, this.syntheticAccessors == null ? null : this.syntheticAccessors[SingleNameReference.WRITE], this.actualReceiverType, true , false);
return;
case Binding.LOCAL :
LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
Reference.reportOnlyUselesslyReadLocal(currentScope, localBinding, valueRequired);
if (localBinding.resolvedPosition == -1) {
if (valueRequired) {
localBinding.useFlag = LocalVariableBinding.USED;
throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null);
}
return;
}
if (TypeBinding.equalsEquals(localBinding.type, TypeBinding.INT)) {
if (valueRequired) {
codeStream.load(localBinding);
}
if (postIncrement.operator == OperatorIds.PLUS) {
codeStream.iinc(localBinding.resolvedPosition, 1);
} else {
codeStream.iinc(localBinding.resolvedPosition, -1);
}
} else {
codeStream.load(localBinding);
if (valueRequired){
switch (localBinding.type.id) {
case TypeIds.T_long :
case TypeIds.T_double :
codeStream.dup2();
break;
default:
codeStream.dup();
break;
}
}
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);
codeStream.store(localBinding, false);
}
}
}
public void generateReceiver(CodeStream codeStream) {
codeStream.aload_0();
}
@Override
public TypeBinding[] genericTypeArguments() {
return null;
}
@Override
public boolean isEquivalent(Reference reference) {
char[] otherToken = null;
if (reference instanceof SingleNameReference) {
otherToken = ((SingleNameReference) reference).token;
} else if (reference instanceof FieldReference) {
FieldReference fr = (FieldReference) reference;
if (fr.receiver.isThis() && !(fr.receiver instanceof QualifiedThisReference))
otherToken = fr.token;
}
return otherToken != null && CharOperation.equals(this.token, otherToken);
}
@Override
public LocalVariableBinding localVariableBinding() {
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.FIELD :
break;
case Binding.LOCAL :
return (LocalVariableBinding) this.binding;
}
return null;
}
@Override
public VariableBinding nullAnnotatedVariableBinding(boolean supportTypeAnnotations) {
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.FIELD :
case Binding.LOCAL :
if (supportTypeAnnotations
|| (((VariableBinding)this.binding).tagBits & TagBits.AnnotationNullMASK) != 0)
return (VariableBinding) this.binding;
}
return null;
}
@Override
public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) {
if ((this.implicitConversion & TypeIds.BOXING) != 0)
return FlowInfo.NON_NULL;
LocalVariableBinding local = localVariableBinding();
if (local != null) {
return flowInfo.nullStatus(local);
}
return super.nullStatus(flowInfo, flowContext);
}
public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
if (((this.bits & ASTNode.DepthMASK) == 0 && (this.bits & ASTNode.IsCapturedOuterLocal) == 0) || (this.constant != Constant.NotAConstant)) {
return;
}
if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) {
LocalVariableBinding localVariableBinding = (LocalVariableBinding) this.binding;
if (localVariableBinding != null) {
if (localVariableBinding.isUninitializedIn(currentScope)) {
return;
}
if ((localVariableBinding.tagBits & TagBits.IsEffectivelyFinal) == 0) {
return;
}
switch(localVariableBinding.useFlag) {
case LocalVariableBinding.FAKE_USED :
case LocalVariableBinding.USED :
currentScope.emulateOuterAccess(localVariableBinding);
}
}
}
}
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) {
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return;
if (this.constant != Constant.NotAConstant)
return;
if ((this.bits & Binding.FIELD) != 0) {
FieldBinding fieldBinding = (FieldBinding) this.binding;
FieldBinding codegenField = fieldBinding.original();
if (((this.bits & ASTNode.DepthMASK) != 0)
&& ((codegenField.isPrivate()
&& !currentScope.enclosingSourceType().isNestmateOf(codegenField.declaringClass) )
|| (codegenField.isProtected()
&& codegenField.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage()))) {
if (this.syntheticAccessors == null)
this.syntheticAccessors = new MethodBinding[2];
this.syntheticAccessors[isReadAccess ? SingleNameReference.READ : SingleNameReference.WRITE] =
((SourceTypeBinding)currentScope.enclosingSourceType().
enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT)).addSyntheticMethod(codegenField, isReadAccess, false );
currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, isReadAccess);
return;
}
}
}
@Override
public TypeBinding postConversionType(Scope scope) {
TypeBinding convertedType = this.resolvedType;
if (this.genericCast != null)
convertedType = this.genericCast;
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);
}
return convertedType;
}
@Override
public StringBuffer printExpression(int indent, StringBuffer output){
return output.append(this.token);
}
public TypeBinding reportError(BlockScope scope) {
this.constant = Constant.NotAConstant;
if (this.binding instanceof ProblemFieldBinding) {
scope.problemReporter().invalidField(this, (FieldBinding) this.binding);
} else if (this.binding instanceof ProblemReferenceBinding || this.binding instanceof MissingTypeBinding) {
scope.problemReporter().invalidType(this, (TypeBinding) this.binding);
} else {
scope.problemReporter().unresolvableReference(this, this.binding);
}
return null;
}
@Override
public TypeBinding resolveType(BlockScope scope) {
if (this.actualReceiverType != null) {
this.binding = scope.getField(this.actualReceiverType, this.token, this);
} else {
this.actualReceiverType = scope.enclosingSourceType();
this.binding = scope.getBinding(this.token, this.bits & ASTNode.RestrictiveFlagMASK, this, true );
}
if (this.binding.isValidBinding()) {
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.VARIABLE :
case Binding.VARIABLE | Binding.TYPE :
if (this.binding instanceof VariableBinding) {
VariableBinding variable = (VariableBinding) this.binding;
TypeBinding variableType;
if (this.binding instanceof LocalVariableBinding) {
this.bits &= ~ASTNode.RestrictiveFlagMASK;
this.bits |= Binding.LOCAL;
((LocalVariableBinding) this.binding).markReferenced();
if (!variable.isFinal() && (this.bits & ASTNode.IsCapturedOuterLocal) != 0) {
if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8)
scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)variable, this);
}
variableType = variable.type;
this.constant = (this.bits & ASTNode.IsStrictlyAssigned) == 0 ? variable.constant(scope) : Constant.NotAConstant;
} else {
variableType = checkFieldAccess(scope);
}
if (variableType != null) {
this.resolvedType = variableType = (((this.bits & ASTNode.IsStrictlyAssigned) == 0)
? variableType.capture(scope, this.sourceStart, this.sourceEnd)
: variableType);
if ((variableType.tagBits & TagBits.HasMissingType) != 0) {
if ((this.bits & Binding.LOCAL) == 0) {
scope.problemReporter().invalidType(this, variableType);
}
return null;
}
}
return variableType;
}
this.bits &= ~ASTNode.RestrictiveFlagMASK;
this.bits |= Binding.TYPE;
case Binding.TYPE :
this.constant = Constant.NotAConstant;
TypeBinding type = (TypeBinding)this.binding;
if (isTypeUseDeprecated(type, scope))
scope.problemReporter().deprecatedType(type, this);
type = scope.environment().convertToRawType(type, false );
return this.resolvedType = type;
}
}
return this.resolvedType = reportError(scope);
}
@Override
public void traverse(ASTVisitor visitor, BlockScope scope) {
visitor.visit(this, scope);
visitor.endVisit(this, scope);
}
@Override
public void traverse(ASTVisitor visitor, ClassScope scope) {
visitor.visit(this, scope);
visitor.endVisit(this, scope);
}
@Override
public String unboundReferenceErrorName(){
return new String(this.token);
}
@Override
public char[][] getName() {
return new char[][] {this.token};
}
}