Esempio n. 1
0
  /**
   * 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 (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 (memberType
          == scope.getMemberType(
              memberType.sourceName(), (ReferenceBinding) alternateEnclosingInstanceType)) {
        scope.problemReporter().unnecessaryCast((CastExpression) enclosingInstance);
      }
    }
  }
Esempio n. 2
0
  /**
   * 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) {
    if (scope.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.problemReporter().unnecessaryCast(rhs);
    }
  }
Esempio n. 3
0
 void checkAssignment(BlockScope scope, TypeBinding lhsType, TypeBinding rhsType) {
   FieldBinding leftField = getLastField(this.lhs);
   if (leftField != null
       && rhsType != TypeBinding.NULL
       && (lhsType.kind() == Binding.WILDCARD_TYPE)
       && ((WildcardBinding) lhsType).boundKind != Wildcard.SUPER) {
     scope.problemReporter().wildcardAssignment(lhsType, rhsType, this.expression);
   } else if (leftField != null
       && !leftField.isStatic()
       && leftField.declaringClass != null /*length pseudo field*/
       && leftField.declaringClass.isRawType()) {
     scope.problemReporter().unsafeRawFieldAssignment(leftField, rhsType, this.lhs);
   } else if (rhsType.needsUncheckedConversion(lhsType)) {
     scope.problemReporter().unsafeTypeConversion(this.expression, rhsType, lhsType);
   }
 }
Esempio n. 4
0
  public TypeBinding resolveType(BlockScope scope) {
    // due to syntax lhs may be only a NameReference, a FieldReference or an ArrayReference
    this.constant = Constant.NotAConstant;
    if (!(this.lhs instanceof Reference) || this.lhs.isThis()) {
      scope.problemReporter().expressionShouldBeAVariable(this.lhs);
      return null;
    }
    TypeBinding lhsType = lhs.resolveType(scope);
    this.expression.setExpectedType(lhsType); // needed in case of generic method invocation
    if (lhsType != null) {
      this.resolvedType = lhsType.capture(scope, this.sourceEnd);
    }
    TypeBinding rhsType = this.expression.resolveType(scope);
    if (lhsType == null || rhsType == null) {
      return null;
    }
    // check for assignment with no effect
    Binding left = getDirectBinding(this.lhs);
    if (left != null && left == getDirectBinding(this.expression)) {
      scope.problemReporter().assignmentHasNoEffect(this, left.shortReadableName());
    }

    // Compile-time conversion of base-types : implicit narrowing integer into byte/short/character
    // may require to widen the rhs expression at runtime
    if (lhsType != rhsType) { // must call before computeConversion() and typeMismatchError()
      scope.compilationUnitScope().recordTypeConversion(lhsType, rhsType);
    }
    if ((this.expression.isConstantValueOfTypeAssignableToType(rhsType, lhsType)
            || (lhsType.isBaseType() && BaseTypeBinding.isWidening(lhsType.id, rhsType.id)))
        || rhsType.isCompatibleWith(lhsType)) {
      this.expression.computeConversion(scope, lhsType, rhsType);
      checkAssignment(scope, lhsType, rhsType);
      if (this.expression instanceof CastExpression
          && (this.expression.bits & ASTNode.UnnecessaryCast) == 0) {
        CastExpression.checkNeedForAssignedCast(scope, lhsType, (CastExpression) this.expression);
      }
      return this.resolvedType;
    } else if (scope.isBoxingCompatibleWith(rhsType, lhsType)
        || (rhsType.isBaseType() // narrowing then boxing ?
            && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing
            && !lhsType.isBaseType()
            && this.expression.isConstantValueOfTypeAssignableToType(
                rhsType, scope.environment().computeBoxingType(lhsType)))) {
      this.expression.computeConversion(scope, lhsType, rhsType);
      if (this.expression instanceof CastExpression
          && (this.expression.bits & ASTNode.UnnecessaryCast) == 0) {
        CastExpression.checkNeedForAssignedCast(scope, lhsType, (CastExpression) this.expression);
      }
      return this.resolvedType;
    }
    scope.problemReporter().typeMismatchError(rhsType, lhsType, this.expression, this.lhs);
    return lhsType;
  }
Esempio n. 5
0
  public TypeBinding resolveType(BlockScope scope) {
    // compute a new constant if the cast is effective

    // due to the fact an expression may start with ( and that a cast can also start with (
    // the field is an expression....it can be a TypeReference OR a NameReference Or
    // any kind of Expression <-- this last one is invalid.......

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

    if ((this.type instanceof TypeReference)
        || (this.type instanceof NameReference)
            && ((this.type.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT)
                == 0) { // no extra parenthesis around type: ((A))exp

      boolean exprContainCast = false;

      TypeBinding castType = this.resolvedType = this.type.resolveType(scope);
      // expression.setExpectedType(this.resolvedType); // needed in case of generic method
      // invocation
      if (this.expression instanceof CastExpression) {
        this.expression.bits |= ASTNode.DisableUnnecessaryCastCheck;
        exprContainCast = true;
      }
      TypeBinding expressionType = this.expression.resolveType(scope);
      if (castType != null) {
        if (expressionType != null) {
          boolean isLegal =
              checkCastTypesCompatibility(scope, castType, expressionType, this.expression);
          if (isLegal) {
            this.expression.computeConversion(scope, castType, expressionType);
            if ((this.bits & ASTNode.UnsafeCast) != 0) { // unsafe cast
              scope.problemReporter().unsafeCast(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.sourceEnd);
        if (exprContainCast) {
          checkNeedForCastCast(scope, this);
        }
      }
      return this.resolvedType;
    } else { // expression as a cast
      TypeBinding expressionType = this.expression.resolveType(scope);
      if (expressionType == null) return null;
      scope.problemReporter().invalidTypeReference(this.type);
      return null;
    }
  }
Esempio n. 6
0
 public boolean checkUnsafeCast(
     Scope scope,
     TypeBinding castType,
     TypeBinding expressionType,
     TypeBinding match,
     boolean isNarrowing) {
   if (match == castType) {
     if (!isNarrowing
         && match
             == this.resolvedType
                 .leafComponentType()) { // do not tag as unnecessary when recursing through upper
       // bounds
       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.isBoundParameterizedType()) {
         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.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 (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.isBoundParameterizedType() || leafType.isTypeVariable())) {
         this.bits |= ASTNode.UnsafeCast;
         return true;
       }
       break;
     case Binding.TYPE_PARAMETER:
       this.bits |= ASTNode.UnsafeCast;
       return true;
   }
   if (!isNarrowing
       && match
           == this.resolvedType
               .leafComponentType()) { // do not tag as unnecessary when recursing through upper
     // bounds
     tagAsUnnecessaryCast(scope, castType);
   }
   return true;
 }
Esempio n. 7
0
  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;
          }
        };
    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 (originalArgumentTypes[i] != alternateArgumentTypes[i]) {
          scope.problemReporter().unnecessaryCast((CastExpression) arguments[i]);
        }
      }
    }
  }