package org.eclipse.jdt.internal.compiler.ast;
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.Constant;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
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.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
public abstract class Reference extends Expression {
public Reference() {
super();
}
public abstract FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound);
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
return flowInfo;
}
@Override
public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) {
if (flowContext.isNullcheckedFieldAccess(this)) {
return true;
}
return super.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck);
}
protected boolean checkNullableFieldDereference(Scope scope, FieldBinding field, long sourcePosition, FlowContext flowContext, int ttlForFieldCheck) {
if (field != null) {
if (ttlForFieldCheck > 0 && scope.compilerOptions().enableSyntacticNullAnalysisForFields)
flowContext.recordNullCheckedFieldReference(this, ttlForFieldCheck);
if ((field.type.tagBits & TagBits.AnnotationNullable) != 0) {
scope.problemReporter().dereferencingNullableExpression(sourcePosition, scope.environment());
return true;
}
if (field.type.isFreeTypeVariable()) {
scope.problemReporter().fieldFreeTypeVariableReference(field, sourcePosition);
return true;
}
if ((field.tagBits & TagBits.AnnotationNullable) != 0) {
scope.problemReporter().nullableFieldDereference(field, sourcePosition);
return true;
}
}
return false;
}
public FieldBinding fieldBinding() {
return null ;
}
public void fieldStore(Scope currentScope, CodeStream codeStream, FieldBinding fieldBinding, MethodBinding syntheticWriteAccessor, TypeBinding receiverType, boolean isImplicitThisReceiver, boolean valueRequired) {
int pc = codeStream.position;
if (fieldBinding.isStatic()) {
if (valueRequired) {
switch (fieldBinding.type.id) {
case TypeIds.T_long :
case TypeIds.T_double :
codeStream.dup2();
break;
default :
codeStream.dup();
break;
}
}
if (syntheticWriteAccessor == null) {
TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, fieldBinding, receiverType, isImplicitThisReceiver);
codeStream.fieldAccess(Opcodes.OPC_putstatic, fieldBinding, constantPoolDeclaringClass);
} else {
codeStream.invoke(Opcodes.OPC_invokestatic, syntheticWriteAccessor, null );
}
} else {
if (valueRequired) {
switch (fieldBinding.type.id) {
case TypeIds.T_long :
case TypeIds.T_double :
codeStream.dup2_x1();
break;
default :
codeStream.dup_x1();
break;
}
}
if (syntheticWriteAccessor == null) {
TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, fieldBinding, receiverType, isImplicitThisReceiver);
codeStream.fieldAccess(Opcodes.OPC_putfield, fieldBinding, constantPoolDeclaringClass);
} else {
codeStream.invoke(Opcodes.OPC_invokestatic, syntheticWriteAccessor, null );
}
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
}
public abstract void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired);
public abstract void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired);
public abstract void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired);
public boolean isEquivalent(Reference reference) {
return false;
}
public FieldBinding lastFieldBinding() {
return null;
}
@Override
public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) {
if ((this.implicitConversion & TypeIds.BOXING) != 0)
return FlowInfo.NON_NULL;
FieldBinding fieldBinding = lastFieldBinding();
if (fieldBinding != null) {
if (fieldBinding.isFinal() && fieldBinding.constant() != Constant.NotAConstant)
return FlowInfo.NON_NULL;
if (fieldBinding.isNonNull() || flowContext.isNullcheckedFieldAccess(this)) {
return FlowInfo.NON_NULL;
} else if (fieldBinding.isNullable()) {
return FlowInfo.POTENTIALLY_NULL;
} else if (fieldBinding.type.isFreeTypeVariable()) {
return FlowInfo.FREE_TYPEVARIABLE;
}
}
if (this.resolvedType != null) {
return FlowInfo.tagBitsToNullStatus(this.resolvedType.tagBits);
}
return FlowInfo.UNKNOWN;
}
void reportOnlyUselesslyReadPrivateField(BlockScope currentScope, FieldBinding fieldBinding, boolean valueRequired) {
if (valueRequired) {
fieldBinding.compoundUseFlag = 0;
fieldBinding.modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
} else {
if (fieldBinding.isUsedOnlyInCompound()) {
fieldBinding.compoundUseFlag--;
if (fieldBinding.compoundUseFlag == 0
&& fieldBinding.isOrEnclosedByPrivateType()
&& (this.implicitConversion & TypeIds.UNBOXING) == 0)
{
currentScope.problemReporter().unusedPrivateField(fieldBinding.sourceField());
}
}
}
}
static void reportOnlyUselesslyReadLocal(BlockScope currentScope, LocalVariableBinding localBinding, boolean valueRequired) {
if (localBinding.declaration == null)
return;
if ((localBinding.declaration.bits & ASTNode.IsLocalDeclarationReachable) == 0)
return;
if (localBinding.useFlag >= LocalVariableBinding.USED)
return;
if (valueRequired) {
localBinding.useFlag = LocalVariableBinding.USED;
return;
} else {
localBinding.useFlag++;
if (localBinding.useFlag != LocalVariableBinding.UNUSED)
return;
}
if (localBinding.declaration instanceof Argument) {
MethodScope methodScope = currentScope.methodScope();
if (methodScope != null && !methodScope.isLambdaScope()) {
MethodBinding method = ((AbstractMethodDeclaration)methodScope.referenceContext()).binding;
boolean shouldReport = !method.isMain();
if (method.isImplementing()) {
shouldReport &= currentScope.compilerOptions().reportUnusedParameterWhenImplementingAbstract;
} else if (method.isOverriding()) {
shouldReport &= currentScope.compilerOptions().reportUnusedParameterWhenOverridingConcrete;
}
if (shouldReport) {
currentScope.problemReporter().unusedArgument(localBinding.declaration);
}
}
} else {
currentScope.problemReporter().unusedLocalVariable(localBinding.declaration);
}
}
}