package org.eclipse.jdt.internal.compiler.ast;
import java.util.ArrayList;
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.BranchLabel;
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.Constant;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
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.InferenceContext18;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
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;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement;
import org.eclipse.jdt.internal.compiler.util.Messages;
public abstract class Expression extends Statement {
public Constant constant;
public int statementEnd = -1;
public int implicitConversion;
public TypeBinding resolvedType;
public static Expression [] NO_EXPRESSIONS = new Expression[0];
public static final boolean isConstantValueRepresentable(Constant constant, int constantTypeID, int targetTypeID) {
if (targetTypeID == constantTypeID)
return true;
switch (targetTypeID) {
case T_char :
switch (constantTypeID) {
case T_char :
return true;
case T_double :
return constant.doubleValue() == constant.charValue();
case T_float :
return constant.floatValue() == constant.charValue();
case T_int :
return constant.intValue() == constant.charValue();
case T_short :
return constant.shortValue() == constant.charValue();
case T_byte :
return constant.byteValue() == constant.charValue();
case T_long :
return constant.longValue() == constant.charValue();
default :
return false;
}
case T_float :
switch (constantTypeID) {
case T_char :
return constant.charValue() == constant.floatValue();
case T_double :
return constant.doubleValue() == constant.floatValue();
case T_float :
return true;
case T_int :
return constant.intValue() == constant.floatValue();
case T_short :
return constant.shortValue() == constant.floatValue();
case T_byte :
return constant.byteValue() == constant.floatValue();
case T_long :
return constant.longValue() == constant.floatValue();
default :
return false;
}
case T_double :
switch (constantTypeID) {
case T_char :
return constant.charValue() == constant.doubleValue();
case T_double :
return true;
case T_float :
return constant.floatValue() == constant.doubleValue();
case T_int :
return constant.intValue() == constant.doubleValue();
case T_short :
return constant.shortValue() == constant.doubleValue();
case T_byte :
return constant.byteValue() == constant.doubleValue();
case T_long :
return constant.longValue() == constant.doubleValue();
default :
return false;
}
case T_byte :
switch (constantTypeID) {
case T_char :
return constant.charValue() == constant.byteValue();
case T_double :
return constant.doubleValue() == constant.byteValue();
case T_float :
return constant.floatValue() == constant.byteValue();
case T_int :
return constant.intValue() == constant.byteValue();
case T_short :
return constant.shortValue() == constant.byteValue();
case T_byte :
return true;
case T_long :
return constant.longValue() == constant.byteValue();
default :
return false;
}
case T_short :
switch (constantTypeID) {
case T_char :
return constant.charValue() == constant.shortValue();
case T_double :
return constant.doubleValue() == constant.shortValue();
case T_float :
return constant.floatValue() == constant.shortValue();
case T_int :
return constant.intValue() == constant.shortValue();
case T_short :
return true;
case T_byte :
return constant.byteValue() == constant.shortValue();
case T_long :
return constant.longValue() == constant.shortValue();
default :
return false;
}
case T_int :
switch (constantTypeID) {
case T_char :
return constant.charValue() == constant.intValue();
case T_double :
return constant.doubleValue() == constant.intValue();
case T_float :
return constant.floatValue() == constant.intValue();
case T_int :
return true;
case T_short :
return constant.shortValue() == constant.intValue();
case T_byte :
return constant.byteValue() == constant.intValue();
case T_long :
return constant.longValue() == constant.intValue();
default :
return false;
}
case T_long :
switch (constantTypeID) {
case T_char :
return constant.charValue() == constant.longValue();
case T_double :
return constant.doubleValue() == constant.longValue();
case T_float :
return constant.floatValue() == constant.longValue();
case T_int :
return constant.intValue() == constant.longValue();
case T_short :
return constant.shortValue() == constant.longValue();
case T_byte :
return constant.byteValue() == constant.longValue();
case T_long :
return true;
default :
return false;
}
default :
return false;
}
}
public Expression() {
super();
}
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
return flowInfo;
}
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
return analyseCode(currentScope, flowContext, flowInfo);
}
public final boolean checkCastTypesCompatibility(Scope scope, TypeBinding castType, TypeBinding expressionType, Expression expression) {
if (castType == null || expressionType == null) return true;
boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
boolean use17specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_7;
if (castType.isBaseType()) {
if (expressionType.isBaseType()) {
if (TypeBinding.equalsEquals(expressionType, castType)) {
if (expression != null) {
this.constant = expression.constant;
}
tagAsUnnecessaryCast(scope, castType);
return true;
}
boolean necessary = false;
if (expressionType.isCompatibleWith(castType)
|| (necessary = BaseTypeBinding.isNarrowing(castType.id, expressionType.id))) {
if (expression != null) {
expression.implicitConversion = (castType.id << 4) + expressionType.id;
if (expression.constant != Constant.NotAConstant) {
this.constant = expression.constant.castTo(expression.implicitConversion);
}
}
if (!necessary) tagAsUnnecessaryCast(scope, castType);
return true;
}
} else if (use17specifics && castType.isPrimitiveType() && expressionType instanceof ReferenceBinding &&
!expressionType.isBoxedPrimitiveType() && checkCastTypesCompatibility(scope, scope.boxing(castType), expressionType, expression)) {
return true;
} else if (use15specifics
&& scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) {
tagAsUnnecessaryCast(scope, castType);
return true;
}
return false;
} else if (use15specifics
&& expressionType.isBaseType()
&& scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) {
tagAsUnnecessaryCast(scope, castType);
return true;
}
if (castType.isIntersectionType18()) {
ReferenceBinding [] intersectingTypes = castType.getIntersectingTypes();
for (int i = 0, length = intersectingTypes.length; i < length; i++) {
if (!checkCastTypesCompatibility(scope, intersectingTypes[i], expressionType, expression))
return false;
}
return true;
}
switch(expressionType.kind()) {
case Binding.BASE_TYPE :
if (expressionType == TypeBinding.NULL) {
tagAsUnnecessaryCast(scope, castType);
return true;
}
return false;
case Binding.ARRAY_TYPE :
if (TypeBinding.equalsEquals(castType, expressionType)) {
tagAsUnnecessaryCast(scope, castType);
return true;
}
switch (castType.kind()) {
case Binding.ARRAY_TYPE :
TypeBinding castElementType = ((ArrayBinding) castType).elementsType();
TypeBinding exprElementType = ((ArrayBinding) expressionType).elementsType();
if (exprElementType.isBaseType() || castElementType.isBaseType()) {
if (TypeBinding.equalsEquals(castElementType, exprElementType)) {
tagAsNeedCheckCast();
return true;
}
return false;
}
return checkCastTypesCompatibility(scope, castElementType, exprElementType, expression);
case Binding.TYPE_PARAMETER :
TypeBinding match = expressionType.findSuperTypeOriginatingFrom(castType);
if (match == null) {
checkUnsafeCast(scope, castType, expressionType, null , true);
}
for (TypeBinding bound : ((TypeVariableBinding) castType).allUpperBounds()) {
if (!checkCastTypesCompatibility(scope, bound, expressionType, expression))
return false;
}
return true;
default:
switch (castType.id) {
case T_JavaLangCloneable :
case T_JavaIoSerializable :
tagAsNeedCheckCast();
return true;
case T_JavaLangObject :
tagAsUnnecessaryCast(scope, castType);
return true;
default :
return false;
}
}
case Binding.TYPE_PARAMETER :
TypeBinding match = expressionType.findSuperTypeOriginatingFrom(castType);
if (match == null) {
if (castType instanceof TypeVariableBinding) {
for (TypeBinding bound : ((TypeVariableBinding)castType).allUpperBounds()) {
if (!checkCastTypesCompatibility(scope, bound, expressionType, expression))
return false;
}
} else {
for (TypeBinding bound : ((TypeVariableBinding)expressionType).allUpperBounds()) {
if (!checkCastTypesCompatibility(scope, castType, bound, expression))
return false;
}
}
}
return checkUnsafeCast(scope, castType, expressionType, match, match == null);
case Binding.WILDCARD_TYPE :
case Binding.INTERSECTION_TYPE :
match = expressionType.findSuperTypeOriginatingFrom(castType);
if (match != null) {
return checkUnsafeCast(scope, castType, expressionType, match, false);
}
TypeBinding bound = ((WildcardBinding)expressionType).bound;
if (bound == null) bound = scope.getJavaLangObject();
return checkCastTypesCompatibility(scope, castType, bound, expression);
case Binding.INTERSECTION_TYPE18:
ReferenceBinding [] intersectingTypes = expressionType.getIntersectingTypes();
for (int i = 0, length = intersectingTypes.length; i < length; i++) {
if (checkCastTypesCompatibility(scope, castType, intersectingTypes[i], expression))
return true;
}
return false;
default:
if (expressionType.isInterface()) {
switch (castType.kind()) {
case Binding.ARRAY_TYPE :
switch (expressionType.id) {
case T_JavaLangCloneable :
case T_JavaIoSerializable :
tagAsNeedCheckCast();
return true;
default :
return false;
}
case Binding.TYPE_PARAMETER :
match = expressionType.findSuperTypeOriginatingFrom(castType);
if (match == null) {
checkUnsafeCast(scope, castType, expressionType, null , true);
}
for (TypeBinding upperBound : ((TypeVariableBinding)castType).allUpperBounds()) {
if (!checkCastTypesCompatibility(scope, upperBound, expressionType, expression))
return false;
}
return true;
default :
if (castType.isInterface()) {
ReferenceBinding interfaceType = (ReferenceBinding) expressionType;
match = interfaceType.findSuperTypeOriginatingFrom(castType);
if (match != null) {
return checkUnsafeCast(scope, castType, interfaceType, match, false);
}
tagAsNeedCheckCast();
match = castType.findSuperTypeOriginatingFrom(interfaceType);
if (match != null) {
return checkUnsafeCast(scope, castType, interfaceType, match, true);
}
if (use15specifics) {
checkUnsafeCast(scope, castType, expressionType, null , true);
if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_7) {
if (interfaceType.hasIncompatibleSuperType((ReferenceBinding) castType)) {
return false;
}
} else if (!castType.isRawType() && interfaceType.hasIncompatibleSuperType((ReferenceBinding) castType)) {
return false;
}
} else {
MethodBinding[] castTypeMethods = getAllOriginalInheritedMethods((ReferenceBinding) castType);
MethodBinding[] expressionTypeMethods = getAllOriginalInheritedMethods((ReferenceBinding) expressionType);
int exprMethodsLength = expressionTypeMethods.length;
for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++) {
for (int j = 0; j < exprMethodsLength; j++) {
if ((TypeBinding.notEquals(castTypeMethods[i].returnType, expressionTypeMethods[j].returnType))
&& (CharOperation.equals(castTypeMethods[i].selector, expressionTypeMethods[j].selector))
&& castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) {
return false;
}
}
}
}
return true;
} else {
if (castType.id == TypeIds.T_JavaLangObject) {
tagAsUnnecessaryCast(scope, castType);
return true;
}
tagAsNeedCheckCast();
match = castType.findSuperTypeOriginatingFrom(expressionType);
if (match != null) {
return checkUnsafeCast(scope, castType, expressionType, match, true);
}
if (((ReferenceBinding) castType).isFinal()) {
return false;
}
if (use15specifics) {
checkUnsafeCast(scope, castType, expressionType, null , true);
if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_7) {
if (((ReferenceBinding)castType).hasIncompatibleSuperType((ReferenceBinding) expressionType)) {
return false;
}
} else if (!castType.isRawType() && ((ReferenceBinding)castType).hasIncompatibleSuperType((ReferenceBinding) expressionType)) {
return false;
}
}
return true;
}
}
} else {
switch (castType.kind()) {
case Binding.ARRAY_TYPE :
if (expressionType.id == TypeIds.T_JavaLangObject) {
if (use15specifics) checkUnsafeCast(scope, castType, expressionType, expressionType, true);
tagAsNeedCheckCast();
return true;
}
return false;
case Binding.TYPE_PARAMETER :
match = expressionType.findSuperTypeOriginatingFrom(castType);
if (match == null) {
checkUnsafeCast(scope, castType, expressionType, null, true);
}
for (TypeBinding upperBound : ((TypeVariableBinding)castType).allUpperBounds()) {
if (!checkCastTypesCompatibility(scope, upperBound, expressionType, expression))
return false;
}
return true;
default :
if (castType.isInterface()) {
ReferenceBinding refExprType = (ReferenceBinding) expressionType;
match = refExprType.findSuperTypeOriginatingFrom(castType);
if (match != null) {
return checkUnsafeCast(scope, castType, expressionType, match, false);
}
if (refExprType.isFinal()) {
return false;
}
tagAsNeedCheckCast();
match = castType.findSuperTypeOriginatingFrom(expressionType);
if (match != null) {
return checkUnsafeCast(scope, castType, expressionType, match, true);
}
if (use15specifics) {
checkUnsafeCast(scope, castType, expressionType, null , true);
if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_7) {
if (refExprType.hasIncompatibleSuperType((ReferenceBinding) castType)) {
return false;
}
} else if (!castType.isRawType() && refExprType.hasIncompatibleSuperType((ReferenceBinding) castType)) {
return false;
}
}
return true;
} else {
match = expressionType.findSuperTypeOriginatingFrom(castType);
if (match != null) {
if (expression != null && castType.id == TypeIds.T_JavaLangString) this.constant = expression.constant;
return checkUnsafeCast(scope, castType, expressionType, match, false);
}
match = castType.findSuperTypeOriginatingFrom(expressionType);
if (match != null) {
tagAsNeedCheckCast();
return checkUnsafeCast(scope, castType, expressionType, match, true);
}
return false;
}
}
}
}
}
public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) {
boolean isNullable = false;
if (this.resolvedType != null) {
if ((this.resolvedType.tagBits & TagBits.AnnotationNonNull) != 0) {
return true;
} else if ((this.resolvedType.tagBits & TagBits.AnnotationNullable) != 0) {
isNullable = true;
}
}
LocalVariableBinding local = localVariableBinding();
if (local != null &&
(local.type.tagBits & TagBits.IsBaseType) == 0) {
if ((this.bits & ASTNode.IsNonNull) == 0) {
flowContext.recordUsingNullReference(scope, local, this,
FlowContext.MAY_NULL, flowInfo);
if (!flowInfo.isDefinitelyNonNull(local)) {
flowContext.recordAbruptExit();
}
}
flowInfo.markAsComparedEqualToNonNull(local);
flowContext.markFinallyNullStatus(local, FlowInfo.NON_NULL);
return true;
} else if (isNullable) {
scope.problemReporter().dereferencingNullableExpression(this);
return true;
}
return false;
}
public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
return checkNPE(scope, flowContext, flowInfo, 0);
}
protected void checkNPEbyUnboxing(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
int status;
if ((this.implicitConversion & UNBOXING) != 0
&& (this.bits & ASTNode.IsNonNull) == 0
&& (status = nullStatus(flowInfo, flowContext)) != FlowInfo.NON_NULL)
{
flowContext.recordUnboxing(scope, this, status, flowInfo);
}
}
public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) {
if (TypeBinding.equalsEquals(match, castType)) {
if (!isNarrowing) tagAsUnnecessaryCast(scope, castType);
return true;
}
if (match != null && (!castType.isReifiable() || !expressionType.isReifiable())) {
if(isNarrowing
? match.isProvablyDistinct(expressionType)
: castType.isProvablyDistinct(match)) {
return false;
}
}
if (!isNarrowing) tagAsUnnecessaryCast(scope, castType);
return true;
}
public void computeConversion(Scope scope, TypeBinding runtimeType, TypeBinding compileTimeType) {
if (runtimeType == null || compileTimeType == null)
return;
if (this.implicitConversion != 0) return;
if (runtimeType != TypeBinding.NULL && runtimeType.isBaseType()) {
if (!compileTimeType.isBaseType()) {
TypeBinding unboxedType = scope.environment().computeBoxingType(compileTimeType);
this.implicitConversion = TypeIds.UNBOXING;
scope.problemReporter().autoboxing(this, compileTimeType, runtimeType);
compileTimeType = unboxedType;
}
} else if (compileTimeType != TypeBinding.NULL && compileTimeType.isBaseType()) {
TypeBinding boxedType = scope.environment().computeBoxingType(runtimeType);
if (TypeBinding.equalsEquals(boxedType, runtimeType))
boxedType = compileTimeType;
if (boxedType.id > TypeIds.T_JavaLangBoolean) {
boxedType = compileTimeType;
}
this.implicitConversion = TypeIds.BOXING | (boxedType.id << 4) + compileTimeType.id;
scope.problemReporter().autoboxing(this, compileTimeType, scope.environment().computeBoxingType(boxedType));
return;
} else if (this.constant != Constant.NotAConstant && this.constant.typeID() != TypeIds.T_JavaLangString) {
this.implicitConversion = TypeIds.BOXING;
return;
}
int compileTimeTypeID, runtimeTypeID;
if ((compileTimeTypeID = compileTimeType.id) >= TypeIds.T_LastWellKnownTypeId) {
compileTimeTypeID = compileTimeType.erasure().id == TypeIds.T_JavaLangString ? TypeIds.T_JavaLangString : TypeIds.T_JavaLangObject;
} else if (runtimeType.isPrimitiveType() && compileTimeType instanceof ReferenceBinding && !compileTimeType.isBoxedPrimitiveType()) {
compileTimeTypeID = TypeIds.T_JavaLangObject;
}
switch (runtimeTypeID = runtimeType.id) {
case T_byte :
case T_short :
case T_char :
if (compileTimeTypeID == TypeIds.T_JavaLangObject) {
this.implicitConversion |= (runtimeTypeID << 4) + compileTimeTypeID;
} else {
this.implicitConversion |= (TypeIds.T_int << 4) + compileTimeTypeID;
}
break;
case T_JavaLangString :
case T_float :
case T_boolean :
case T_double :
case T_int :
case T_long :
this.implicitConversion |= (runtimeTypeID << 4) + compileTimeTypeID;
break;
default :
}
}
public static int computeNullStatus(int status, int combinedStatus) {
if ((combinedStatus & (FlowInfo.NULL|FlowInfo.POTENTIALLY_NULL)) != 0)
status |= FlowInfo.POTENTIALLY_NULL;
if ((combinedStatus & (FlowInfo.NON_NULL|FlowInfo.POTENTIALLY_NON_NULL)) != 0)
status |= FlowInfo.POTENTIALLY_NON_NULL;
if ((combinedStatus & (FlowInfo.UNKNOWN|FlowInfo.POTENTIALLY_UNKNOWN)) != 0)
status |= FlowInfo.POTENTIALLY_UNKNOWN;
return status;
}
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream) {
if ((this.bits & ASTNode.IsReachable) == 0) {
return;
}
generateCode(currentScope, codeStream, false);
}
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
if (this.constant != Constant.NotAConstant) {
int pc = codeStream.position;
codeStream.generateConstant(this.constant, this.implicitConversion);
codeStream.recordPositionsFrom(pc, this.sourceStart);
} else {
throw new ShouldNotImplement(Messages.ast_missingCode);
}
}
public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
Constant cst = optimizedBooleanConstant();
generateCode(currentScope, codeStream, valueRequired && cst == Constant.NotAConstant);
if ((cst != Constant.NotAConstant) && (cst.typeID() == TypeIds.T_boolean)) {
int pc = codeStream.position;
if (cst.booleanValue() == true) {
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.goto_(trueLabel);
}
}
}
} else {
if (valueRequired) {
if (falseLabel != null) {
if (trueLabel == null) {
codeStream.goto_(falseLabel);
}
}
}
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
return;
}
int position = codeStream.position;
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.ifne(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.ifeq(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(position, this.sourceEnd);
}
public void generateOptimizedStringConcatenation(BlockScope blockScope, CodeStream codeStream, int typeID) {
if (typeID == TypeIds.T_JavaLangString && this.constant != Constant.NotAConstant && this.constant.stringValue().length() == 0) {
return;
}
generateCode(blockScope, codeStream, true);
codeStream.invokeStringConcatenationAppendForType(typeID);
}
public void generateOptimizedStringConcatenationCreation(BlockScope blockScope, CodeStream codeStream, int typeID) {
codeStream.newStringContatenation();
codeStream.dup();
switch (typeID) {
case T_JavaLangObject :
case T_undefined :
codeStream.invokeStringConcatenationDefaultConstructor();
generateCode(blockScope, codeStream, true);
codeStream.invokeStringConcatenationAppendForType(TypeIds.T_JavaLangObject);
return;
case T_JavaLangString :
case T_null :
if (this.constant != Constant.NotAConstant) {
String stringValue = this.constant.stringValue();
if (stringValue.length() == 0) {
codeStream.invokeStringConcatenationDefaultConstructor();
return;
}
codeStream.ldc(stringValue);
} else {
generateCode(blockScope, codeStream, true);
codeStream.invokeStringValueOf(TypeIds.T_JavaLangObject);
}
break;
default :
generateCode(blockScope, codeStream, true);
codeStream.invokeStringValueOf(typeID);
}
codeStream.invokeStringConcatenationStringConstructor();
}
private MethodBinding[] getAllOriginalInheritedMethods(ReferenceBinding binding) {
ArrayList<MethodBinding> collector = new ArrayList<>();
getAllInheritedMethods0(binding, collector);
for (int i = 0, len = collector.size(); i < len; i++) {
collector.set(i, collector.get(i).original());
}
return collector.toArray(new MethodBinding[collector.size()]);
}
private void getAllInheritedMethods0(ReferenceBinding binding, ArrayList<MethodBinding> collector) {
if (!binding.isInterface()) return;
MethodBinding[] methodBindings = binding.methods();
for (int i = 0, max = methodBindings.length; i < max; i++) {
collector.add(methodBindings[i]);
}
ReferenceBinding[] superInterfaces = binding.superInterfaces();
for (int i = 0, max = superInterfaces.length; i < max; i++) {
getAllInheritedMethods0(superInterfaces[i], collector);
}
}
public static Binding getDirectBinding(Expression someExpression) {
if ((someExpression.bits & ASTNode.IgnoreNoEffectAssignCheck) != 0) {
return null;
}
if (someExpression instanceof SingleNameReference) {
return ((SingleNameReference)someExpression).binding;
} else if (someExpression instanceof FieldReference) {
FieldReference fieldRef = (FieldReference)someExpression;
if (fieldRef.receiver.isThis() && !(fieldRef.receiver instanceof QualifiedThisReference)) {
return fieldRef.binding;
}
} else if (someExpression instanceof Assignment) {
Expression lhs = ((Assignment)someExpression).lhs;
if ((lhs.bits & ASTNode.IsStrictlyAssigned) != 0) {
return getDirectBinding (((Assignment)someExpression).lhs);
} else if (someExpression instanceof PrefixExpression) {
return getDirectBinding (((Assignment)someExpression).lhs);
}
} else if (someExpression instanceof QualifiedNameReference) {
QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) someExpression;
if (qualifiedNameReference.indexOfFirstFieldBinding != 1
&& qualifiedNameReference.otherBindings == null) {
return qualifiedNameReference.binding;
}
} else if (someExpression.isThis()) {
return someExpression.resolvedType;
}
return null;
}
public boolean isCompactableOperation() {
return false;
}
public boolean isConstantValueOfTypeAssignableToType(TypeBinding constantType, TypeBinding targetType) {
if (this.constant == Constant.NotAConstant)
return false;
if (TypeBinding.equalsEquals(constantType, targetType))
return true;
if (BaseTypeBinding.isWidening(TypeIds.T_int, constantType.id)
&& (BaseTypeBinding.isNarrowing(targetType.id, TypeIds.T_int))) {
return isConstantValueRepresentable(this.constant, constantType.id, targetType.id);
}
return false;
}
public boolean isTypeReference() {
return false;
}
public LocalVariableBinding localVariableBinding() {
return null;
}
public void markAsNonNull() {
this.bits |= ASTNode.IsNonNull;
}
public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) {
return FlowInfo.NON_NULL;
}
public Constant optimizedBooleanConstant() {
return this.constant;
}
public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) {
return true;
}
public TypeBinding postConversionType(Scope scope) {
TypeBinding convertedType = this.resolvedType;
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 print(int indent, StringBuffer output) {
printIndent(indent, output);
return printExpression(indent, output);
}
public abstract StringBuffer printExpression(int indent, StringBuffer output);
@Override
public StringBuffer printStatement(int indent, StringBuffer output) {
return print(indent, output).append(";");
}
@Override
public void resolve(BlockScope scope) {
this.resolveType(scope);
return;
}
@Override
public TypeBinding resolveExpressionType(BlockScope scope) {
return resolveType(scope);
}
public TypeBinding resolveType(BlockScope scope) {
return null;
}
public TypeBinding resolveType(ClassScope scope) {
return null;
}
public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) {
setExpectedType(expectedType);
TypeBinding expressionType = this.resolveType(scope);
if (expressionType == null) return null;
if (TypeBinding.equalsEquals(expressionType, expectedType)) return expressionType;
if (!expressionType.isCompatibleWith(expectedType)) {
if (scope.isBoxingCompatibleWith(expressionType, expectedType)) {
computeConversion(scope, expectedType, expressionType);
} else {
scope.problemReporter().typeMismatchError(expressionType, expectedType, this, null);
return null;
}
}
return expressionType;
}
public Expression resolveExpressionExpecting(TypeBinding targetType, Scope scope, InferenceContext18 context) {
return this;
}
public boolean forcedToBeRaw(ReferenceContext referenceContext) {
if (this instanceof NameReference) {
final Binding receiverBinding = ((NameReference) this).binding;
if (receiverBinding.isParameter() && (((LocalVariableBinding) receiverBinding).tagBits & TagBits.ForcedToBeRawType) != 0) {
return true;
} else if (receiverBinding instanceof FieldBinding) {
FieldBinding field = (FieldBinding) receiverBinding;
if (field.type.isRawType()) {
if (referenceContext instanceof AbstractMethodDeclaration) {
AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration) referenceContext;
ReferenceBinding declaringClass = methodDecl.binding != null
? methodDecl.binding.declaringClass
: methodDecl.scope.enclosingReceiverType();
if (TypeBinding.notEquals(field.declaringClass, declaringClass)) {
return true;
}
} else if (referenceContext instanceof TypeDeclaration) {
TypeDeclaration type = (TypeDeclaration) referenceContext;
if (TypeBinding.notEquals(field.declaringClass, type.binding)) {
return true;
}
}
}
}
} else if (this instanceof MessageSend) {
if (!CharOperation.equals(((MessageSend) this).binding.declaringClass.getFileName(),
referenceContext.compilationResult().getFileName())) {
return true;
}
} else if (this instanceof FieldReference) {
FieldBinding field = ((FieldReference) this).binding;
if (!CharOperation.equals(field.declaringClass.getFileName(),
referenceContext.compilationResult().getFileName())) {
return true;
}
if (field.type.isRawType()) {
if (referenceContext instanceof AbstractMethodDeclaration) {
AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration) referenceContext;
if (TypeBinding.notEquals(field.declaringClass, methodDecl.binding.declaringClass)) {
return true;
}
} else if (referenceContext instanceof TypeDeclaration) {
TypeDeclaration type = (TypeDeclaration) referenceContext;
if (TypeBinding.notEquals(field.declaringClass, type.binding)) {
return true;
}
}
}
} else if (this instanceof ConditionalExpression) {
ConditionalExpression ternary = (ConditionalExpression) this;
if (ternary.valueIfTrue.forcedToBeRaw(referenceContext) || ternary.valueIfFalse.forcedToBeRaw(referenceContext)) {
return true;
}
} else if (this instanceof SwitchExpression) {
SwitchExpression se = (SwitchExpression) this;
for (Expression e : se.resultExpressions) {
if (e.forcedToBeRaw(referenceContext))
return true;
}
}
return false;
}
public Object reusableJSRTarget() {
if (this.constant != Constant.NotAConstant && (this.implicitConversion & TypeIds.BOXING) == 0) {
return this.constant;
}
return null;
}
public void setExpectedType(TypeBinding expectedType) {
}
public void setExpressionContext(ExpressionContext context) {
}
public boolean isCompatibleWith(TypeBinding left, Scope scope) {
return this.resolvedType != null && this.resolvedType.isCompatibleWith(left, scope);
}
public boolean isBoxingCompatibleWith(TypeBinding left, Scope scope) {
return this.resolvedType != null && isBoxingCompatible(this.resolvedType, left, this, scope);
}
public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope scope) {
return s.isCompatibleWith(t, scope);
}
public boolean isExactMethodReference() {
return false;
}
public boolean isPolyExpression() throws UnsupportedOperationException {
return false;
}
public boolean isPolyExpression(MethodBinding method) {
return false;
}
public void tagAsNeedCheckCast() {
}
public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) {
}
public Expression toTypeReference() {
return this;
}
@Override
public void traverse(ASTVisitor visitor, BlockScope scope) {
}
public void traverse(ASTVisitor visitor, ClassScope scope) {
}
public boolean statementExpression() {
return false;
}
public boolean isTrulyExpression() {
return true;
}
public VariableBinding nullAnnotatedVariableBinding(boolean supportTypeAnnotations) {
return null;
}
public boolean isFunctionalType() {
return false;
}
public Expression [] getPolyExpressions() {
return isPolyExpression() ? new Expression [] { this } : NO_EXPRESSIONS;
}
public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope) {
return isCompatibleWith(targetType, scope);
}
protected Constant optimizedNullComparisonConstant() {
return Constant.NotAConstant;
}
}