Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*******************************************************************************
* Copyright (c) 2000, 2023 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - Contributions for
* bug 292478 - Report potentially null across variable assignment
* bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null"
* bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
* bug 331649 - [compiler][null] consider null annotations for fields
* bug 383368 - [compiler][null] syntactic null analysis for field references
* bug 400761 - [compiler][null] null may be return as boolean without a diagnostic
* bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check
* bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking
* Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
* Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
* Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec)
* Bug 426792 - [1.8][inference][impl] generify new type inference engine
* Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference"
* Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280)
* Bug 426996 - [1.8][inference] try to avoid method Expression.unresolve()?
* Bug 428274 - [1.8] [compiler] Cannot cast from Number to double
* Bug 428352 - [1.8][compiler] Resolution errors don't always surface
* Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression
* Lars Vogel - Contributions for
* Bug 473178
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
import java.util.ArrayList;
import java.util.List;
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.TypeConstants;
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;
//Some expression may not be used - from a java semantic point
//of view only - as statements. Other may. In order to avoid the creation
//of wrappers around expression in order to tune them as expression
//Expression is a subclass of Statement. See the message isValidJavaStatement()
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) {
//true if there is no loss of precision while casting.
// constantTypeID == constant.typeID
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;//boolean
}
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;//boolean
}
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; //boolean
}
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; //boolean
}
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; //boolean
}
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; //boolean
}
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; //boolean
}
default :
return false; //boolean
}
}
public Expression() {
super();
}
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
return flowInfo;
}
/**
* More sophisticated for of the flow analysis used for analyzing expressions, and be able to optimize out
* portions of expressions where no actual value is required.
*
* @return The state of initialization after the analysis of the current expression
*/
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
return analyseCode(currentScope, flowContext, flowInfo);
}
/**
* Back-propagation of flow info: before analysing a branch where a given condition is known to hold true/false respectively,
* ask the condition to contribute its information to the given flowInfo.
* @param flowInfo the info to be used for analysing the branch
* @param result condition result that would cause entering the branch
*/
protected void updateFlowOnBooleanResult(FlowInfo flowInfo, boolean result) {
// nop
}
/**
* Returns false if cast is not legal.
*/
public final boolean checkCastTypesCompatibility(Scope scope, TypeBinding castType, TypeBinding expressionType, Expression expression, boolean useAutoBoxing) {
// see specifications 5.5
// handle errors and process constant when needed
// if either one of the type is null ==>
// some error has been already reported some where ==>
// we then do not report an obvious-cascade-error.
if (castType == null || expressionType == null) return true;
// identity conversion cannot be performed upfront, due to side-effects
// like constant propagation
boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
boolean use17specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_7;
useAutoBoxing &= use15specifics;
if (castType.isBaseType()) {
if (expressionType.isBaseType()) {
if (TypeBinding.equalsEquals(expressionType, castType)) {
if (expression != null) {
this.constant = expression.constant; //use the same 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 (useAutoBoxing && use17specifics && castType.isPrimitiveType() && expressionType instanceof ReferenceBinding &&
!expressionType.isBoxedPrimitiveType() && checkCastTypesCompatibility(scope, scope.boxing(castType), expressionType, expression, useAutoBoxing)) {
// cast from any reference type (other than boxing types) to base type allowed from 1.7, see JLS $5.5
// by our own interpretation (in accordance with javac) we reject arays, though.
return true;
} else if (useAutoBoxing
&& scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) { // unboxing - only widening match is allowed
tagAsUnnecessaryCast(scope, castType);
return true;
}
return false;
} else if (useAutoBoxing
&& expressionType.isBaseType()
&& scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) { // boxing - only widening match is allowed
tagAsUnnecessaryCast(scope, castType);
return true;
}
if (castType.isIntersectionType18()) {
ReferenceBinding [] intersectingTypes = castType.getIntersectingTypes();
for (ReferenceBinding intersectingType : intersectingTypes) {
if (!checkCastTypesCompatibility(scope, intersectingType, expressionType, expression, useAutoBoxing))
return false;
}
return true;
}
switch(expressionType.kind()) {
case Binding.BASE_TYPE :
//-----------cast to something which is NOT a base type--------------------------
if (expressionType == TypeBinding.NULL) {
tagAsUnnecessaryCast(scope, castType);
return true; //null is compatible with every thing
}
return false;
case Binding.ARRAY_TYPE :
if (TypeBinding.equalsEquals(castType, expressionType)) {
tagAsUnnecessaryCast(scope, castType);
return true; // identity conversion
}
switch (castType.kind()) {
case Binding.ARRAY_TYPE :
// ( ARRAY ) ARRAY
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;
}
// recurse on array type elements
return checkCastTypesCompatibility(scope, castElementType, exprElementType, expression, useAutoBoxing);
case Binding.TYPE_PARAMETER :
// ( TYPE_PARAMETER ) ARRAY
TypeBinding match = expressionType.findSuperTypeOriginatingFrom(castType);
if (match == null) {
checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true);
}
for (TypeBinding bound : ((TypeVariableBinding) castType).allUpperBounds()) {
if (!checkCastTypesCompatibility(scope, bound, expressionType, expression, useAutoBoxing))
return false;
}
return true;
default:
// ( CLASS/INTERFACE ) ARRAY
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) {
// recursively on the type variable upper bounds
if (castType instanceof TypeVariableBinding) {
// prefer iterating over required types, not provides
for (TypeBinding bound : ((TypeVariableBinding)castType).allUpperBounds()) {
if (!checkCastTypesCompatibility(scope, bound, expressionType, expression, useAutoBoxing))
return false;
}
} else {
for (TypeBinding bound : ((TypeVariableBinding)expressionType).allUpperBounds()) {
if (!checkCastTypesCompatibility(scope, castType, bound, expression, useAutoBoxing))
return false;
}
}
}
// if no incompatibility found:
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();
// recursively on the type variable upper bound
return checkCastTypesCompatibility(scope, castType, bound, expression, useAutoBoxing);
case Binding.INTERSECTION_TYPE18:
ReferenceBinding [] intersectingTypes = expressionType.getIntersectingTypes();
for (ReferenceBinding intersectingType : intersectingTypes) {
if (checkCastTypesCompatibility(scope, castType, intersectingType, expression, useAutoBoxing))
return true;
}
return false;
default:
if (expressionType.isInterface()) {
switch (castType.kind()) {
case Binding.ARRAY_TYPE :
// ( ARRAY ) INTERFACE
switch (expressionType.id) {
case T_JavaLangCloneable :
case T_JavaIoSerializable :
tagAsNeedCheckCast();
return true;
default :
return false;
}
case Binding.TYPE_PARAMETER :
// ( INTERFACE ) TYPE_PARAMETER
match = expressionType.findSuperTypeOriginatingFrom(castType);
if (match == null) {
checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true);
}
// recursively on the type variable upper bounds
for (TypeBinding upperBound : ((TypeVariableBinding)castType).allUpperBounds()) {
if (!checkCastTypesCompatibility(scope, upperBound, expressionType, expression, useAutoBoxing))
return false;
}
return true;
default :
if (castType.isInterface()) {
// ( INTERFACE ) INTERFACE
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 (((ReferenceBinding) castType).isDisjointFrom(interfaceType))
return false;
if (use15specifics) {
checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true);
// ensure there is no collision between both interfaces: i.e. I1 extends List, I2 extends List