/** * This method is used by {@link * org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.CallinMethodMappingsAttribute * CallinMethodMappingsAttribute} for decoding a mapping from its bytecode attribute. * * @param method * @return the bytecode level signature of the given method (yet retrenched) */ public static char[] signature(MethodBinding method, WeavingScheme weavingScheme) { StringBuffer buffer = new StringBuffer(); buffer.append('('); // synthetic args for static role method? MethodBinding orig = method.copyInheritanceSrc != null ? method.copyInheritanceSrc : method; // normalize to copyInhSrc so reading a callin-attr. from bytes can more // easily find the method if (weavingScheme == WeavingScheme.OTDRE && orig.declaringClass.isRole() && orig.isStatic()) { buffer.append('I'); buffer.append(String.valueOf(orig.declaringClass.enclosingType().signature())); } // manual retrenching? boolean shouldRetrench = weavingScheme == WeavingScheme.OTRE && method.isCallin(); int offset = shouldRetrench ? MethodSignatureEnhancer.getEnhancingArgLen(weavingScheme) : 0; int paramLen = method.parameters.length; for (int i = offset; i < paramLen; i++) { // 'weaken' to that erasure that was used in the tsuper version: TypeBinding targetParameter = method.getCodeGenType(i); buffer.append(targetParameter.signature()); } buffer.append(')'); TypeBinding sourceReturnType = shouldRetrench ? MethodModel.getReturnType(method) : method.returnType; // 'weaken' to that erasure that was used in the tsuper version: MethodBinding tsuperOriginal = (method.tagBits & TagBits.IsCopyOfParameterized) != 0 ? method.copyInheritanceSrc.original() : null; TypeBinding returnType = (tsuperOriginal != null && tsuperOriginal.returnType.isTypeVariable() && !sourceReturnType.isTypeVariable()) ? tsuperOriginal.returnType : sourceReturnType; if (returnType.isTypeVariable() && method instanceof ParameterizedGenericMethodBinding) returnType = ((ParameterizedGenericMethodBinding) method) .reverseSubstitute((TypeVariableBinding) returnType); buffer.append(returnType.erasure().signature()); int nameLength = buffer.length(); char[] signature = new char[nameLength]; buffer.getChars(0, nameLength, signature, 0); return signature; }
/** * If 'hasSignature' check the return type of the bound method against the declared return type. */ public boolean checkRoleReturnType(CallinCalloutScope scope, boolean isCallout) { TypeBinding methodReturn = boundMethodReturnType(); TypeBinding resolvedReturnType = this.returnType.resolvedType; TypeBinding firstBound = null; if (resolvedReturnType.isTypeVariable()) { firstBound = ((TypeVariableBinding) resolvedReturnType).firstBound; // if declared return type is a type variable, so must the return type of the resolved method: if (!isMethodReturnTypeVariable(this.resolvedMethod)) { scope.problemReporter().differentReturnInMethodSpec(this, /*isCallout*/ false); return false; } } // the role side of a callout may indeed refine the return type // of its inherited role method: if (isCallout) if (this.returnType.resolvedType.isCompatibleWith(methodReturn)) return true; // in other cases types have to be identical: if (!MethodModel.hasUnboundedReturnType( this.resolvedMethod) // unbounded type variable always matches && !TypeAnalyzer.isSameType(scope.enclosingSourceType(), resolvedReturnType, methodReturn) && !TypeAnalyzer.isSameType(scope.enclosingSourceType(), firstBound, methodReturn)) { scope .problemReporter() .differentReturnInMethodSpec( this, ((AbstractMethodMappingDeclaration) scope.referenceContext).isCallout()); return false; } return true; }
private boolean typeUsesTypeVariable(TypeBinding type, TypeBinding variable) { if (TypeBinding.equalsEquals(type.leafComponentType(), variable)) return true; for (TypeVariableBinding t : type.typeVariables()) if (typeUsesTypeVariable(t, variable)) return true; if (type.isTypeVariable()) { if (typeUsesTypeVariable(((ReferenceBinding) type).superclass(), variable)) return true; for (TypeBinding superIfc : ((ReferenceBinding) type).superInterfaces()) if (typeUsesTypeVariable(superIfc, variable)) return true; } return false; }
protected boolean isBoxingCompatible( TypeBinding expressionType, TypeBinding targetType, Expression expression, Scope scope) { if (scope.isBoxingCompatibleWith(expressionType, targetType)) return true; return expressionType .isBaseType() // narrowing then boxing ? Only allowed for some target types see 362279 && !targetType.isBaseType() && !targetType.isTypeVariable() && scope.compilerOptions().sourceLevel >= org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_5 // autoboxing && (targetType.id == TypeIds.T_JavaLangByte || targetType.id == TypeIds.T_JavaLangShort || targetType.id == TypeIds.T_JavaLangCharacter) && expression.isConstantValueOfTypeAssignableToType( expressionType, scope.environment().computeBoxingType(targetType)); }
// interpreting 'type' as a provided type, compute the provide null bits // we inspect the main type plus bounds of type variables and wildcards static long providedNullTagBits(TypeBinding type) { long tagBits = type.tagBits & TagBits.AnnotationNullMASK; if (tagBits != 0) return validNullTagBits(tagBits); if (type.isWildcard()) { // wildcard can be 'provided' during inheritance checks WildcardBinding wildcard = (WildcardBinding) type; if (wildcard.boundKind == Wildcard.UNBOUND) return 0; tagBits = wildcard.bound.tagBits & TagBits.AnnotationNullMASK; if (tagBits == 0) return 0; switch (wildcard.boundKind) { case Wildcard.EXTENDS: if (tagBits == TagBits.AnnotationNonNull) return TagBits.AnnotationNonNull; return TagBits.AnnotationNullMASK; // @Nullable or better case Wildcard.SUPER: if (tagBits == TagBits.AnnotationNullable) return TagBits.AnnotationNullable; return TagBits.AnnotationNullMASK; // @NonNull or worse } return 0; } if (type.isTypeVariable()) { // incl. captures TypeVariableBinding typeVariable = (TypeVariableBinding) type; boolean haveNullBits = false; if (typeVariable.isCapture()) { TypeBinding lowerBound = ((CaptureBinding) typeVariable).lowerBound; if (lowerBound != null) { tagBits = lowerBound.tagBits & TagBits.AnnotationNullMASK; if (tagBits == TagBits.AnnotationNullable) return TagBits.AnnotationNullable; // cannot be @NonNull haveNullBits |= (tagBits != 0); } } if (typeVariable.firstBound != null) { long boundBits = typeVariable.firstBound.tagBits & TagBits.AnnotationNullMASK; if (boundBits == TagBits.AnnotationNonNull) return TagBits.AnnotationNonNull; // cannot be @Nullable haveNullBits |= (boundBits != 0); } if (haveNullBits) return TagBits .AnnotationNullMASK; // could be either, can only match to a wildcard accepting both } return 0; }
public TypeBinding resolveSuperType(ClassScope scope) { // assumes the implementation of resolveType(ClassScope) will call back to detect cycles TypeBinding superType = resolveType(scope); if (superType == null) return null; if (superType.isTypeVariable()) { if (this.resolvedType.isValidBinding()) { this.resolvedType = new ProblemReferenceBinding( getTypeName(), (ReferenceBinding) this.resolvedType, ProblemReasons.IllegalSuperTypeVariable); reportInvalidType(scope); } return null; } return superType; }
// interpreting 'type' as a required type, compute the required null bits // we inspect the main type plus bounds of type variables and wildcards static long requiredNullTagBits(TypeBinding type) { long tagBits = type.tagBits & TagBits.AnnotationNullMASK; if (tagBits != 0) return validNullTagBits(tagBits); if (type.isWildcard()) { WildcardBinding wildcard = (WildcardBinding) type; if (wildcard.boundKind == Wildcard.UNBOUND) return 0; tagBits = wildcard.bound.tagBits & TagBits.AnnotationNullMASK; if (tagBits == 0) return 0; switch (wildcard.boundKind) { case Wildcard.EXTENDS: if (tagBits == TagBits.AnnotationNonNull) return TagBits.AnnotationNonNull; return TagBits.AnnotationNullMASK; // wildcard accepts @Nullable or better case Wildcard.SUPER: if (tagBits == TagBits.AnnotationNullable) return TagBits.AnnotationNullable; return TagBits.AnnotationNullMASK; // wildcard accepts @NonNull or worse } return 0; } if (type.isTypeVariable()) { // assume we must require @NonNull, unless: (1) lower @Nullable bound, or (2) no nullness // specified TypeVariableBinding typeVariable = (TypeVariableBinding) type; boolean haveNullBits = false; if (type.isCapture()) { TypeBinding lowerBound = ((CaptureBinding) type).lowerBound; if (lowerBound != null) { tagBits = lowerBound.tagBits & TagBits.AnnotationNullMASK; if (tagBits == TagBits.AnnotationNullable) return TagBits.AnnotationNullable; // (1) type cannot require @NonNull haveNullBits = tagBits != 0; } } if (typeVariable.firstBound != null) haveNullBits |= (typeVariable.firstBound.tagBits & TagBits.AnnotationNullMASK) != 0; if (haveNullBits) return TagBits .AnnotationNonNull; // could require @NonNull (unless (2) unspecified nullness) } return 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; }
/** Check whether the baseSpec has a result compatible via replace. */ public void checkResultForReplace(MethodSpec baseSpec) { boolean typeIdentityRequired = true; // default unless return is type variable // covariant return requires a fresh type parameter for the role's return type: if (baseSpec.covariantReturn && this.roleMethodSpec.returnType != null) { TypeBinding resolvedRoleReturn = this.roleMethodSpec.returnType.resolvedType; if (resolvedRoleReturn != null) { if (!resolvedRoleReturn.isTypeVariable()) { this.scope .problemReporter() .covariantReturnRequiresTypeParameter(this.roleMethodSpec.returnType); this.binding.tagBits |= TagBits.HasMappingIncompatibility; } else { // is the type parameter "fresh"? for (Argument arg : this.roleMethodSpec.arguments) { if (typeUsesTypeVariable( arg.type.resolvedType.leafComponentType(), resolvedRoleReturn)) { this.scope .problemReporter() .duplicateUseOfTypeVariableInCallin( this.roleMethodSpec.returnType, resolvedRoleReturn); this.binding.tagBits |= TagBits.HasMappingIncompatibility; break; } } } } } TypeVariableBinding returnVariable = MethodModel.checkedGetReturnTypeVariable(this.roleMethodSpec.resolvedMethod); if (returnVariable != null) { // unbounded type variable always matches: if (returnVariable.firstBound == null) return; // in case of type variable only one-way compatibility is needed even for replace: typeIdentityRequired = false; } // now go for the actual type checking: TypeBinding baseReturn = baseSpec.resolvedMethod.returnType; TypeBinding roleReturn = MethodModel.getReturnType(this.roleMethodSpec.resolvedMethod); TypeBinding roleReturnLeaf = roleReturn != null ? roleReturn.leafComponentType() : null; if (roleReturnLeaf instanceof ReferenceBinding && ((ReferenceBinding) roleReturnLeaf).isRole()) { // strengthen: roleReturnLeaf = TeamModel.strengthenRoleType(this.scope.enclosingSourceType(), roleReturnLeaf); if (roleReturnLeaf == null) { // FIXME(SH): testcase and better handling String roleReturnName = roleReturn != null ? new String(roleReturn.readableName()) : "null return type"; //$NON-NLS-1$ throw new InternalCompilerError( "role strengthening for " + roleReturnName + " -> null"); // $NON-NLS-1$ //$NON-NLS-2$ } // bound roles use their topmost bound super: if (((ReferenceBinding) roleReturnLeaf).baseclass() != null) roleReturnLeaf = RoleModel.getTopmostBoundRole(this.scope, (ReferenceBinding) roleReturnLeaf); // need the RTB: if (!(roleReturnLeaf instanceof DependentTypeBinding)) roleReturnLeaf = RoleTypeCreator.maybeWrapUnqualifiedRoleType( roleReturnLeaf, this.scope.enclosingSourceType()); // array? int dims = roleReturn != null ? roleReturn.dimensions() : 0; if (dims == 0) { roleReturn = roleReturnLeaf; this.realRoleReturn = roleReturnLeaf; } else { roleReturn = ((DependentTypeBinding) roleReturnLeaf).getArrayType(dims); this.realRoleReturn = ((DependentTypeBinding) roleReturnLeaf).getArrayType(dims); } } if (baseReturn == null || baseReturn == TypeBinding.VOID) { // OTJLD 4.4(b): "A callin method bound with replace // to a base method returning void // must not declare a non-void result." if (!(roleReturn == null || roleReturn == TypeBinding.VOID)) { this.scope.problemReporter().callinIllegalRoleReturnReturn(baseSpec, this.roleMethodSpec); this.binding.tagBits |= TagBits.HasMappingIncompatibility; } } else { if (roleReturn == null || roleReturn == TypeBinding.VOID) { this.baseMethodNeedingResultFromBasecall = baseSpec; // will be reported in checkBaseResult(). return; } TypeBinding baseLeaf = baseReturn.leafComponentType(); if (baseLeaf instanceof DependentTypeBinding) { // instantiate relative to Role._OT$base: ReferenceBinding enclosingRole = this.scope.enclosingSourceType(); FieldBinding baseField = enclosingRole.getField(IOTConstants._OT_BASE, true); if (baseField != null && baseField.isValidBinding()) baseReturn = baseField.getRoleTypeBinding((ReferenceBinding) baseLeaf, baseReturn.dimensions()); } // check auto(un)boxing: if (this.scope.isBoxingCompatibleWith(roleReturn, baseReturn)) return; Config oldConfig = Config.createOrResetConfig(this); try { if (!roleReturn.isCompatibleWith(baseReturn)) { if (typeIdentityRequired) { this.scope .problemReporter() .callinIncompatibleReturnType(baseSpec, this.roleMethodSpec); this.binding.tagBits |= TagBits.HasMappingIncompatibility; return; } // else we still needed the lowering test } // callin replace requires two way compatibility: baseSpec.returnNeedsTranslation = Config.getLoweringRequired(); } finally { Config.removeOrRestore(oldConfig, this); } // from now on don't bother with arrays any more (dimensions have been checked): roleReturn = roleReturn.leafComponentType(); baseReturn = baseReturn.leafComponentType(); TypeBinding translatedReturn = baseSpec.returnNeedsTranslation ? ((ReferenceBinding) roleReturn).baseclass() : roleReturn; if (translatedReturn.isTypeVariable()) { TypeBinding firstBound = ((TypeVariableBinding) translatedReturn).firstBound; if (firstBound != null) translatedReturn = firstBound; } if (!baseReturn.isCompatibleWith(translatedReturn)) { this.scope .problemReporter() .callinIncompatibleReturnTypeBaseCall(baseSpec, this.roleMethodSpec); this.binding.tagBits |= TagBits.HasMappingIncompatibility; } } }
/** * Check all parameters in methodSpec against the resolved role method. Also record which * parameters (including result) need translation (lifting/lowering). * * <p>Pre: not called if parameter mappings are present. * * @param methodSpec */ protected boolean internalCheckParametersCompatibility( MethodSpec methodSpec, TypeBinding[] roleParams, TypeBinding[] baseParams) { if (baseParams.length < roleParams.length) { this.scope .problemReporter() .tooFewArgumentsInMethodMapping(this.roleMethodSpec, methodSpec, false /*callout*/); this.binding.tagBits |= TagBits.HasMappingIncompatibility; return false; } else { // before modifying the parameters array copy it: System.arraycopy( this.roleMethodSpec.parameters, 0, this.roleMethodSpec.parameters = new TypeBinding[roleParams.length], 0, roleParams.length); for (int j = 0; j < roleParams.length; j++) { TypeBinding baseParam = baseParams[j]; TypeBinding roleParam = roleParams[j]; if (baseParam.dimensions() != roleParam.dimensions()) { this.scope .problemReporter() .incompatibleMappedArgument( baseParam, roleParam, this.roleMethodSpec, j, /*callout*/ false); this.binding.tagBits |= TagBits.HasMappingIncompatibility; continue; // no real type checking needed. } TypeBinding baseLeaf = baseParam.leafComponentType(); TypeBinding roleLeaf = roleParam.leafComponentType(); ASTNode location = (methodSpec.hasSignature) ? (ASTNode) methodSpec.arguments[j] : methodSpec; boolean compatibilityViaBaseAnchor = false; boolean hasReportedError = false; boolean isTypeVariable = false; try { // capture continue exits // unbound type variable matches everything: if (roleParam.isTypeVariable()) { TypeVariableBinding typeVariableBinding = (TypeVariableBinding) roleParam; if (typeVariableBinding.firstBound == null) continue; // use bound for type checking below, yet need not check two-way compatibility: isTypeVariable = true; roleLeaf = typeVariableBinding.firstBound.leafComponentType(); } int dimensions = roleParam.dimensions(); if (baseLeaf.isCompatibleWith(roleLeaf)) { this.roleMethodSpec.parameters[j] = roleParam; continue; } if (RoleTypeCreator.isCompatibleViaBaseAnchor( this.scope, baseLeaf, roleLeaf, TokenNameBINDIN)) { this.roleMethodSpec.parameters[j] = roleParam; compatibilityViaBaseAnchor = true; continue; } TypeBinding roleToLiftTo = null; if (isReplaceCallin()) { TypeBinding roleSideType = roleLeaf; if (roleSideType.isRole()) { ReferenceBinding roleRef = (ReferenceBinding) roleSideType; roleRef = (ReferenceBinding) TeamModel.strengthenRoleType(this.scope.enclosingReceiverType(), roleRef); if (TypeBinding.equalsEquals(roleRef.baseclass(), baseLeaf)) { if (dimensions > 0) { if (roleRef instanceof DependentTypeBinding) roleToLiftTo = ((DependentTypeBinding) roleRef).getArrayType(dimensions); else roleToLiftTo = this.scope.createArrayType(roleRef, dimensions); // FIXME(SH): is this OK? } else { roleToLiftTo = roleRef; } } } } else { // this uses OTJLD 2.3.3(a) adaptation which is not reversible, ie., not usable for // replace: roleToLiftTo = TeamModel.getRoleToLiftTo(this.scope, baseParam, roleParam, false, location); } if (roleToLiftTo != null) { // success by translation methodSpec.argNeedsTranslation[j] = true; this.roleMethodSpec.argNeedsTranslation[j] = true; this.roleMethodSpec.parameters[j] = roleToLiftTo; // this applies to all bindings // still need to check for ambiguity/abstract role: ReferenceBinding enclosingTeam = this.scope.enclosingSourceType().enclosingType(); int iProblem = enclosingTeam .getTeamModel() .canLiftingFail((ReferenceBinding) roleToLiftTo.leafComponentType()); if (iProblem > 0) addRoleLiftingProblem((ReferenceBinding) roleToLiftTo.leafComponentType(), iProblem); continue; } // check auto(un)boxing: if (this.scope.isBoxingCompatibleWith(baseLeaf, roleLeaf)) continue; if (roleParam instanceof ReferenceBinding) { ReferenceBinding roleRef = (ReferenceBinding) roleParam; if (roleRef.isRole() && roleRef.baseclass() != null) { this.scope .problemReporter() .typeMismatchErrorPotentialLift( location, baseParam, roleParam, roleRef.baseclass()); hasReportedError = true; continue; } } // no compatibility detected: this.scope .problemReporter() .incompatibleMappedArgument( baseParam, roleParam, this.roleMethodSpec, j, /*callout*/ false); hasReportedError = true; } finally { if (hasReportedError) this.binding.tagBits |= TagBits.HasMappingIncompatibility; // regardless of continue, check this last because it is the least precise message: if (!hasReportedError && baseLeaf.isCompatibleWith(roleLeaf)) { if (isReplaceCallin() && !isTypeVariable) { boolean twowayCompatible = compatibilityViaBaseAnchor ? RoleTypeCreator.isCompatibleViaBaseAnchor( this.scope, baseLeaf, roleLeaf, TokenNameBINDOUT) : roleLeaf.isCompatibleWith(baseLeaf); if (!twowayCompatible) { // requires two-way compatibility (see additional paragraph in 4.5(d)) this.scope .problemReporter() .typesNotTwowayCompatibleInReplace(baseParam, roleParam, location, j); } } } } } } return true; // unused in the callin case }
static boolean isEqual( org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding2, HashSet visitedTypes) { if (typeBinding == typeBinding2) return true; if (typeBinding == null || typeBinding2 == null) return false; switch (typeBinding.kind()) { case Binding.BASE_TYPE: if (!typeBinding2.isBaseType()) { return false; } return typeBinding.id == typeBinding2.id; case Binding.ARRAY_TYPE: if (!typeBinding2.isArrayType()) { return false; } return typeBinding.dimensions() == typeBinding2.dimensions() && isEqual( typeBinding.leafComponentType(), typeBinding2.leafComponentType(), visitedTypes); case Binding.PARAMETERIZED_TYPE: if (!typeBinding2.isParameterizedType()) { return false; } ParameterizedTypeBinding parameterizedTypeBinding = (ParameterizedTypeBinding) typeBinding; ParameterizedTypeBinding parameterizedTypeBinding2 = (ParameterizedTypeBinding) typeBinding2; return CharOperation.equals( parameterizedTypeBinding.compoundName, parameterizedTypeBinding2.compoundName) && (parameterizedTypeBinding.modifiers & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) == (parameterizedTypeBinding2.modifiers & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) && isEqual( parameterizedTypeBinding.arguments, parameterizedTypeBinding2.arguments, visitedTypes) && isEqual( parameterizedTypeBinding.enclosingType(), parameterizedTypeBinding2.enclosingType(), visitedTypes); case Binding.WILDCARD_TYPE: if (typeBinding2.kind() != Binding.WILDCARD_TYPE) { return false; } WildcardBinding wildcardBinding = (WildcardBinding) typeBinding; WildcardBinding wildcardBinding2 = (WildcardBinding) typeBinding2; return isEqual(wildcardBinding.bound, wildcardBinding2.bound, visitedTypes) && wildcardBinding.boundKind == wildcardBinding2.boundKind; case Binding.INTERSECTION_TYPE: if (typeBinding2.kind() != Binding.INTERSECTION_TYPE) { return false; } WildcardBinding intersectionBinding = (WildcardBinding) typeBinding; WildcardBinding intersectionBinding2 = (WildcardBinding) typeBinding2; return isEqual(intersectionBinding.bound, intersectionBinding2.bound, visitedTypes) && isEqual( intersectionBinding.otherBounds, intersectionBinding2.otherBounds, visitedTypes); case Binding.TYPE_PARAMETER: if (!(typeBinding2.isTypeVariable())) { return false; } if (typeBinding.isCapture()) { if (!(typeBinding2.isCapture())) { return false; } CaptureBinding captureBinding = (CaptureBinding) typeBinding; CaptureBinding captureBinding2 = (CaptureBinding) typeBinding2; if (captureBinding.position == captureBinding2.position) { if (visitedTypes.contains(typeBinding)) return true; visitedTypes.add(typeBinding); return isEqual(captureBinding.wildcard, captureBinding2.wildcard, visitedTypes) && isEqual(captureBinding.sourceType, captureBinding2.sourceType, visitedTypes); } return false; } TypeVariableBinding typeVariableBinding = (TypeVariableBinding) typeBinding; TypeVariableBinding typeVariableBinding2 = (TypeVariableBinding) typeBinding2; if (CharOperation.equals(typeVariableBinding.sourceName, typeVariableBinding2.sourceName)) { if (visitedTypes.contains(typeBinding)) return true; visitedTypes.add(typeBinding); return isEqual( typeVariableBinding.declaringElement, typeVariableBinding2.declaringElement, visitedTypes) && isEqual( typeVariableBinding.superclass(), typeVariableBinding2.superclass(), visitedTypes) && isEqual( typeVariableBinding.superInterfaces(), typeVariableBinding2.superInterfaces(), visitedTypes); } return false; case Binding.GENERIC_TYPE: if (!typeBinding2.isGenericType()) { return false; } ReferenceBinding referenceBinding = (ReferenceBinding) typeBinding; ReferenceBinding referenceBinding2 = (ReferenceBinding) typeBinding2; return CharOperation.equals(referenceBinding.compoundName, referenceBinding2.compoundName) && (referenceBinding.modifiers & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) == (referenceBinding2.modifiers & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) && isEqual( referenceBinding.typeVariables(), referenceBinding2.typeVariables(), visitedTypes) && isEqual( referenceBinding.enclosingType(), referenceBinding2.enclosingType(), visitedTypes); case Binding.RAW_TYPE: default: if (!(typeBinding2 instanceof ReferenceBinding)) { return false; } referenceBinding = (ReferenceBinding) typeBinding; referenceBinding2 = (ReferenceBinding) typeBinding2; char[] constantPoolName = referenceBinding.constantPoolName(); char[] constantPoolName2 = referenceBinding2.constantPoolName(); // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=116833 if (constantPoolName == null) { if (constantPoolName2 != null) { return false; } if (!CharOperation.equals( referenceBinding.computeUniqueKey(), referenceBinding2.computeUniqueKey())) { return false; } } else { if (constantPoolName2 == null) { return false; } if (!CharOperation.equals(constantPoolName, constantPoolName2)) { return false; } } return CharOperation.equals(referenceBinding.compoundName, referenceBinding2.compoundName) && (!referenceBinding2.isGenericType()) && (referenceBinding.isRawType() == referenceBinding2.isRawType()) && ((referenceBinding.modifiers & ~ClassFileConstants.AccSuper) & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) == ((referenceBinding2.modifiers & ~ClassFileConstants.AccSuper) & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) && isEqual( referenceBinding.enclosingType(), referenceBinding2.enclosingType(), visitedTypes); } }
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; }