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; }
private void searchVisibleMethods( ReferenceBinding receiverType, Scope scope, InvocationSite invocationSite, Scope invocationScope, boolean onlyStaticMethods, boolean notInJavadoc, ObjectVector methodsFound) { ReferenceBinding currentType = receiverType; if (notInJavadoc) { if (receiverType.isInterface()) { searchVisibleInterfaceMethods( new ReferenceBinding[] {currentType}, receiverType, scope, invocationSite, invocationScope, onlyStaticMethods, methodsFound); currentType = scope.getJavaLangObject(); } } boolean hasPotentialDefaultAbstractMethods = true; while (currentType != null) { MethodBinding[] methods = currentType.availableMethods(); if (methods != null) { searchVisibleLocalMethods( methods, receiverType, scope, invocationSite, invocationScope, onlyStaticMethods, methodsFound); } if (notInJavadoc && hasPotentialDefaultAbstractMethods && (currentType.isAbstract() || currentType.isTypeVariable() || currentType.isIntersectionType() || currentType.isEnum())) { ReferenceBinding[] superInterfaces = currentType.superInterfaces(); if (superInterfaces != null && currentType.isIntersectionType()) { for (int i = 0; i < superInterfaces.length; i++) { superInterfaces[i] = (ReferenceBinding) superInterfaces[i].capture( invocationScope, invocationSite.sourceStart(), invocationSite.sourceEnd()); } } searchVisibleInterfaceMethods( superInterfaces, receiverType, scope, invocationSite, invocationScope, onlyStaticMethods, methodsFound); } else { hasPotentialDefaultAbstractMethods = false; } if (currentType.isParameterizedType()) { currentType = ((ParameterizedTypeBinding) currentType).genericType().superclass(); } else { currentType = currentType.superclass(); } } }