org.eclipse.jdt.internal.compiler.ast.CastExpression.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jdt.internal.compiler.ast.CastExpression.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2017 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
 *     Nick Teryaev - fix for bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=40752)
 *     Stephan Herrmann - Contributions for
 *                        bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE
 *                        bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null"
 *                        bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation.
 *                        bug 383368 - [compiler][null] syntactic null analysis for field references
 *                        bug 401017 - [compiler][null] casted reference to @Nullable field lacks a warning
 *                        bug 400761 - [compiler][null] null may be return as boolean without a diagnostic
 *                        Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
 *                        Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking
 *                        Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
 *                        Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec)
 *                        Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280)
 *                        Bug 430150 - [1.8][null] stricter checking against type variables
 *                        Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
 *                        Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null
 *        Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
 *                          Bug 415541 - [1.8][compiler] Type annotations in the body of static initializer get dropped
 *******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;

import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.CASTING_CONTEXT;

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.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.impl.IrritantSet;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18;
import org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.PolymorphicMethodBinding;
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.problem.ProblemSeverities;

public class CastExpression extends Expression {

    public Expression expression;
    public TypeReference type;
    public TypeBinding expectedType; // when assignment conversion to a given expected type: String s = (String) t;
    public TypeBinding instanceofType; // set by InstanceofExpression to ensure we don't flag a necessary cast unnecessary

    //expression.implicitConversion holds the cast for baseType casting
    public CastExpression(Expression expression, TypeReference type) {
        this.expression = expression;
        this.type = type;
        type.bits |= ASTNode.IgnoreRawTypeCheck; // no need to worry about raw type usage
    }

    @Override
    public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
        FlowInfo result = this.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
        this.expression.checkNPEbyUnboxing(currentScope, flowContext, flowInfo);
        // account for pot. CCE:
        flowContext.recordAbruptExit();
        return result;
    }

    /**
     * Complain if assigned expression is cast, but not actually used as such, e.g. Object o = (List) object;
     */
    public static void checkNeedForAssignedCast(BlockScope scope, TypeBinding expectedType, CastExpression rhs) {
        CompilerOptions compilerOptions = scope.compilerOptions();
        if (compilerOptions.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore)
            return;

        TypeBinding castedExpressionType = rhs.expression.resolvedType;
        //   int i = (byte) n; // cast still had side effect
        // double d = (float) n; // cast to float is unnecessary
        if (castedExpressionType == null || rhs.resolvedType.isBaseType())
            return;
        //if (castedExpressionType.id == T_null) return; // tolerate null expression cast
        if (castedExpressionType.isCompatibleWith(expectedType, scope)) {
            if (scope.environment().usesNullTypeAnnotations()) {
                // are null annotations compatible, too?
                if (NullAnnotationMatching.analyse(expectedType, castedExpressionType, -1).isAnyMismatch())
                    return; // already reported unchecked cast (nullness), say no more.
            }
            scope.problemReporter().unnecessaryCast(rhs);
        }
    }

    /**
     * Complain if cast expression is cast, but not actually needed, int i = (int)(Integer) 12;
     * Note that this (int) cast is however needed:   Integer i = 0;  char c = (char)((int) i);
     */
    public static void checkNeedForCastCast(BlockScope scope, CastExpression enclosingCast) {
        if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore)
            return;

        CastExpression nestedCast = (CastExpression) enclosingCast.expression;
        if ((nestedCast.bits & ASTNode.UnnecessaryCast) == 0)
            return;
        // check if could cast directly to enclosing cast type, without intermediate type cast
        CastExpression alternateCast = new CastExpression(null, enclosingCast.type);
        alternateCast.resolvedType = enclosingCast.resolvedType;
        if (!alternateCast.checkCastTypesCompatibility(scope, enclosingCast.resolvedType,
                nestedCast.expression.resolvedType, null /* no expr to avoid side-effects*/))
            return;
        scope.problemReporter().unnecessaryCast(nestedCast);
    }

    /**
     * Casting an enclosing instance will considered as useful if removing it would actually bind to a different type
     */
    public static void checkNeedForEnclosingInstanceCast(BlockScope scope, Expression enclosingInstance,
            TypeBinding enclosingInstanceType, TypeBinding memberType) {
        if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore)
            return;

        TypeBinding castedExpressionType = ((CastExpression) enclosingInstance).expression.resolvedType;
        if (castedExpressionType == null)
            return; // cannot do better
        // obvious identity cast
        if (TypeBinding.equalsEquals(castedExpressionType, enclosingInstanceType)) {
            scope.problemReporter().unnecessaryCast((CastExpression) enclosingInstance);
        } else if (castedExpressionType == TypeBinding.NULL) {
            return; // tolerate null enclosing instance cast
        } else {
            TypeBinding alternateEnclosingInstanceType = castedExpressionType;
            if (castedExpressionType.isBaseType() || castedExpressionType.isArrayType())
                return; // error case
            if (TypeBinding.equalsEquals(memberType, scope.getMemberType(memberType.sourceName(),
                    (ReferenceBinding) alternateEnclosingInstanceType))) {
                scope.problemReporter().unnecessaryCast((CastExpression) enclosingInstance);
            }
        }
    }

    /**
     * Only complain for identity cast, since other type of casts may be useful: e.g.  ~((~(long) 0) << 32)  is different from: ~((~0) << 32)
     */
    public static void checkNeedForArgumentCast(BlockScope scope, int operator, int operatorSignature,
            Expression expression, int expressionTypeId) {
        if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore)
            return;

        // check need for left operand cast
        if ((expression.bits & ASTNode.UnnecessaryCast) == 0 && expression.resolvedType.isBaseType()) {
            // narrowing conversion on base type may change value, thus necessary
            return;
        } else {
            TypeBinding alternateLeftType = ((CastExpression) expression).expression.resolvedType;
            if (alternateLeftType == null)
                return; // cannot do better
            if (alternateLeftType.id == expressionTypeId) { // obvious identity cast
                scope.problemReporter().unnecessaryCast((CastExpression) expression);
                return;
            }
        }
    }

    /**
     * Cast expressions will considered as useful if removing them all would actually bind to a different method
     * (no fine grain analysis on per casted argument basis, simply separate widening cast from narrowing ones)
     */
    public static void checkNeedForArgumentCasts(BlockScope scope, Expression receiver, TypeBinding receiverType,
            MethodBinding binding, Expression[] arguments, TypeBinding[] argumentTypes,
            final InvocationSite invocationSite) {
        if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore)
            return;

        int length = argumentTypes.length;

        // iterate over arguments, and retrieve original argument types (before cast)
        TypeBinding[] rawArgumentTypes = argumentTypes;
        for (int i = 0; i < length; i++) {
            Expression argument = arguments[i];
            if (argument instanceof CastExpression) {
                // narrowing conversion on base type may change value, thus necessary
                if ((argument.bits & ASTNode.UnnecessaryCast) == 0 && argument.resolvedType.isBaseType()) {
                    continue;
                }
                TypeBinding castedExpressionType = ((CastExpression) argument).expression.resolvedType;
                if (castedExpressionType == null)
                    return; // cannot do better
                // obvious identity cast
                if (TypeBinding.equalsEquals(castedExpressionType, argumentTypes[i])) {
                    scope.problemReporter().unnecessaryCast((CastExpression) argument);
                } else if (castedExpressionType == TypeBinding.NULL) {
                    continue; // tolerate null argument cast
                } else if ((argument.implicitConversion & TypeIds.BOXING) != 0) {
                    continue; // boxing has a side effect: (int) char   is not boxed as simple char
                } else {
                    if (rawArgumentTypes == argumentTypes) {
                        System.arraycopy(rawArgumentTypes, 0, rawArgumentTypes = new TypeBinding[length], 0,
                                length);
                    }
                    // retain original argument type
                    rawArgumentTypes[i] = castedExpressionType;
                }
            }
        }
        // perform alternate lookup with original types
        if (rawArgumentTypes != argumentTypes) {
            checkAlternateBinding(scope, receiver, receiverType, binding, arguments, argumentTypes,
                    rawArgumentTypes, invocationSite);
        }
    }

    /**
     * Check binary operator casted arguments
     */
    public static void checkNeedForArgumentCasts(BlockScope scope, int operator, int operatorSignature,
            Expression left, int leftTypeId, boolean leftIsCast, Expression right, int rightTypeId,
            boolean rightIsCast) {
        if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore)
            return;

        // check need for left operand cast
        int alternateLeftTypeId = leftTypeId;
        if (leftIsCast) {
            if ((left.bits & ASTNode.UnnecessaryCast) == 0 && left.resolvedType.isBaseType()) {
                // narrowing conversion on base type may change value, thus necessary
                leftIsCast = false;
            } else {
                TypeBinding alternateLeftType = ((CastExpression) left).expression.resolvedType;
                if (alternateLeftType == null)
                    return; // cannot do better
                if ((alternateLeftTypeId = alternateLeftType.id) == leftTypeId
                        || scope.environment().computeBoxingType(alternateLeftType).id == leftTypeId) { // obvious identity cast
                    scope.problemReporter().unnecessaryCast((CastExpression) left);
                    leftIsCast = false;
                } else if (alternateLeftTypeId == TypeIds.T_null) {
                    alternateLeftTypeId = leftTypeId; // tolerate null argument cast
                    leftIsCast = false;
                }
            }
        }
        // check need for right operand cast
        int alternateRightTypeId = rightTypeId;
        if (rightIsCast) {
            if ((right.bits & ASTNode.UnnecessaryCast) == 0 && right.resolvedType.isBaseType()) {
                // narrowing conversion on base type may change value, thus necessary
                rightIsCast = false;
            } else {
                TypeBinding alternateRightType = ((CastExpression) right).expression.resolvedType;
                if (alternateRightType == null)
                    return; // cannot do better
                if ((alternateRightTypeId = alternateRightType.id) == rightTypeId
                        || scope.environment().computeBoxingType(alternateRightType).id == rightTypeId) { // obvious identity cast
                    scope.problemReporter().unnecessaryCast((CastExpression) right);
                    rightIsCast = false;
                } else if (alternateRightTypeId == TypeIds.T_null) {
                    alternateRightTypeId = rightTypeId; // tolerate null argument cast
                    rightIsCast = false;
                }
            }
        }
        if (leftIsCast || rightIsCast) {
            if (alternateLeftTypeId > 15 || alternateRightTypeId > 15) { // must convert String + Object || Object + String
                if (alternateLeftTypeId == TypeIds.T_JavaLangString) {
                    alternateRightTypeId = TypeIds.T_JavaLangObject;
                } else if (alternateRightTypeId == TypeIds.T_JavaLangString) {
                    alternateLeftTypeId = TypeIds.T_JavaLangObject;
                } else {
                    return; // invalid operator
                }
            }
            int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4)
                    + alternateRightTypeId];
            // (cast)  left   Op (cast)  right --> result
            //  1111   0000       1111   0000     1111
            //  <<16   <<12       <<8    <<4       <<0
            final int CompareMASK = (0xF << 16) + (0xF << 8) + 0xF; // mask hiding compile-time types
            if ((operatorSignature & CompareMASK) == (alternateOperatorSignature & CompareMASK)) { // same promotions and result
                if (leftIsCast)
                    scope.problemReporter().unnecessaryCast((CastExpression) left);
                if (rightIsCast)
                    scope.problemReporter().unnecessaryCast((CastExpression) right);
            }
        }
    }

    @Override
    public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) {
        if ((this.resolvedType.tagBits & TagBits.AnnotationNonNull) != 0) {
            return true;
        }
        checkNPEbyUnboxing(scope, flowContext, flowInfo);
        return this.expression.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck);
    }

    private static void checkAlternateBinding(BlockScope scope, Expression receiver, TypeBinding receiverType,
            MethodBinding binding, Expression[] arguments, TypeBinding[] originalArgumentTypes,
            TypeBinding[] alternateArgumentTypes, final InvocationSite invocationSite) {
        InvocationSite fakeInvocationSite = new InvocationSite() {
            @Override
            public TypeBinding[] genericTypeArguments() {
                return null;
            }

            @Override
            public boolean isSuperAccess() {
                return invocationSite.isSuperAccess();
            }

            @Override
            public boolean isTypeAccess() {
                return invocationSite.isTypeAccess();
            }

            @Override
            public void setActualReceiverType(ReferenceBinding actualReceiverType) {
                /* ignore */}

            @Override
            public void setDepth(int depth) {
                /* ignore */}

            @Override
            public void setFieldIndex(int depth) {
                /* ignore */}

            @Override
            public int sourceStart() {
                return 0;
            }

            @Override
            public int sourceEnd() {
                return 0;
            }

            @Override
            public TypeBinding invocationTargetType() {
                return invocationSite.invocationTargetType();
            }

            @Override
            public boolean receiverIsImplicitThis() {
                return invocationSite.receiverIsImplicitThis();
            }

            @Override
            public InferenceContext18 freshInferenceContext(Scope someScope) {
                return invocationSite.freshInferenceContext(someScope);
            }

            @Override
            public ExpressionContext getExpressionContext() {
                return invocationSite.getExpressionContext();
            }

            @Override
            public boolean isQualifiedSuper() {
                return invocationSite.isQualifiedSuper();
            }

            @Override
            public boolean checkingPotentialCompatibility() {
                return false;
            }

            @Override
            public void acceptPotentiallyCompatibleMethods(MethodBinding[] methods) {
                /* ignore */}
        };
        MethodBinding bindingIfNoCast;
        if (binding.isConstructor()) {
            bindingIfNoCast = scope.getConstructor((ReferenceBinding) receiverType, alternateArgumentTypes,
                    fakeInvocationSite);
        } else {
            bindingIfNoCast = receiver.isImplicitThis()
                    ? scope.getImplicitMethod(binding.selector, alternateArgumentTypes, fakeInvocationSite)
                    : scope.getMethod(receiverType, binding.selector, alternateArgumentTypes, fakeInvocationSite);
        }
        if (bindingIfNoCast == binding) {
            int argumentLength = originalArgumentTypes.length;
            if (binding.isVarargs()) {
                int paramLength = binding.parameters.length;
                if (paramLength == argumentLength) {
                    int varargsIndex = paramLength - 1;
                    ArrayBinding varargsType = (ArrayBinding) binding.parameters[varargsIndex];
                    TypeBinding lastArgType = alternateArgumentTypes[varargsIndex];
                    // originalType may be compatible already, but cast mandated
                    // to clarify between varargs/non-varargs call
                    if (varargsType.dimensions != lastArgType.dimensions()) {
                        return;
                    }
                    if (lastArgType.isCompatibleWith(varargsType.elementsType())
                            && lastArgType.isCompatibleWith(varargsType)) {
                        return;
                    }
                }
            }
            for (int i = 0; i < argumentLength; i++) {
                if (TypeBinding.notEquals(originalArgumentTypes[i], alternateArgumentTypes[i])
                /*&& !originalArgumentTypes[i].needsUncheckedConversion(alternateArgumentTypes[i])*/) {
                    if (!preventsUnlikelyTypeWarning(originalArgumentTypes[i], alternateArgumentTypes[i],
                            receiverType, binding, scope))
                        scope.problemReporter().unnecessaryCast((CastExpression) arguments[i]);
                }
            }
        }
    }

    private static boolean preventsUnlikelyTypeWarning(TypeBinding castedType, TypeBinding uncastedType,
            TypeBinding receiverType, MethodBinding binding, BlockScope scope) {
        if (!scope.compilerOptions().isAnyEnabled(IrritantSet.UNLIKELY_ARGUMENT_TYPE))
            return false;
        if (binding.isStatic() || binding.parameters.length != 1)
            return false;
        // would using the uncastedType be considered as dangerous?
        UnlikelyArgumentCheck argumentChecks = UnlikelyArgumentCheck.determineCheckForNonStaticSingleArgumentMethod(
                uncastedType, scope, binding.selector, receiverType, binding.parameters);
        if (argumentChecks != null && argumentChecks.isDangerous(scope)) {
            // does the cast help?
            argumentChecks = UnlikelyArgumentCheck.determineCheckForNonStaticSingleArgumentMethod(castedType, scope,
                    binding.selector, receiverType, binding.parameters);
            if (argumentChecks == null || !argumentChecks.isDangerous(scope))
                return true;
        }
        return false;
    }

    @Override
    public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match,
            boolean isNarrowing) {
        if (TypeBinding.equalsEquals(match, castType)) {
            if (!isNarrowing && TypeBinding.equalsEquals(match, this.resolvedType.leafComponentType()) // do not tag as unnecessary when recursing through upper bounds
                    && !(expressionType.isParameterizedType() && expressionType.isProvablyDistinct(castType))) {
                tagAsUnnecessaryCast(scope, castType);
            }
            return true;
        }
        if (match != null) {
            if (isNarrowing ? match.isProvablyDistinct(expressionType) : castType.isProvablyDistinct(match)) {
                return false;
            }
        }
        switch (castType.kind()) {
        case Binding.PARAMETERIZED_TYPE:
            if (!castType.isReifiable()) {
                if (match == null) { // unrelated types
                    this.bits |= ASTNode.UnsafeCast;
                    return true;
                }
                switch (match.kind()) {
                case Binding.PARAMETERIZED_TYPE:
                    if (isNarrowing) {
                        // [JLS 5.5] T <: S
                        if (expressionType.isRawType() || !expressionType.isEquivalentTo(match)) {
                            this.bits |= ASTNode.UnsafeCast;
                            return true;
                        }
                        // [JLS 5.5] S has no subtype X != T, such that |X| == |T|
                        // if I2<T,U> extends I1<T>, then cast from I1<T> to I2<T,U> is unchecked
                        ParameterizedTypeBinding paramCastType = (ParameterizedTypeBinding) castType;
                        ParameterizedTypeBinding paramMatch = (ParameterizedTypeBinding) match;
                        // easy case if less parameters on match
                        TypeBinding[] castArguments = paramCastType.arguments;
                        int length = castArguments == null ? 0 : castArguments.length;
                        if (paramMatch.arguments == null || length > paramMatch.arguments.length) {
                            this.bits |= ASTNode.UnsafeCast;
                        } else if ((paramCastType.tagBits
                                & (TagBits.HasDirectWildcard | TagBits.HasTypeVariable)) != 0) {
                            // verify alternate cast type, substituting different type arguments
                            nextAlternateArgument: for (int i = 0; i < length; i++) {
                                switch (castArguments[i].kind()) {
                                case Binding.WILDCARD_TYPE:
                                case Binding.TYPE_PARAMETER:
                                    break; // check substituting with other
                                default:
                                    continue nextAlternateArgument; // no alternative possible
                                }
                                TypeBinding[] alternateArguments;
                                // need to clone for each iteration to avoid env paramtype cache interference
                                System.arraycopy(paramCastType.arguments, 0,
                                        alternateArguments = new TypeBinding[length], 0, length);
                                alternateArguments[i] = scope.getJavaLangObject();
                                LookupEnvironment environment = scope.environment();
                                ParameterizedTypeBinding alternateCastType = environment.createParameterizedType(
                                        (ReferenceBinding) castType.erasure(), alternateArguments,
                                        castType.enclosingType());
                                if (TypeBinding.equalsEquals(
                                        alternateCastType.findSuperTypeOriginatingFrom(expressionType), match)) {
                                    this.bits |= ASTNode.UnsafeCast;
                                    break;
                                }
                            }
                        }
                        return true;
                    } else {
                        // [JLS 5.5] T >: S
                        if (!match.isEquivalentTo(castType)) {
                            this.bits |= ASTNode.UnsafeCast;
                            return true;
                        }
                    }
                    break;
                case Binding.RAW_TYPE:
                    this.bits |= ASTNode.UnsafeCast; // upcast since castType is known to be bound paramType
                    return true;
                default:
                    if (isNarrowing) {
                        // match is not parameterized or raw, then any other subtype of match will erase  to |T|
                        this.bits |= ASTNode.UnsafeCast;
                        return true;
                    }
                    break;
                }
            }
            break;
        case Binding.ARRAY_TYPE:
            TypeBinding leafType = castType.leafComponentType();
            if (isNarrowing && (!leafType.isReifiable() || leafType.isTypeVariable())) {
                this.bits |= ASTNode.UnsafeCast;
                return true;
            }
            break;
        case Binding.TYPE_PARAMETER:
            this.bits |= ASTNode.UnsafeCast;
            return true;
        //      (disabled) https://bugs.eclipse.org/bugs/show_bug.cgi?id=240807         
        //      case Binding.TYPE :
        //         if (isNarrowing && match == null && expressionType.isParameterizedType()) {
        //            this.bits |= ASTNode.UnsafeCast;
        //            return true;
        //         }
        //         break;
        }
        if (!isNarrowing && TypeBinding.equalsEquals(match, this.resolvedType.leafComponentType())) { // do not tag as unnecessary when recursing through upper bounds
            tagAsUnnecessaryCast(scope, castType);
        }
        return true;
    }

    /**
     * Cast expression code generation
     *
     * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
     * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
     * @param valueRequired boolean
     */
    @Override
    public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
        int pc = codeStream.position;
        boolean annotatedCast = (this.type.bits & ASTNode.HasTypeAnnotations) != 0;
        boolean needRuntimeCheckcast = (this.bits & ASTNode.GenerateCheckcast) != 0;
        if (this.constant != Constant.NotAConstant) {
            if (valueRequired || needRuntimeCheckcast || annotatedCast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check
                codeStream.generateConstant(this.constant, this.implicitConversion);
                if (needRuntimeCheckcast || annotatedCast) {
                    codeStream.checkcast(this.type, this.resolvedType, pc);
                }
                if (!valueRequired) {
                    // the resolveType cannot be double or long
                    codeStream.pop();
                }
            }
            codeStream.recordPositionsFrom(pc, this.sourceStart);
            return;
        }
        this.expression.generateCode(currentScope, codeStream,
                annotatedCast || valueRequired || needRuntimeCheckcast);
        if (annotatedCast || (needRuntimeCheckcast && TypeBinding
                .notEquals(this.expression.postConversionType(currentScope), this.resolvedType.erasure()))) { // no need to issue a checkcast if already done as genericCast
            codeStream.checkcast(this.type, this.resolvedType, pc);
        }
        if (valueRequired) {
            codeStream.generateImplicitConversion(this.implicitConversion);
        } else if (annotatedCast || needRuntimeCheckcast) {
            switch (this.resolvedType.id) {
            case T_long:
            case T_double:
                codeStream.pop2();
                break;
            default:
                codeStream.pop();
                break;
            }
        }
        codeStream.recordPositionsFrom(pc, this.sourceStart);
    }

    public Expression innermostCastedExpression() {
        Expression current = this.expression;
        while (current instanceof CastExpression) {
            current = ((CastExpression) current).expression;
        }
        return current;
    }

    /**
     * @see org.eclipse.jdt.internal.compiler.ast.Expression#localVariableBinding()
     */
    @Override
    public LocalVariableBinding localVariableBinding() {
        return this.expression.localVariableBinding();
    }

    @Override
    public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) {
        if ((this.implicitConversion & TypeIds.BOXING) != 0)
            return FlowInfo.NON_NULL;
        return this.expression.nullStatus(flowInfo, flowContext);
    }

    /**
     * @see org.eclipse.jdt.internal.compiler.ast.Expression#optimizedBooleanConstant()
     */
    @Override
    public Constant optimizedBooleanConstant() {
        switch (this.resolvedType.id) {
        case T_boolean:
        case T_JavaLangBoolean:
            return this.expression.optimizedBooleanConstant();
        }
        return Constant.NotAConstant;
    }

    @Override
    public StringBuffer printExpression(int indent, StringBuffer output) {
        int parenthesesCount = (this.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
        String suffix = ""; //$NON-NLS-1$
        for (int i = 0; i < parenthesesCount; i++) {
            output.append('(');
            suffix += ')';
        }
        output.append('(');
        this.type.print(0, output).append(") "); //$NON-NLS-1$
        return this.expression.printExpression(0, output).append(suffix);
    }

    @Override
    public TypeBinding resolveType(BlockScope scope) {
        // compute a new constant if the cast is effective

        this.constant = Constant.NotAConstant;
        this.implicitConversion = TypeIds.T_undefined;

        boolean exprContainCast = false;

        TypeBinding castType = this.resolvedType = this.type.resolveType(scope);
        if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) {
            this.expression.setExpressionContext(CASTING_CONTEXT);
            if (this.expression instanceof FunctionalExpression) {
                this.expression.setExpectedType(this.resolvedType);
                this.bits |= ASTNode.DisableUnnecessaryCastCheck;
            }
        }
        if (this.expression instanceof CastExpression) {
            this.expression.bits |= ASTNode.DisableUnnecessaryCastCheck;
            exprContainCast = true;
        }
        TypeBinding expressionType = this.expression.resolveType(scope);
        if (this.expression instanceof MessageSend) {
            MessageSend messageSend = (MessageSend) this.expression;
            MethodBinding methodBinding = messageSend.binding;
            if (methodBinding != null && methodBinding.isPolymorphic()) {
                messageSend.binding = scope.environment()
                        .updatePolymorphicMethodReturnType((PolymorphicMethodBinding) methodBinding, castType);
                if (TypeBinding.notEquals(expressionType, castType)) {
                    expressionType = castType;
                    this.bits |= ASTNode.DisableUnnecessaryCastCheck;
                }
            }
        }
        if (castType != null) {
            if (expressionType != null) {

                boolean nullAnnotationMismatch = scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled
                        && NullAnnotationMatching.analyse(castType, expressionType, -1).isAnyMismatch();

                if (this.instanceofType != null && expressionType.isParameterizedType()
                        && expressionType.isProvablyDistinct(this.instanceofType)) {
                    this.bits |= ASTNode.DisableUnnecessaryCastCheck;
                }
                boolean isLegal = checkCastTypesCompatibility(scope, castType, expressionType, this.expression);
                if (isLegal) {
                    this.expression.computeConversion(scope, castType, expressionType);
                    if ((this.bits & ASTNode.UnsafeCast) != 0) { // unsafe cast
                        if (scope.compilerOptions().reportUnavoidableGenericTypeProblems
                                || !(expressionType.isRawType()
                                        && this.expression.forcedToBeRaw(scope.referenceContext()))) {
                            scope.problemReporter().unsafeCast(this, scope);
                        }
                    } else if (nullAnnotationMismatch) {
                        // report null annotation issue at medium priority
                        scope.problemReporter().unsafeNullnessCast(this, scope);
                    } else {
                        if (castType.isRawType() && scope.compilerOptions()
                                .getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore) {
                            scope.problemReporter().rawTypeReference(this.type, castType);
                        }
                        if ((this.bits & (ASTNode.UnnecessaryCast
                                | ASTNode.DisableUnnecessaryCastCheck)) == ASTNode.UnnecessaryCast) { // unnecessary cast
                            if (!isIndirectlyUsed()) // used for generic type inference or boxing ?
                                scope.problemReporter().unnecessaryCast(this);
                        }
                    }
                } else { // illegal cast
                    if ((castType.tagBits & TagBits.HasMissingType) == 0) { // no complaint if secondary error
                        scope.problemReporter().typeCastError(this, castType, expressionType);
                    }
                    this.bits |= ASTNode.DisableUnnecessaryCastCheck; // disable further secondary diagnosis
                }
            }
            this.resolvedType = castType.capture(scope, this.type.sourceStart, this.type.sourceEnd); // make it unique, a cast expression shares source end with the expression.
            if (exprContainCast) {
                checkNeedForCastCast(scope, this);
            }
        }
        return this.resolvedType;
    }

    /**
     * @see org.eclipse.jdt.internal.compiler.ast.Expression#setExpectedType(org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
     */
    @Override
    public void setExpectedType(TypeBinding expectedType) {
        this.expectedType = expectedType;
    }

    /**
     * Determines whether apparent unnecessary cast wasn't actually used to
     * perform return type inference of generic method invocation or boxing.
     */
    private boolean isIndirectlyUsed() {
        if (this.expression instanceof MessageSend) {
            MethodBinding method = ((MessageSend) this.expression).binding;
            if (method instanceof ParameterizedGenericMethodBinding
                    && ((ParameterizedGenericMethodBinding) method).inferredReturnType) {
                if (this.expectedType == null)
                    return true;
                if (TypeBinding.notEquals(this.resolvedType, this.expectedType))
                    return true;
            }
        }
        if (this.expectedType != null && this.resolvedType.isBaseType()
                && !this.resolvedType.isCompatibleWith(this.expectedType)) {
            // boxing: Short s = (short) _byte
            return true;
        }
        return false;
    }

    /**
     * @see org.eclipse.jdt.internal.compiler.ast.Expression#tagAsNeedCheckCast()
     */
    @Override
    public void tagAsNeedCheckCast() {
        this.bits |= ASTNode.GenerateCheckcast;
    }

    /**
     * @see org.eclipse.jdt.internal.compiler.ast.Expression#tagAsUnnecessaryCast(Scope, TypeBinding)
     */
    @Override
    public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) {
        this.bits |= ASTNode.UnnecessaryCast;
    }

    public void setInstanceofType(TypeBinding instanceofTypeBinding) {
        this.instanceofType = instanceofTypeBinding;
    }

    @Override
    public void traverse(ASTVisitor visitor, BlockScope blockScope) {
        if (visitor.visit(this, blockScope)) {
            this.type.traverse(visitor, blockScope);
            this.expression.traverse(visitor, blockScope);
        }
        visitor.endVisit(this, blockScope);
    }
}