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; }
public TypeBinding resolveType(BlockScope scope) { this.constant = Constant.NotAConstant; if ((this.targetType = this.type.resolveType(scope, true /* check bounds*/)) == null) return null; /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=320463 https://bugs.eclipse.org/bugs/show_bug.cgi?id=312076 JLS3 15.8.2 forbids the type named in the class literal expression from being a parameterized type. And the grammar in 18.1 disallows (where X and Y are some concrete types) constructs of the form Outer<X>.class, Outer<X>.Inner.class, Outer.Inner<X>.class, Outer<X>.Inner<Y>.class etc. Corollary wise, we should resolve the type of the class literal expression to be a raw type as class literals exist only for the raw underlying type. */ LookupEnvironment environment = scope.environment(); this.targetType = environment.convertToRawType( this.targetType, true /* force conversion of enclosing types*/); if (this.targetType.isArrayType()) { ArrayBinding arrayBinding = (ArrayBinding) this.targetType; TypeBinding leafComponentType = arrayBinding.leafComponentType; if (leafComponentType == TypeBinding.VOID) { scope.problemReporter().cannotAllocateVoidArray(this); return null; } else if (leafComponentType.isTypeVariable()) { scope .problemReporter() .illegalClassLiteralForTypeVariable((TypeVariableBinding) leafComponentType, this); } } else if (this.targetType.isTypeVariable()) { scope .problemReporter() .illegalClassLiteralForTypeVariable((TypeVariableBinding) this.targetType, this); } // {ObjectTeams: do we need a RoleClassLiteralAccess? if (this.targetType instanceof ReferenceBinding) { ReferenceBinding targetRef = (ReferenceBinding) this.targetType; if (targetRef.isRole()) { if (this.verbatim) { this.targetType = RoleTypeCreator.maybeWrapUnqualifiedRoleType(scope, this.targetType, this); } else { SourceTypeBinding site = scope.enclosingSourceType(); if (scope.methodScope().isStatic // role class literal needs team instance && !site.isRole() // static role method are OK. && !RoleTypeBinding.isRoleWithExplicitAnchor(this.targetType)) // t.R.class? { scope.problemReporter().roleClassLiteralLacksTeamInstance(this, targetRef); return null; } ReferenceBinding teamBinding; if (RoleTypeBinding.isRoleWithExplicitAnchor(targetRef)) teamBinding = targetRef.enclosingType(); else teamBinding = TeamModel.findEnclosingTeamContainingRole(site, targetRef); if (teamBinding == null) scope.problemReporter().externalizedRoleClassLiteral(this, targetRef); else { TypeBinding methodType = RoleClassLiteralAccess.ensureGetClassMethod( teamBinding.getTeamModel(), targetRef.roleModel); // not affected by visibility check (for resilience) this.roleClassLiteralAccess = new RoleClassLiteralAccess(this, methodType); this.resolvedType = this.roleClassLiteralAccess.resolveType(scope); } return this.resolvedType; } } } // SH} ReferenceBinding classType = scope.getJavaLangClass(); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328689 if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { // Integer.class --> Class<Integer>, perform boxing of base types (int.class --> // Class<Integer>) TypeBinding boxedType = null; if (this.targetType.id == T_void) { boxedType = environment.getResolvedType(JAVA_LANG_VOID, scope); } else { boxedType = scope.boxing(this.targetType); } if (environment.usesNullTypeAnnotations()) boxedType = environment.createAnnotatedType( boxedType, new AnnotationBinding[] {environment.getNonNullAnnotation()}); this.resolvedType = environment.createParameterizedType( classType, new TypeBinding[] {boxedType}, null /*not a member*/); } else { this.resolvedType = classType; } return this.resolvedType; }