Exemplo n.º 1
0
  public static boolean checkInvocationArguments(
      BlockScope scope,
      Expression receiver,
      TypeBinding receiverType,
      MethodBinding method,
      Expression[] arguments,
      TypeBinding[] argumentTypes,
      boolean argsContainCast,
      InvocationSite invocationSite) {
    TypeBinding[] params = method.parameters;
    int paramLength = params.length;
    boolean isRawMemberInvocation =
        !method.isStatic()
            && !receiverType.isUnboundWildcard()
            && method.declaringClass.isRawType()
            && method.hasSubstitutedParameters();

    boolean uncheckedBoundCheck =
        (method.tagBits & TagBits.HasUncheckedTypeArgumentForBoundCheck) != 0;
    MethodBinding rawOriginalGenericMethod = null;
    if (!isRawMemberInvocation) {
      if (method instanceof ParameterizedGenericMethodBinding) {
        ParameterizedGenericMethodBinding paramMethod = (ParameterizedGenericMethodBinding) method;
        if (paramMethod.isRaw && method.hasSubstitutedParameters()) {
          rawOriginalGenericMethod = method.original();
        }
      }
    }
    int invocationStatus = INVOCATION_ARGUMENT_OK;
    if (arguments == null) {
      if (method.isVarargs()) {
        TypeBinding parameterType =
            ((ArrayBinding) params[paramLength - 1])
                .elementsType(); // no element was supplied for vararg parameter
        if (!parameterType.isReifiable()) {
          scope
              .problemReporter()
              .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite);
        }
      }
    } else {
      if (method.isVarargs()) {
        // 4 possibilities exist for a call to the vararg method foo(int i, long ... value) :
        // foo(1), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new long[] {1, 2})
        int lastIndex = paramLength - 1;
        for (int i = 0; i < lastIndex; i++) {
          TypeBinding originalRawParam =
              rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i];
          invocationStatus |=
              checkInvocationArgument(
                  scope, arguments[i], params[i], argumentTypes[i], originalRawParam);
        }
        int argLength = arguments.length;
        if (lastIndex < argLength) { // vararg argument was provided
          TypeBinding parameterType = params[lastIndex];
          TypeBinding originalRawParam = null;

          if (paramLength != argLength
              || parameterType.dimensions() != argumentTypes[lastIndex].dimensions()) {
            parameterType =
                ((ArrayBinding) parameterType)
                    .elementsType(); // single element was provided for vararg parameter
            if (!parameterType.isReifiable()) {
              scope
                  .problemReporter()
                  .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite);
            }
            originalRawParam =
                rawOriginalGenericMethod == null
                    ? null
                    : ((ArrayBinding) rawOriginalGenericMethod.parameters[lastIndex])
                        .elementsType();
          }
          for (int i = lastIndex; i < argLength; i++) {
            invocationStatus |=
                checkInvocationArgument(
                    scope, arguments[i], parameterType, argumentTypes[i], originalRawParam);
          }
        }
        if (paramLength == argLength) { // 70056
          int varargsIndex = paramLength - 1;
          ArrayBinding varargsType = (ArrayBinding) params[varargsIndex];
          TypeBinding lastArgType = argumentTypes[varargsIndex];
          int dimensions;
          if (lastArgType == TypeBinding.NULL) {
            if (!(varargsType.leafComponentType().isBaseType() && varargsType.dimensions() == 1))
              scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite);
          } else if (varargsType.dimensions <= (dimensions = lastArgType.dimensions())) {
            if (lastArgType.leafComponentType().isBaseType()) {
              dimensions--;
            }
            if (varargsType.dimensions < dimensions) {
              scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite);
            } else if (varargsType.dimensions == dimensions
                && lastArgType != varargsType
                && lastArgType.leafComponentType().erasure()
                    != varargsType.leafComponentType.erasure()
                && lastArgType.isCompatibleWith(varargsType.elementsType())
                && lastArgType.isCompatibleWith(varargsType)) {
              scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite);
            }
          }
        }
      } else {
        for (int i = 0; i < paramLength; i++) {
          TypeBinding originalRawParam =
              rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i];
          invocationStatus |=
              checkInvocationArgument(
                  scope, arguments[i], params[i], argumentTypes[i], originalRawParam);
        }
      }
      if (argsContainCast) {
        CastExpression.checkNeedForArgumentCasts(
            scope, receiver, receiverType, method, arguments, argumentTypes, invocationSite);
      }
    }
    if ((invocationStatus & INVOCATION_ARGUMENT_WILDCARD) != 0) {
      scope
          .problemReporter()
          .wildcardInvocation((ASTNode) invocationSite, receiverType, method, argumentTypes);
    } else if (!method.isStatic()
        && !receiverType.isUnboundWildcard()
        && method.declaringClass.isRawType()
        && method.hasSubstitutedParameters()) {
      scope.problemReporter().unsafeRawInvocation((ASTNode) invocationSite, method);
    } else if (rawOriginalGenericMethod != null
        || uncheckedBoundCheck
        || ((invocationStatus & INVOCATION_ARGUMENT_UNCHECKED) != 0
            && method instanceof ParameterizedGenericMethodBinding
        /*&& method.returnType != scope.environment().convertToRawType(method.returnType.erasure(), true)*/ )) {
      scope
          .problemReporter()
          .unsafeRawGenericMethodInvocation((ASTNode) invocationSite, method, argumentTypes);
      return true;
    }
    return false;
  }
  public TypeBinding resolveType(BlockScope scope) {

    boolean leftIsCast, rightIsCast;
    if ((leftIsCast = this.left instanceof CastExpression) == true)
      this.left.bits |= DisableUnnecessaryCastCheck; // will check later on
    TypeBinding originalLeftType = this.left.resolveType(scope);

    if ((rightIsCast = this.right instanceof CastExpression) == true)
      this.right.bits |= DisableUnnecessaryCastCheck; // will check later on
    TypeBinding originalRightType = this.right.resolveType(scope);

    // always return BooleanBinding
    if (originalLeftType == null || originalRightType == null) {
      this.constant = Constant.NotAConstant;
      return null;
    }

    // autoboxing support
    boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
    TypeBinding leftType = originalLeftType, rightType = originalRightType;
    if (use15specifics) {
      if (leftType != TypeBinding.NULL && leftType.isBaseType()) {
        if (!rightType.isBaseType()) {
          rightType = scope.environment().computeBoxingType(rightType);
        }
      } else {
        if (rightType != TypeBinding.NULL && rightType.isBaseType()) {
          leftType = scope.environment().computeBoxingType(leftType);
        }
      }
    }
    // both base type
    if (leftType.isBaseType() && rightType.isBaseType()) {
      int leftTypeID = leftType.id;
      int rightTypeID = rightType.id;

      // the code is an int
      // (cast)  left   == (cast)  right --> result
      //  0000   0000       0000   0000      0000
      //  <<16   <<12       <<8    <<4       <<0
      int operatorSignature = OperatorSignatures[EQUAL_EQUAL][(leftTypeID << 4) + rightTypeID];
      this.left.computeConversion(
          scope,
          TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F),
          originalLeftType);
      this.right.computeConversion(
          scope,
          TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F),
          originalRightType);
      this.bits |= operatorSignature & 0xF;
      if ((operatorSignature & 0x0000F) == T_undefined) {
        this.constant = Constant.NotAConstant;
        scope.problemReporter().invalidOperator(this, leftType, rightType);
        return null;
      }
      // check need for operand cast
      if (leftIsCast || rightIsCast) {
        CastExpression.checkNeedForArgumentCasts(
            scope,
            EQUAL_EQUAL,
            operatorSignature,
            this.left,
            leftType.id,
            leftIsCast,
            this.right,
            rightType.id,
            rightIsCast);
      }
      computeConstant(leftType, rightType);

      // check whether comparing identical expressions
      Binding leftDirect = Expression.getDirectBinding(this.left);
      if (leftDirect != null && leftDirect == Expression.getDirectBinding(this.right)) {
        if (leftTypeID != TypeIds.T_double
            && leftTypeID != TypeIds.T_float
            && (!(this.right
                instanceof Assignment))) // https://bugs.eclipse.org/bugs/show_bug.cgi?id=281776
        scope.problemReporter().comparingIdenticalExpressions(this);
      } else if (this.constant != Constant.NotAConstant) {
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=276740
        int operator = (this.bits & OperatorMASK) >> OperatorSHIFT;
        if ((operator == EQUAL_EQUAL && this.constant == BooleanConstant.fromValue(true))
            || (operator == NOT_EQUAL && this.constant == BooleanConstant.fromValue(false)))
          scope.problemReporter().comparingIdenticalExpressions(this);
      }
      return this.resolvedType = TypeBinding.BOOLEAN;
    }

    // Object references
    // spec 15.20.3
    if ((!leftType.isBaseType() || leftType == TypeBinding.NULL) // cannot compare: Object == (int)0
        && (!rightType.isBaseType() || rightType == TypeBinding.NULL)
        && (checkCastTypesCompatibility(scope, leftType, rightType, null)
            || checkCastTypesCompatibility(scope, rightType, leftType, null))) {

      // (special case for String)
      if ((rightType.id == T_JavaLangString) && (leftType.id == T_JavaLangString)) {
        computeConstant(leftType, rightType);
      } else {
        this.constant = Constant.NotAConstant;
      }
      TypeBinding objectType = scope.getJavaLangObject();
      this.left.computeConversion(scope, objectType, leftType);
      this.right.computeConversion(scope, objectType, rightType);
      // check need for operand cast
      boolean unnecessaryLeftCast = (this.left.bits & UnnecessaryCast) != 0;
      boolean unnecessaryRightCast = (this.right.bits & UnnecessaryCast) != 0;
      if (unnecessaryLeftCast || unnecessaryRightCast) {
        TypeBinding alternateLeftType =
            unnecessaryLeftCast ? ((CastExpression) this.left).expression.resolvedType : leftType;
        TypeBinding alternateRightType =
            unnecessaryRightCast
                ? ((CastExpression) this.right).expression.resolvedType
                : rightType;
        if (checkCastTypesCompatibility(scope, alternateLeftType, alternateRightType, null)
            || checkCastTypesCompatibility(scope, alternateRightType, alternateLeftType, null)) {
          if (unnecessaryLeftCast)
            scope.problemReporter().unnecessaryCast((CastExpression) this.left);
          if (unnecessaryRightCast)
            scope.problemReporter().unnecessaryCast((CastExpression) this.right);
        }
      }
      // check whether comparing identical expressions
      Binding leftDirect = Expression.getDirectBinding(this.left);
      if (leftDirect != null && leftDirect == Expression.getDirectBinding(this.right)) {
        if (!(this.right instanceof Assignment)) {
          scope.problemReporter().comparingIdenticalExpressions(this);
        }
      }
      return this.resolvedType = TypeBinding.BOOLEAN;
    }
    this.constant = Constant.NotAConstant;
    scope.problemReporter().notCompatibleTypesError(this, leftType, rightType);
    return null;
  }