public TypeBinding resolveType(BlockScope scope) {
   // it can be a package, type, member type, local variable or field
   this.binding = scope.getBinding(this.tokens, this);
   if (!this.binding.isValidBinding()) {
     if (this.binding instanceof ProblemFieldBinding) {
       // tolerate some error cases
       if (this.binding.problemId() == ProblemReasons.NotVisible
           || this.binding.problemId() == ProblemReasons.InheritedNameHidesEnclosingName
           || this.binding.problemId() == ProblemReasons.NonStaticReferenceInConstructorInvocation
           || this.binding.problemId() == ProblemReasons.NonStaticReferenceInStaticContext) {
         throw new SelectionNodeFound(this.binding);
       }
       scope.problemReporter().invalidField(this, (FieldBinding) this.binding);
     } else if (this.binding instanceof ProblemReferenceBinding
         || this.binding instanceof MissingTypeBinding) {
       // tolerate some error cases
       if (this.binding.problemId() == ProblemReasons.NotVisible) {
         throw new SelectionNodeFound(this.binding);
       }
       scope.problemReporter().invalidType(this, (TypeBinding) this.binding);
     } else {
       scope.problemReporter().unresolvableReference(this, this.binding);
     }
     throw new SelectionNodeFound();
   }
   throw new SelectionNodeFound(this.binding);
 }
Example #2
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);
      }
    }
  }
  /** Resolve without warnings */
  public void resolve(BlockScope scope, boolean warn, boolean considerParamRefAsUsage) {

    LocalVariableBinding variableBinding = scope.findVariable(this.token);
    if (variableBinding != null
        && variableBinding.isValidBinding()
        && ((variableBinding.tagBits & TagBits.IsArgument) != 0)) {
      this.binding = variableBinding;
      if (considerParamRefAsUsage) {
        variableBinding.useFlag = LocalVariableBinding.USED;
      }
      return;
    }
    if (warn) {
      try {
        MethodScope methScope = (MethodScope) scope;
        scope
            .problemReporter()
            .javadocUndeclaredParamTagName(
                this.token,
                this.sourceStart,
                this.sourceEnd,
                methScope.referenceMethod().modifiers);
      } catch (Exception e) {
        scope
            .problemReporter()
            .javadocUndeclaredParamTagName(this.token, this.sourceStart, this.sourceEnd, -1);
      }
    }
  }
  public TypeBinding resolveType(BlockScope scope) {
    this.constant = Constant.NotAConstant;
    TypeBinding expressionType = this.expression.resolveType(scope);
    TypeBinding checkedType = this.type.resolveType(scope, true /* check bounds*/);
    if (expressionType == null || checkedType == null) return null;

    if (!checkedType.isReifiable()) {
      scope.problemReporter().illegalInstanceOfGenericType(checkedType, this);
    } else if ((expressionType != TypeBinding.NULL
            && expressionType.isBaseType()) // disallow autoboxing
        || !checkCastTypesCompatibility(scope, checkedType, expressionType, null)) {
      scope.problemReporter().notCompatibleTypesError(this, expressionType, checkedType);
    }
    return this.resolvedType = TypeBinding.BOOLEAN;
  }
 public void resolve(BlockScope scope) {
   this.assertExpression.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
   if (this.exceptionArgument != null) {
     TypeBinding exceptionArgumentType = this.exceptionArgument.resolveType(scope);
     if (exceptionArgumentType != null) {
       int id = exceptionArgumentType.id;
       switch (id) {
         case T_void:
           scope.problemReporter().illegalVoidExpression(this.exceptionArgument);
           // $FALL-THROUGH$
         default:
           id = T_JavaLangObject;
           // $FALL-THROUGH$
         case T_boolean:
         case T_byte:
         case T_char:
         case T_short:
         case T_double:
         case T_float:
         case T_int:
         case T_long:
         case T_JavaLangString:
           this.exceptionArgument.implicitConversion = (id << 4) + id;
       }
     }
   }
 }
Example #6
0
 /**
  * Record that a nullity mismatch was detected against an annotated type reference.
  *
  * @param currentScope scope for error reporting
  * @param expression the expression violating the specification
  * @param providedType the type of the provided value, i.e., either expression or an element
  *     thereof (in ForeachStatements)
  * @param expectedType the declared type of the spec'ed variable, for error reporting.
  * @param flowInfo the flowInfo observed when visiting expression
  * @param nullStatus the null status of expression at the current location
  * @param annotationStatus status from type annotation analysis, or null
  */
 public void recordNullityMismatch(
     BlockScope currentScope,
     Expression expression,
     TypeBinding providedType,
     TypeBinding expectedType,
     FlowInfo flowInfo,
     int nullStatus,
     NullAnnotationMatching annotationStatus) {
   if (providedType == null) {
     return; // assume type error was already reported
   }
   if (expression.localVariableBinding()
       != null) { // flowContext cannot yet handle non-localvar expressions (e.g., fields)
     // find the inner-most flowContext that might need deferred handling:
     FlowContext currentContext = this;
     while (currentContext != null) {
       // some flow contexts implement deferred checking, should we participate in that?
       int isInsideAssert = 0x0;
       if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
         isInsideAssert = FlowContext.HIDE_NULL_COMPARISON_WARNING;
       }
       if (currentContext.internalRecordNullityMismatch(
           expression,
           providedType,
           flowInfo,
           nullStatus,
           expectedType,
           ASSIGN_TO_NONNULL | isInsideAssert)) return;
       currentContext = currentContext.parent;
     }
   }
   // no reason to defer, so report now:
   if (annotationStatus != null)
     currentScope
         .problemReporter()
         .nullityMismatchingTypeAnnotation(
             expression, providedType, expectedType, annotationStatus);
   else
     currentScope
         .problemReporter()
         .nullityMismatch(
             expression,
             providedType,
             expectedType,
             nullStatus,
             currentScope.environment().getNonNullAnnotationName());
 }
 /** Check null-ness of 'var' against a possible null annotation */
 public static int checkAssignment(
     BlockScope currentScope,
     FlowContext flowContext,
     VariableBinding var,
     int nullStatus,
     Expression expression,
     TypeBinding providedType) {
   long lhsTagBits = 0L;
   boolean hasReported = false;
   if (currentScope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) {
     lhsTagBits = var.tagBits & TagBits.AnnotationNullMASK;
   } else {
     if (expression instanceof ConditionalExpression && expression.isPolyExpression()) {
       // drill into both branches:
       ConditionalExpression ce = ((ConditionalExpression) expression);
       int status1 =
           NullAnnotationMatching.checkAssignment(
               currentScope,
               flowContext,
               var,
               ce.ifTrueNullStatus,
               ce.valueIfTrue,
               ce.valueIfTrue.resolvedType);
       int status2 =
           NullAnnotationMatching.checkAssignment(
               currentScope,
               flowContext,
               var,
               ce.ifFalseNullStatus,
               ce.valueIfFalse,
               ce.valueIfFalse.resolvedType);
       if (status1 == status2) return status1;
       return nullStatus; // if both branches disagree use the precomputed & merged nullStatus
     }
     lhsTagBits = var.type.tagBits & TagBits.AnnotationNullMASK;
     NullAnnotationMatching annotationStatus = analyse(var.type, providedType, nullStatus);
     if (annotationStatus.isDefiniteMismatch()) {
       currentScope
           .problemReporter()
           .nullityMismatchingTypeAnnotation(expression, providedType, var.type, annotationStatus);
       hasReported = true;
     } else if (annotationStatus.isUnchecked()) {
       flowContext.recordNullityMismatch(
           currentScope, expression, providedType, var.type, nullStatus);
       hasReported = true;
     }
   }
   if (lhsTagBits == TagBits.AnnotationNonNull && nullStatus != FlowInfo.NON_NULL) {
     if (!hasReported)
       flowContext.recordNullityMismatch(
           currentScope, expression, providedType, var.type, nullStatus);
     return FlowInfo.NON_NULL;
   } else if (lhsTagBits == TagBits.AnnotationNullable
       && nullStatus == FlowInfo.UNKNOWN) { // provided a legacy type?
     return FlowInfo.POTENTIALLY_NULL; // -> use more specific info from the annotation
   }
   return nullStatus;
 }
  /*
   * No need to emulate access to protected fields since not implicitly accessed
   */
  public void manageSyntheticAccessIfNecessary(
      BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) {
    if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return;

    // if field from parameterized type got found, use the original field at codegen time
    FieldBinding codegenBinding = this.binding.original();
    if (this.binding.isPrivate()) {
      if ((currentScope.enclosingSourceType() != codegenBinding.declaringClass)
          && this.binding.constant() == Constant.NotAConstant) {
        if (this.syntheticAccessors == null) this.syntheticAccessors = new MethodBinding[2];
        this.syntheticAccessors[isReadAccess ? FieldReference.READ : FieldReference.WRITE] =
            ((SourceTypeBinding) codegenBinding.declaringClass)
                .addSyntheticMethod(
                    codegenBinding, isReadAccess, false /* not super ref in remote type*/);
        currentScope.problemReporter().needToEmulateFieldAccess(codegenBinding, this, isReadAccess);
        return;
      }
    } else if (this.receiver instanceof QualifiedSuperReference) { // qualified super
      // qualified super need emulation always
      SourceTypeBinding destinationType =
          (SourceTypeBinding) (((QualifiedSuperReference) this.receiver).currentCompatibleType);
      if (this.syntheticAccessors == null) this.syntheticAccessors = new MethodBinding[2];
      this.syntheticAccessors[isReadAccess ? FieldReference.READ : FieldReference.WRITE] =
          destinationType.addSyntheticMethod(codegenBinding, isReadAccess, isSuperAccess());
      currentScope.problemReporter().needToEmulateFieldAccess(codegenBinding, this, isReadAccess);
      return;

    } else if (this.binding.isProtected()) {
      SourceTypeBinding enclosingSourceType;
      if (((this.bits & ASTNode.DepthMASK) != 0)
          && this.binding.declaringClass.getPackage()
              != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) {

        SourceTypeBinding currentCompatibleType =
            (SourceTypeBinding)
                enclosingSourceType.enclosingTypeAt(
                    (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT);
        if (this.syntheticAccessors == null) this.syntheticAccessors = new MethodBinding[2];
        this.syntheticAccessors[isReadAccess ? FieldReference.READ : FieldReference.WRITE] =
            currentCompatibleType.addSyntheticMethod(codegenBinding, isReadAccess, isSuperAccess());
        currentScope.problemReporter().needToEmulateFieldAccess(codegenBinding, this, isReadAccess);
        return;
      }
    }
  }
Example #9
0
  public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {

    if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return;

    // if method from parameterized type got found, use the original method at codegen time
    MethodBinding codegenBinding = this.binding.original();
    if (this.binding.isPrivate()) {

      // depth is set for both implicit and explicit access (see MethodBinding#canBeSeenBy)
      if (currentScope.enclosingSourceType() != codegenBinding.declaringClass) {
        this.syntheticAccessor =
            ((SourceTypeBinding) codegenBinding.declaringClass)
                .addSyntheticMethod(codegenBinding, false /* not super access there */);
        currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this);
        return;
      }

    } else if (this.receiver instanceof QualifiedSuperReference) { // qualified super

      // qualified super need emulation always
      SourceTypeBinding destinationType =
          (SourceTypeBinding) (((QualifiedSuperReference) this.receiver).currentCompatibleType);
      this.syntheticAccessor = destinationType.addSyntheticMethod(codegenBinding, isSuperAccess());
      currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this);
      return;

    } else if (this.binding.isProtected()) {

      SourceTypeBinding enclosingSourceType;
      if (((this.bits & ASTNode.DepthMASK) != 0)
          && codegenBinding.declaringClass.getPackage()
              != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) {

        SourceTypeBinding currentCompatibleType =
            (SourceTypeBinding)
                enclosingSourceType.enclosingTypeAt(
                    (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT);
        this.syntheticAccessor =
            currentCompatibleType.addSyntheticMethod(codegenBinding, isSuperAccess());
        currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this);
        return;
      }
    }
  }
 /**
  * @see
  *     org.eclipse.jdt.internal.compiler.ast.BinaryExpression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope)
  */
 public TypeBinding resolveType(BlockScope scope) {
   TypeBinding result = super.resolveType(scope);
   // 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 result;
 }
Example #11
0
  /**
   * 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 (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);
    }
  }
  public TypeBinding resolveType(BlockScope scope) {

    this.constant = Constant.NotAConstant;
    if (!checkAccess(scope.methodScope())) return null;
    ReferenceBinding enclosingReceiverType = scope.enclosingReceiverType();
    if (enclosingReceiverType.id == T_JavaLangObject) {
      scope.problemReporter().cannotUseSuperInJavaLangObject(this);
      return null;
    }
    return this.resolvedType = enclosingReceiverType.superclass();
  }
 // Report an error if necessary (if even more unreachable than previously reported
 // complaintLevel = 0 if was reachable up until now, 1 if fake reachable (deadcode), 2 if fatal
 // unreachable (error)
 public int complainIfUnreachable(
     FlowInfo flowInfo, BlockScope scope, int previousComplaintLevel, boolean endOfBlock) {
   if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0) {
     if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE_OR_DEAD) != 0)
       this.bits &= ~ASTNode.IsReachable;
     if (flowInfo == FlowInfo.DEAD_END) {
       if (previousComplaintLevel < COMPLAINED_UNREACHABLE) {
         scope.problemReporter().unreachableCode(this);
         if (endOfBlock) scope.checkUnclosedCloseables(flowInfo, null, null, null);
       }
       return COMPLAINED_UNREACHABLE;
     } else {
       if (previousComplaintLevel < COMPLAINED_FAKE_REACHABLE) {
         scope.problemReporter().fakeReachable(this);
         if (endOfBlock) scope.checkUnclosedCloseables(flowInfo, null, null, null);
       }
       return COMPLAINED_FAKE_REACHABLE;
     }
   }
   return previousComplaintLevel;
 }
 public void resolve(BlockScope scope) {
   if (this.expression != null) {
     if (this.expression.resolveType(scope) != null) {
       TypeBinding javaLangClass = scope.getJavaLangClass();
       if (!javaLangClass.isValidBinding()) {
         scope
             .problemReporter()
             .codeSnippetMissingClass(
                 "java.lang.Class", this.sourceStart, this.sourceEnd); // $NON-NLS-1$
         return;
       }
       TypeBinding javaLangObject = scope.getJavaLangObject();
       if (!javaLangObject.isValidBinding()) {
         scope
             .problemReporter()
             .codeSnippetMissingClass(
                 "java.lang.Object", this.sourceStart, this.sourceEnd); // $NON-NLS-1$
         return;
       }
       TypeBinding[] argumentTypes = new TypeBinding[] {javaLangObject, javaLangClass};
       this.setResultMethod = scope.getImplicitMethod(SETRESULT_SELECTOR, argumentTypes, this);
       if (!this.setResultMethod.isValidBinding()) {
         scope
             .problemReporter()
             .codeSnippetMissingMethod(
                 ROOT_FULL_CLASS_NAME,
                 new String(SETRESULT_SELECTOR),
                 new String(SETRESULT_ARGUMENTS),
                 this.sourceStart,
                 this.sourceEnd);
         return;
       }
       // in constant case, the implicit conversion cannot be left uninitialized
       if (this.expression.constant != Constant.NotAConstant) {
         // fake 'no implicit conversion' (the return type is always void)
         this.expression.implicitConversion = this.expression.constant.typeID() << 4;
       }
     }
   }
 }
Example #15
0
  // Report an error if necessary
  public boolean complainIfUnreachable(
      FlowInfo flowInfo, BlockScope scope, boolean didAlreadyComplain) {

    if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0) {
      this.bits &= ~ASTNode.IsReachableMASK;
      boolean reported = flowInfo == FlowInfo.DEAD_END;
      if (!didAlreadyComplain && reported) {
        scope.problemReporter().unreachableCode(this);
      }
      return reported; // keep going for fake reachable
    }
    return false;
  }
Example #16
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);
    }
  }
Example #17
0
  /**
   * 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);
  }
 public void checkCapturedLocalInitializationIfNecessary(
     ReferenceBinding checkedType, BlockScope currentScope, FlowInfo flowInfo) {
   if (((checkedType.tagBits & (TagBits.AnonymousTypeMask | TagBits.LocalTypeMask))
           == TagBits.LocalTypeMask)
       && !currentScope.isDefinedInType(checkedType)) { // only check external allocations
     NestedTypeBinding nestedType = (NestedTypeBinding) checkedType;
     SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticOuterLocalVariables();
     if (syntheticArguments != null)
       for (int i = 0, count = syntheticArguments.length; i < count; i++) {
         SyntheticArgumentBinding syntheticArgument = syntheticArguments[i];
         LocalVariableBinding targetLocal;
         if ((targetLocal = syntheticArgument.actualOuterLocalVariable) == null) continue;
         if (targetLocal.declaration != null && !flowInfo.isDefinitelyAssigned(targetLocal)) {
           currentScope.problemReporter().uninitializedLocalVariable(targetLocal, this);
         }
       }
   }
 }
  /**
   * 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);
    }
  }
  /**
   * 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;
      }
    }
  }
 public void checkTypeArgumentRedundancy(
     ParameterizedTypeBinding allocationType,
     ReferenceBinding enclosingType,
     TypeBinding[] argumentTypes,
     final BlockScope scope) {
   ProblemReporter reporter = scope.problemReporter();
   if ((reporter.computeSeverity(IProblem.RedundantSpecificationOfTypeArguments)
           == ProblemSeverities.Ignore)
       || scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_7) return;
   if (allocationType.arguments == null) return; // raw binding
   if (this.genericTypeArguments != null)
     return; // diamond can't occur with explicit type args for constructor
   if (argumentTypes == Binding.NO_PARAMETERS
       && this.typeExpected instanceof ParameterizedTypeBinding) {
     ParameterizedTypeBinding expected = (ParameterizedTypeBinding) this.typeExpected;
     if (expected.arguments != null
         && allocationType.arguments.length == expected.arguments.length) {
       // check the case when no ctor takes no params and inference uses the expected type directly
       // eg. X<String> x = new X<String>()
       int i;
       for (i = 0; i < allocationType.arguments.length; i++) {
         if (allocationType.arguments[i] != expected.arguments[i]) break;
       }
       if (i == allocationType.arguments.length) {
         reporter.redundantSpecificationOfTypeArguments(this.type, allocationType.arguments);
         return;
       }
     }
   }
   TypeBinding[] inferredTypes =
       inferElidedTypes(allocationType.genericType(), enclosingType, argumentTypes, scope);
   if (inferredTypes == null) {
     return;
   }
   for (int i = 0; i < inferredTypes.length; i++) {
     if (inferredTypes[i] != allocationType.arguments[i]) return;
   }
   reporter.redundantSpecificationOfTypeArguments(this.type, allocationType.arguments);
 }
 /** Check null-ness of 'var' against a possible null annotation */
 protected int checkAssignmentAgainstNullAnnotation(
     BlockScope currentScope,
     FlowContext flowContext,
     VariableBinding var,
     int nullStatus,
     Expression expression,
     TypeBinding providedType) {
   int severity = 0;
   if ((var.tagBits & TagBits.AnnotationNonNull) != 0 && nullStatus != FlowInfo.NON_NULL) {
     flowContext.recordNullityMismatch(
         currentScope, expression, providedType, var.type, nullStatus);
     return FlowInfo.NON_NULL;
   } else if ((severity = findNullTypeAnnotationMismatch(var.type, providedType)) > 0) {
     currentScope
         .problemReporter()
         .nullityMismatchingTypeAnnotation(
             expression, providedType, var.type, severity == 1, currentScope.environment());
   } else if ((var.tagBits & TagBits.AnnotationNullable) != 0
       && nullStatus == FlowInfo.UNKNOWN) { // provided a legacy type?
     return FlowInfo.POTENTIALLY_NULL; // -> use more specific info from the annotation
   }
   return nullStatus;
 }
  public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
    if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return;
    // if constructor from parameterized type got found, use the original constructor at codegen
    // time
    MethodBinding codegenBinding = this.binding.original();

    ReferenceBinding declaringClass;
    if (codegenBinding.isPrivate()
        && currentScope.enclosingSourceType() != (declaringClass = codegenBinding.declaringClass)) {

      // from 1.4 on, local type constructor can lose their private flag to ease emulation
      if ((declaringClass.tagBits & TagBits.IsLocalType) != 0
          && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
        // constructor will not be dumped as private, no emulation required thus
        codegenBinding.tagBits |= TagBits.ClearPrivateModifier;
      } else {
        this.syntheticAccessor =
            ((SourceTypeBinding) declaringClass)
                .addSyntheticMethod(codegenBinding, isSuperAccess());
        currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this);
      }
    }
  }
Example #24
0
  /**
   * 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
    int alternateLeftTypeId = expressionTypeId;
    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 ((alternateLeftTypeId = alternateLeftType.id)
          == expressionTypeId) { // obvious identity cast
        scope.problemReporter().unnecessaryCast((CastExpression) expression);
        return;
      } else if (alternateLeftTypeId == TypeIds.T_null) {
        alternateLeftTypeId = expressionTypeId; // tolerate null argument cast
        return;
      }
    }
    /*		tolerate widening cast in unary expressions, as may be used when combined in binary expressions (41680)
    		int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4) + alternateLeftTypeId];
    		// (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
    			scope.problemReporter().unnecessaryCastForArgument((CastExpression)expression,  TypeBinding.wellKnownType(scope, expression.implicitConversion >> 4));
    		}
    */
  }
Example #25
0
  private static int checkInvocationArgument(
      BlockScope scope,
      Expression argument,
      TypeBinding parameterType,
      TypeBinding argumentType,
      TypeBinding originalParameterType) {
    argument.computeConversion(scope, parameterType, argumentType);

    if (argumentType != TypeBinding.NULL
        && parameterType.kind() == Binding.WILDCARD_TYPE) { // intersection types are tolerated
      WildcardBinding wildcard = (WildcardBinding) parameterType;
      if (wildcard.boundKind != Wildcard.SUPER) {
        return INVOCATION_ARGUMENT_WILDCARD;
      }
    }
    TypeBinding checkedParameterType =
        parameterType; // originalParameterType == null ? parameterType : originalParameterType;
    if (argumentType != checkedParameterType
        && argumentType.needsUncheckedConversion(checkedParameterType)) {
      scope.problemReporter().unsafeTypeConversion(argument, argumentType, checkedParameterType);
      return INVOCATION_ARGUMENT_UNCHECKED;
    }
    return INVOCATION_ARGUMENT_OK;
  }
Example #26
0
  public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {

    // Consider the try block and catch block so as to compute the intersection of initializations
    // and
    // the minimum exit relative depth amongst all of them. Then consider the subroutine, and append
    // its
    // initialization to the try/catch ones, if the subroutine completes normally. If the subroutine
    // does not
    // complete, then only keep this result for the rest of the analysis

    // process the finally block (subroutine) - create a context for the subroutine

    preTryInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);

    if (anyExceptionVariable != null) {
      anyExceptionVariable.useFlag = LocalVariableBinding.USED;
    }
    if (returnAddressVariable != null) { // TODO (philippe) if subroutine is escaping, unused
      returnAddressVariable.useFlag = LocalVariableBinding.USED;
    }
    InsideSubRoutineFlowContext insideSubContext;
    FinallyFlowContext finallyContext;
    UnconditionalFlowInfo subInfo;
    if (subRoutineStartLabel == null) {
      // no finally block
      insideSubContext = null;
      finallyContext = null;
      subInfo = null;
    } else {
      // analyse finally block first
      insideSubContext = new InsideSubRoutineFlowContext(flowContext, this);
      subInfo =
          finallyBlock
              .analyseCode(
                  currentScope,
                  finallyContext = new FinallyFlowContext(flowContext, finallyBlock),
                  flowInfo.copy().unconditionalInits().discardNullRelatedInitializations())
              .unconditionalInits();
      if (subInfo == FlowInfo.DEAD_END) {
        isSubRoutineEscaping = true;
        scope.problemReporter().finallyMustCompleteNormally(finallyBlock);
      }
      this.subRoutineInits = subInfo;
    }
    // process the try block in a context handling the local exceptions.
    ExceptionHandlingFlowContext handlingContext =
        new ExceptionHandlingFlowContext(
            insideSubContext == null ? flowContext : insideSubContext,
            tryBlock,
            caughtExceptionTypes,
            scope,
            flowInfo.unconditionalInits());

    FlowInfo tryInfo;
    if (tryBlock.isEmptyBlock()) {
      tryInfo = flowInfo;
      tryBlockExit = false;
    } else {
      tryInfo = tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy());
      tryBlockExit = !tryInfo.isReachable();
    }

    // check unreachable catch blocks
    handlingContext.complainIfUnusedExceptionHandlers(scope, this);

    // process the catch blocks - computing the minimal exit depth amongst try/catch
    if (catchArguments != null) {
      int catchCount;
      catchExits = new boolean[catchCount = catchBlocks.length];
      for (int i = 0; i < catchCount; i++) {
        // keep track of the inits that could potentially have led to this exception handler (for
        // final assignments diagnosis)
        FlowInfo catchInfo =
            flowInfo
                .copy()
                .unconditionalInits()
                .addPotentialInitializationsFrom(
                    handlingContext.initsOnException(caughtExceptionTypes[i]).unconditionalInits())
                .addPotentialInitializationsFrom(tryInfo.unconditionalInits())
                .addPotentialInitializationsFrom(handlingContext.initsOnReturn);

        // catch var is always set
        LocalVariableBinding catchArg = catchArguments[i].binding;
        FlowContext catchContext = insideSubContext == null ? flowContext : insideSubContext;
        catchInfo.markAsDefinitelyAssigned(catchArg);
        catchInfo.markAsDefinitelyNonNull(catchArg);
        /*
        "If we are about to consider an unchecked exception handler, potential inits may have occured inside
        the try block that need to be detected , e.g.
        try { x = 1; throwSomething();} catch(Exception e){ x = 2} "
        "(uncheckedExceptionTypes notNil and: [uncheckedExceptionTypes at: index])
        ifTrue: [catchInits addPotentialInitializationsFrom: tryInits]."
        */
        if (tryBlock.statements == null) {
          catchInfo.setReachMode(FlowInfo.UNREACHABLE);
        }
        catchInfo = catchBlocks[i].analyseCode(currentScope, catchContext, catchInfo);
        catchExits[i] = !catchInfo.isReachable();
        tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits());
      }
    }
    if (subRoutineStartLabel == null) {
      mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo);
      return tryInfo;
    }

    // we also need to check potential multiple assignments of final variables inside the finally
    // block
    // need to include potential inits from returns inside the try/catch parts - 1GK2AOF
    finallyContext.complainOnDeferredChecks(
        tryInfo.isReachable()
            ? (tryInfo.addPotentialInitializationsFrom(insideSubContext.initsOnReturn))
            : insideSubContext.initsOnReturn,
        currentScope);
    if (subInfo == FlowInfo.DEAD_END) {
      mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(subInfo);
      return subInfo;
    } else {
      FlowInfo mergedInfo = tryInfo.addInitializationsFrom(subInfo);
      mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
      return mergedInfo;
    }
  }
Example #27
0
  public void resolve(BlockScope upperScope) {

    // special scope for secret locals optimization.
    this.scope = new BlockScope(upperScope);

    BlockScope tryScope = new BlockScope(scope);
    BlockScope finallyScope = null;

    if (finallyBlock != null) {
      if (finallyBlock.isEmptyBlock()) {
        if ((finallyBlock.bits & UndocumentedEmptyBlockMASK) != 0) {
          scope
              .problemReporter()
              .undocumentedEmptyBlock(finallyBlock.sourceStart, finallyBlock.sourceEnd);
        }
      } else {
        finallyScope = new BlockScope(scope, false); // don't add it yet to parent scope

        // provision for returning and forcing the finally block to run
        MethodScope methodScope = scope.methodScope();

        // the type does not matter as long as it is not a base type
        if (!upperScope.compilerOptions().inlineJsrBytecode) {
          this.returnAddressVariable =
              new LocalVariableBinding(
                  SecretReturnName, upperScope.getJavaLangObject(), AccDefault, false);
          finallyScope.addLocalVariable(returnAddressVariable);
          this.returnAddressVariable.setConstant(NotAConstant); // not inlinable
        }
        this.subRoutineStartLabel = new Label();

        this.anyExceptionVariable =
            new LocalVariableBinding(
                SecretAnyHandlerName, scope.getJavaLangThrowable(), AccDefault, false);
        finallyScope.addLocalVariable(this.anyExceptionVariable);
        this.anyExceptionVariable.setConstant(NotAConstant); // not inlinable

        if (!methodScope.isInsideInitializer()) {
          MethodBinding methodBinding =
              ((AbstractMethodDeclaration) methodScope.referenceContext).binding;
          if (methodBinding != null) {
            TypeBinding methodReturnType = methodBinding.returnType;
            if (methodReturnType.id != T_void) {
              this.secretReturnValue =
                  new LocalVariableBinding(
                      SecretLocalDeclarationName, methodReturnType, AccDefault, false);
              finallyScope.addLocalVariable(this.secretReturnValue);
              this.secretReturnValue.setConstant(NotAConstant); // not inlinable
            }
          }
        }
        finallyBlock.resolveUsing(finallyScope);
        // force the finally scope to have variable positions shifted after its try scope and catch
        // ones
        finallyScope.shiftScopes =
            new BlockScope[catchArguments == null ? 1 : catchArguments.length + 1];
        finallyScope.shiftScopes[0] = tryScope;
      }
    }
    this.tryBlock.resolveUsing(tryScope);

    // arguments type are checked against JavaLangThrowable in resolveForCatch(..)
    if (this.catchBlocks != null) {
      int length = this.catchArguments.length;
      TypeBinding[] argumentTypes = new TypeBinding[length];
      boolean catchHasError = false;
      for (int i = 0; i < length; i++) {
        BlockScope catchScope = new BlockScope(scope);
        if (finallyScope != null) {
          finallyScope.shiftScopes[i + 1] = catchScope;
        }
        // side effect on catchScope in resolveForCatch(..)
        if ((argumentTypes[i] = catchArguments[i].resolveForCatch(catchScope)) == null) {
          catchHasError = true;
        }
        catchBlocks[i].resolveUsing(catchScope);
      }
      if (catchHasError) {
        return;
      }
      // Verify that the catch clause are ordered in the right way:
      // more specialized first.
      this.caughtExceptionTypes = new ReferenceBinding[length];
      for (int i = 0; i < length; i++) {
        caughtExceptionTypes[i] = (ReferenceBinding) argumentTypes[i];
        for (int j = 0; j < i; j++) {
          if (caughtExceptionTypes[i].isCompatibleWith(argumentTypes[j])) {
            scope
                .problemReporter()
                .wrongSequenceOfExceptionTypesError(
                    this, caughtExceptionTypes[i], i, argumentTypes[j]);
          }
        }
      }
    } else {
      caughtExceptionTypes = new ReferenceBinding[0];
    }

    if (finallyScope != null) {
      // add finallyScope as last subscope, so it can be shifted behind try/catch subscopes.
      // the shifting is necessary to achieve no overlay in between the finally scope and its
      // sibling in term of local variable positions.
      this.scope.addSubscope(finallyScope);
    }
  }
Example #28
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]);
        }
      }
    }
  }
Example #29
0
  /** 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) { // 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) { // 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);
      }
    }
  }
Example #30
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;
    }
  }