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; }
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]); } } } }