/**
   * 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);
    }
  }
  /**
   * 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);
    }
  }
  /**
   * 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);
      }
    }
  }
  /*
   * Creates the super class handle of the given type.
   * Returns null if the type has no super class.
   * Adds the simple name to the hierarchy missing types if the class is not found and returns null.
   */
  private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) {
    ReferenceBinding superBinding = typeBinding.superclass();

    if (superBinding != null) {
      superBinding = (ReferenceBinding) superBinding.erasure();
      if (typeBinding.isHierarchyInconsistent()) {
        if (superBinding.problemId() == ProblemReasons.NotFound) {
          this.hasMissingSuperClass = true;
          this.builder.hierarchy.missingTypes.add(
              new String(superBinding.sourceName)); // note: this could be Map$Entry
          return null;
        } else if ((superBinding.id == TypeIds.T_JavaLangObject)) {
          char[] superclassName;
          char separator;
          if (type instanceof IBinaryType) {
            superclassName = ((IBinaryType) type).getSuperclassName();
            separator = '/';
          } else if (type instanceof ISourceType) {
            superclassName = ((ISourceType) type).getSuperclassName();
            separator = '.';
          } else if (type instanceof HierarchyType) {
            superclassName = ((HierarchyType) type).superclassName;
            separator = '.';
          } else {
            return null;
          }

          if (superclassName
              != null) { // check whether subclass of Object due to broken hierarchy (as opposed to
                         // explicitly extending it)
            int lastSeparator = CharOperation.lastIndexOf(separator, superclassName);
            char[] simpleName =
                lastSeparator == -1
                    ? superclassName
                    : CharOperation.subarray(
                        superclassName, lastSeparator + 1, superclassName.length);
            if (!CharOperation.equals(simpleName, TypeConstants.OBJECT)) {
              this.hasMissingSuperClass = true;
              this.builder.hierarchy.missingTypes.add(new String(simpleName));
              return null;
            }
          }
        }
      }
      for (int t = this.typeIndex; t >= 0; t--) {
        if (TypeBinding.equalsEquals(this.typeBindings[t], superBinding)) {
          return this.builder.getHandle(this.typeModels[t], superBinding);
        }
      }
    }
    return null;
  }
 /**
  * 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;
 }
 private boolean subTypeOfType(ReferenceBinding subType, ReferenceBinding typeBinding) {
   if (typeBinding == null || subType == null) return false;
   if (TypeBinding.equalsEquals(subType, typeBinding)) return true;
   ReferenceBinding superclass = subType.superclass();
   if (superclass != null) superclass = (ReferenceBinding) superclass.erasure();
   //	if (superclass != null && superclass.id == TypeIds.T_JavaLangObject &&
   // subType.isHierarchyInconsistent()) return false;
   if (subTypeOfType(superclass, typeBinding)) return true;
   ReferenceBinding[] superInterfaces = subType.superInterfaces();
   if (superInterfaces != null) {
     for (int i = 0, length = superInterfaces.length; i < length; i++) {
       ReferenceBinding superInterface = (ReferenceBinding) superInterfaces[i].erasure();
       if (subTypeOfType(superInterface, typeBinding)) return true;
     }
   }
   return false;
 }
 /**
  * Cast expression code generation
  *
  * @param currentScope org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope
  * @param codeStream org.aspectj.org.eclipse.jdt.internal.compiler.codegen.CodeStream
  * @param valueRequired boolean
  */
 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);
       }
       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);
   }
   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 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();

        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;
  }
 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;
 }
  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() {
          public TypeBinding[] genericTypeArguments() {
            return null;
          }

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

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

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

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

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

          public int sourceStart() {
            return 0;
          }

          public int sourceEnd() {
            return 0;
          }

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

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

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

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

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

          public boolean checkingPotentialCompatibility() {
            return false;
          }

          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])*/ ) {
          scope.problemReporter().unnecessaryCast((CastExpression) arguments[i]);
        }
      }
    }
  }
  /**
   * Returns the constant intValue or ordinal for enum constants. If constant is NotAConstant, then
   * answers Float.MIN_VALUE
   *
   * @see
   *     org.aspectj.org.eclipse.jdt.internal.compiler.ast.Statement#resolveCase(org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope,
   *     org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding,
   *     org.aspectj.org.eclipse.jdt.internal.compiler.ast.SwitchStatement)
   */
  public Constant resolveCase(
      BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
    // switchExpressionType maybe null in error case
    scope.enclosingCase = this; // record entering in a switch case block

    if (this.constantExpression == null) {
      // remember the default case into the associated switch statement
      if (switchStatement.defaultCase != null) scope.problemReporter().duplicateDefaultCase(this);

      // on error the last default will be the selected one ...
      switchStatement.defaultCase = this;
      return Constant.NotAConstant;
    }
    // add into the collection of cases of the associated switch statement
    switchStatement.cases[switchStatement.caseCount++] = this;
    // tag constant name with enum type for privileged access to its members
    if (switchExpressionType != null
        && switchExpressionType.isEnum()
        && (this.constantExpression instanceof SingleNameReference)) {
      ((SingleNameReference) this.constantExpression)
          .setActualReceiverType((ReferenceBinding) switchExpressionType);
    }
    TypeBinding caseType = this.constantExpression.resolveType(scope);
    if (caseType == null || switchExpressionType == null) return Constant.NotAConstant;
    if (this.constantExpression.isConstantValueOfTypeAssignableToType(
            caseType, switchExpressionType)
        || caseType.isCompatibleWith(switchExpressionType)) {
      if (caseType.isEnum()) {
        if (((this.constantExpression.bits & ASTNode.ParenthesizedMASK)
                >> ASTNode.ParenthesizedSHIFT)
            != 0) {
          scope
              .problemReporter()
              .enumConstantsCannotBeSurroundedByParenthesis(this.constantExpression);
        }

        if (this.constantExpression instanceof NameReference
            && (this.constantExpression.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) {
          NameReference reference = (NameReference) this.constantExpression;
          FieldBinding field = reference.fieldBinding();
          if ((field.modifiers & ClassFileConstants.AccEnum) == 0) {
            scope.problemReporter().enumSwitchCannotTargetField(reference, field);
          } else if (reference instanceof QualifiedNameReference) {
            scope.problemReporter().cannotUseQualifiedEnumConstantInCaseLabel(reference, field);
          }
          return IntConstant.fromValue(
              field.original().id
                  + 1); // (ordinal value + 1) zero should not be returned see bug 141810
        }
      } else {
        return this.constantExpression.constant;
      }
    } else if (isBoxingCompatible(caseType, switchExpressionType, this.constantExpression, scope)) {
      // constantExpression.computeConversion(scope, caseType, switchExpressionType); - do not
      // report boxing/unboxing conversion
      return this.constantExpression.constant;
    }
    scope
        .problemReporter()
        .typeMismatchError(
            caseType, switchExpressionType, this.constantExpression, switchStatement.expression);
    return Constant.NotAConstant;
  }
  /*
   * For all type bindings that have hierarchy problems, artificially fix their superclass/superInterfaces so that the connection
   * can be made.
   */
  private void fixSupertypeBindings() {
    for (int current = this.typeIndex; current >= 0; current--) {
      ReferenceBinding typeBinding = this.typeBindings[current];
      if ((typeBinding.tagBits & TagBits.HierarchyHasProblems) == 0) continue;

      if (typeBinding instanceof SourceTypeBinding) {
        if (typeBinding instanceof LocalTypeBinding) {
          LocalTypeBinding localTypeBinding = (LocalTypeBinding) typeBinding;
          QualifiedAllocationExpression allocationExpression =
              localTypeBinding.scope.referenceContext.allocation;
          TypeReference type;
          if (allocationExpression != null
              && (type = allocationExpression.type) != null
              && type.resolvedType != null) {
            localTypeBinding.setSuperClass((ReferenceBinding) type.resolvedType);
            continue;
          }
        }
        ClassScope scope = ((SourceTypeBinding) typeBinding).scope;
        if (scope != null) {
          TypeDeclaration typeDeclaration = scope.referenceContext;
          TypeReference superclassRef = typeDeclaration == null ? null : typeDeclaration.superclass;
          TypeBinding superclass = superclassRef == null ? null : superclassRef.resolvedType;
          if (superclass != null) {
            superclass = superclass.closestMatch();
          }
          if (superclass instanceof ReferenceBinding) {
            // ensure we are not creating a cycle (see
            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=215681 )
            if (!(subTypeOfType((ReferenceBinding) superclass, typeBinding))) {
              ((SourceTypeBinding) typeBinding).setSuperClass((ReferenceBinding) superclass);
            }
          }

          TypeReference[] superInterfaces =
              typeDeclaration == null ? null : typeDeclaration.superInterfaces;
          int length;
          ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();
          if (superInterfaces != null
              && (length = superInterfaces.length)
                  > (interfaceBindings == null
                      ? 0
                      : interfaceBindings
                          .length)) { // check for interfaceBindings being null (see
                                      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=139689)
            interfaceBindings = new ReferenceBinding[length];
            int index = 0;
            for (int i = 0; i < length; i++) {
              TypeBinding superInterface = superInterfaces[i].resolvedType;
              if (superInterface != null) {
                superInterface = superInterface.closestMatch();
              }
              if (superInterface instanceof ReferenceBinding) {
                // ensure we are not creating a cycle (see
                // https://bugs.eclipse.org/bugs/show_bug.cgi?id=215681 )
                if (!(subTypeOfType((ReferenceBinding) superInterface, typeBinding))) {
                  interfaceBindings[index++] = (ReferenceBinding) superInterface;
                }
              }
            }
            if (index < length)
              System.arraycopy(
                  interfaceBindings, 0, interfaceBindings = new ReferenceBinding[index], 0, index);
            ((SourceTypeBinding) typeBinding).setSuperInterfaces(interfaceBindings);
          }
        }
      } else if (typeBinding instanceof BinaryTypeBinding) {
        try {
          typeBinding.superclass();
        } catch (AbortCompilation e) {
          // allow subsequent call to superclass() to succeed so that we don't have to catch
          // AbortCompilation everywhere
          ((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperclass;
          this.builder.hierarchy.missingTypes.add(
              new String(typeBinding.superclass().sourceName()));
          this.hasMissingSuperClass = true;
        }
        try {
          typeBinding.superInterfaces();
        } catch (AbortCompilation e) {
          // allow subsequent call to superInterfaces() to succeed so that we don't have to catch
          // AbortCompilation everywhere
          ((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperinterfaces;
        }
      }
    }
  }
  /*
   * Returns the handles of the super interfaces of the given type.
   * Adds the simple name to the hierarchy missing types if an interface is not found (but don't put null in the returned array)
   */
  private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBinding) {
    char[][] superInterfaceNames;
    char separator;
    if (type instanceof IBinaryType) {
      superInterfaceNames = ((IBinaryType) type).getInterfaceNames();
      separator = '/';
    } else if (type instanceof ISourceType) {
      ISourceType sourceType = (ISourceType) type;
      if (sourceType.isAnonymous()) { // if anonymous type
        if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) {
          superInterfaceNames = new char[][] {sourceType.getSuperclassName()};
        } else {
          superInterfaceNames = sourceType.getInterfaceNames();
        }
      } else {
        if (TypeDeclaration.kind(sourceType.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL)
          superInterfaceNames =
              new char[][] {TypeConstants.CharArray_JAVA_LANG_ANNOTATION_ANNOTATION};
        else superInterfaceNames = sourceType.getInterfaceNames();
      }
      separator = '.';
    } else if (type instanceof HierarchyType) {
      HierarchyType hierarchyType = (HierarchyType) type;
      if (hierarchyType.isAnonymous()) { // if anonymous type
        if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) {
          superInterfaceNames = new char[][] {hierarchyType.superclassName};
        } else {
          superInterfaceNames = hierarchyType.superInterfaceNames;
        }
      } else {
        superInterfaceNames = hierarchyType.superInterfaceNames;
      }
      separator = '.';
    } else {
      return null;
    }

    ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();
    int bindingIndex = 0;
    int bindingLength = interfaceBindings == null ? 0 : interfaceBindings.length;
    int length = superInterfaceNames == null ? 0 : superInterfaceNames.length;
    IType[] superinterfaces = new IType[length];
    int index = 0;
    next:
    for (int i = 0; i < length; i++) {
      char[] superInterfaceName = superInterfaceNames[i];
      int end = superInterfaceName.length;

      // find the end of simple name
      int genericStart = CharOperation.indexOf(Signature.C_GENERIC_START, superInterfaceName);
      if (genericStart != -1) end = genericStart;

      // find the start of simple name
      int lastSeparator = CharOperation.lastIndexOf(separator, superInterfaceName, 0, end);
      int start = lastSeparator + 1;

      // case of binary inner type -> take the last part
      int lastDollar = CharOperation.lastIndexOf('$', superInterfaceName, start);
      if (lastDollar != -1) start = lastDollar + 1;

      char[] simpleName = CharOperation.subarray(superInterfaceName, start, end);

      if (bindingIndex < bindingLength) {
        ReferenceBinding interfaceBinding =
            (ReferenceBinding) interfaceBindings[bindingIndex].erasure();

        // ensure that the binding corresponds to the interface defined by the user
        if (CharOperation.equals(simpleName, interfaceBinding.sourceName)) {
          bindingIndex++;
          for (int t = this.typeIndex; t >= 0; t--) {
            if (TypeBinding.equalsEquals(this.typeBindings[t], interfaceBinding)) {
              IType handle = this.builder.getHandle(this.typeModels[t], interfaceBinding);
              if (handle != null) {
                superinterfaces[index++] = handle;
                continue next;
              }
            }
          }
        }
      }
      this.builder.hierarchy.missingTypes.add(new String(simpleName));
    }
    if (index != length)
      System.arraycopy(superinterfaces, 0, superinterfaces = new IType[index], 0, index);
    return superinterfaces;
  }