/** * 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); } }
/** * 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); } }
private static List<MethodBinding> getApplicableExtensionMethodsDefinedInProvider( EclipseNode typeNode, ReferenceBinding extensionMethodProviderBinding, TypeBinding receiverType) { List<MethodBinding> extensionMethods = new ArrayList<MethodBinding>(); CompilationUnitScope cuScope = ((CompilationUnitDeclaration) typeNode.top().get()).scope; for (MethodBinding method : extensionMethodProviderBinding.methods()) { if (!method.isStatic()) continue; if (!method.isPublic()) continue; if (method.parameters == null || method.parameters.length == 0) continue; TypeBinding firstArgType = method.parameters[0]; if (receiverType.isProvablyDistinct(firstArgType) && !receiverType.isCompatibleWith(firstArgType.erasure())) continue; TypeBinding[] argumentTypes = Arrays.copyOfRange(method.parameters, 1, method.parameters.length); if ((receiverType instanceof ReferenceBinding) && ((ReferenceBinding) receiverType) .getExactMethod(method.selector, argumentTypes, cuScope) != null) continue; extensionMethods.add(method); } return extensionMethods; }
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]); } } } }
/** Analysing arguments of MessageSend, ExplicitConstructorCall, AllocationExpression. */ protected void analyseArguments( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, MethodBinding methodBinding, Expression[] arguments) { // compare actual null-status against parameter annotations of the called method: if (arguments != null) { CompilerOptions compilerOptions = currentScope.compilerOptions(); boolean considerTypeAnnotations = compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8 && compilerOptions.isAnnotationBasedNullAnalysisEnabled; boolean hasJDK15NullAnnotations = methodBinding.parameterNonNullness != null; int numParamsToCheck = methodBinding.parameters.length; if (considerTypeAnnotations || hasJDK15NullAnnotations) { // check if varargs need special treatment: boolean passThrough = false; if (methodBinding.isVarargs()) { int varArgPos = numParamsToCheck - 1; // this if-block essentially copied from generateArguments(..): if (numParamsToCheck == arguments.length) { TypeBinding varArgsType = methodBinding.parameters[varArgPos]; TypeBinding lastType = arguments[varArgPos].resolvedType; if (lastType == TypeBinding.NULL || (varArgsType.dimensions() == lastType.dimensions() && lastType.isCompatibleWith(varArgsType))) passThrough = true; // pass directly as-is } if (!passThrough) numParamsToCheck--; // with non-passthrough varargs last param is fed from individual // args -> don't check } } if (considerTypeAnnotations) { for (int i = 0; i < numParamsToCheck; i++) { TypeBinding expectedType = methodBinding.parameters[i]; Expression argument = arguments[i]; // prefer check based on type annotations: int severity = findNullTypeAnnotationMismatch(expectedType, argument.resolvedType); if (severity > 0) { // immediate reporting: currentScope .problemReporter() .nullityMismatchingTypeAnnotation( argument, argument.resolvedType, expectedType, severity == 1, currentScope.environment()); // next check flow-based null status against null JDK15-style annotations: } else if (hasJDK15NullAnnotations && methodBinding.parameterNonNullness[i] == Boolean.TRUE) { int nullStatus = argument.nullStatus( flowInfo, flowContext); // slight loss of precision: should also use the null info from // the receiver. if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided flowContext.recordNullityMismatch( currentScope, argument, argument.resolvedType, expectedType, nullStatus); } } } else if (hasJDK15NullAnnotations) { for (int i = 0; i < numParamsToCheck; i++) { if (methodBinding.parameterNonNullness[i] == Boolean.TRUE) { TypeBinding expectedType = methodBinding.parameters[i]; Expression argument = arguments[i]; int nullStatus = argument.nullStatus( flowInfo, flowContext); // slight loss of precision: should also use the null info from // the receiver. if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided flowContext.recordNullityMismatch( currentScope, argument, argument.resolvedType, expectedType, nullStatus); } } } } }
/** Generate invocation arguments, considering varargs methods */ public void generateArguments( MethodBinding binding, Expression[] arguments, BlockScope currentScope, CodeStream codeStream) { if (binding.isVarargs()) { // 5 possibilities exist for a call to the vararg method foo(int i, int ... value) : // foo(1), foo(1, null), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new int[] {1, 2}) TypeBinding[] params = binding.parameters; int paramLength = params.length; int varArgIndex = paramLength - 1; for (int i = 0; i < varArgIndex; i++) { arguments[i].generateCode(currentScope, codeStream, true); } ArrayBinding varArgsType = (ArrayBinding) params[varArgIndex]; // parameterType has to be an array type ArrayBinding codeGenVarArgsType = (ArrayBinding) binding.parameters[varArgIndex].erasure(); int elementsTypeID = varArgsType.elementsType().id; int argLength = arguments == null ? 0 : arguments.length; if (argLength > paramLength) { // right number but not directly compatible or too many arguments - wrap extra into array // called with (argLength - lastIndex) elements : foo(1, 2) or foo(1, 2, 3, 4) // need to gen elements into an array, then gen each remaining element into created array codeStream.generateInlinedValue(argLength - varArgIndex); codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array for (int i = varArgIndex; i < argLength; i++) { codeStream.dup(); codeStream.generateInlinedValue(i - varArgIndex); arguments[i].generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } } else if (argLength == paramLength) { // right number of arguments - could be inexact - pass argument as is TypeBinding lastType = arguments[varArgIndex].resolvedType; if (lastType == TypeBinding.NULL || (varArgsType.dimensions() == lastType.dimensions() && lastType.isCompatibleWith(varArgsType))) { // foo(1, new int[]{2, 3}) or foo(1, null) --> last arg is passed as-is arguments[varArgIndex].generateCode(currentScope, codeStream, true); } else { // right number but not directly compatible or too many arguments - wrap extra into array // need to gen elements into an array, then gen each remaining element into created array codeStream.generateInlinedValue(1); codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array codeStream.dup(); codeStream.generateInlinedValue(0); arguments[varArgIndex].generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } } else { // not enough arguments - pass extra empty array // scenario: foo(1) --> foo(1, new int[0]) // generate code for an empty array of parameterType codeStream.generateInlinedValue(0); codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array } } else if (arguments != null) { // standard generation for method arguments for (int i = 0, max = arguments.length; i < max; i++) arguments[i].generateCode(currentScope, codeStream, 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 }
public int boundCheck(Substitution var1, TypeBinding var2) { if (var2 != TypeBinding.field_187 && var2 != this) { boolean var3 = var1 != null; if (!(var2 instanceof ReferenceBinding) && !var2.method_147()) { return 2; } else if (this.superclass == null) { return 0; } else { TypeBinding var8; if (var2.kind() != 516) { boolean var14 = false; if (this.superclass.id != 1) { Object var15 = var3 ? Scope.substitute(var1, this.superclass) : this.superclass; if (var15 != var2) { if (!var2.isCompatibleWith((TypeBinding) var15)) { return 2; } TypeBinding var18 = var2.method_140((TypeBinding) var15); if (var18 != null && var18.method_166() && ((TypeBinding) var15).method_149()) { var14 = true; } } } int var16 = 0; for (int var17 = this.superInterfaces.length; var16 < var17; ++var16) { Object var19 = var3 ? Scope.substitute(var1, this.superInterfaces[var16]) : this.superInterfaces[var16]; if (var19 != var2) { if (!var2.isCompatibleWith((TypeBinding) var19)) { return 2; } var8 = var2.method_140((TypeBinding) var19); if (var8 != null && var8.method_166() && ((TypeBinding) var19).method_149()) { var14 = true; } } } return var14 ? 1 : 0; } else { WildcardBinding var4 = (WildcardBinding) var2; switch (var4.field_215) { case 1: TypeBinding var5 = var4.bound; if (var5 == this) { return 0; } else { ReferenceBinding var6 = var3 ? (ReferenceBinding) Scope.substitute(var1, this.superclass) : this.superclass; boolean var7 = var5.method_147(); if (!var5.method_157() && var6.id != 1) { if (var7) { if (!var5.isCompatibleWith(var6)) { return 2; } } else { var8 = var5.method_140(var6); if (var8 != null) { if (var6.method_164(var8)) { return 2; } } else { var8 = var6.method_140(var5); if (var8 != null) { if (var8.method_164(var5)) { return 2; } } else if (!var5.method_169() && !var6.method_169()) { return 2; } } } } ReferenceBinding[] var20 = var3 ? Scope.substitute(var1, this.superInterfaces) : this.superInterfaces; int var9 = var20.length; boolean var10 = var7 || ((ReferenceBinding) var5).method_221(); for (int var11 = 0; var11 < var9; ++var11) { ReferenceBinding var12 = var20[var11]; if (var7) { if (!var5.isCompatibleWith(var12)) { return 2; } } else { TypeBinding var13 = var5.method_140(var12); if (var13 != null) { if (var12.method_164(var13)) { return 2; } } else if (var10) { return 2; } } } } case 0: default: return 0; case 2: return this.boundCheck(var1, var4.bound); } } } } else { return 0; } }
public void resolve(MethodScope var1) { if ((this.field_446 & 16) == 0) { if (this.binding != null && this.binding.isValidBinding()) { this.field_446 |= 16; ClassScope var2 = var1.method_582(); if (var2 != null) { label338: { SourceTypeBinding var3 = var2.enclosingSourceType(); if (var3.superclass != null) { FieldBinding var4 = var2.findField(var3.superclass, this.name, this, false); if (var4 != null && var4.isValidBinding()) { label334: { if (var4 instanceof FieldBinding) { FieldBinding var5 = (FieldBinding) var4; if (var5.original() == this.binding || !var5.canBeSeenBy(var3, this, var1)) { break label334; } } var1.problemReporter().fieldHiding(this, var4); break label338; } } } Scope var13 = var2.parent; if (var13.kind != 4) { Binding var15 = var13.getBinding(this.name, 3, this, false); if (var15 != null && var15.isValidBinding() && var15 != this.binding) { label323: { if (var15 instanceof FieldBinding) { FieldBinding var6 = (FieldBinding) var15; if (var6.original() == this.binding || !var6.method_431() && var3.method_226()) { break label323; } } var1.problemReporter().fieldHiding(this, var15); } } } } } if (this.type != null) { this.type.resolvedType = this.binding.type; } FieldBinding var12 = var1.initializedField; int var14 = var1.field_407; try { var1.initializedField = this.binding; var1.field_407 = this.binding.field_304; method_761(var1, this.annotations, this.binding); if ((this.binding.getAnnotationTagBits() & 70368744177664L) == 0L && (this.binding.field_300 & 1048576) != 0 && var1.compilerOptions().field_1928 >= 3211264L) { var1.problemReporter().method_1675(this); } if (this.initialization == null) { this.binding.setConstant(Constant.NotAConstant); } else { this.binding.setConstant(Constant.NotAConstant); TypeBinding var17 = this.binding.type; this.initialization.setExpectedType(var17); TypeBinding var18; if (this.initialization instanceof ArrayInitializer) { if ((var18 = this.initialization.resolveTypeExpecting(var1, var17)) != null) { ((ArrayInitializer) this.initialization).binding = (ArrayBinding) var18; this.initialization.computeConversion(var1, var17, var18); } } else if ((var18 = this.initialization.resolveType(var1)) != null) { if (var17 != var18) { var1.compilationUnitScope().recordTypeConversion(var17, var18); } if (!this.initialization.isConstantValueOfTypeAssignableToType(var18, var17) && (!var17.method_148() || !BaseTypeBinding.method_185(var17.id, var18.id)) && !var18.isCompatibleWith(var17)) { if (!var1.isBoxingCompatibleWith(var18, var17) && (!var18.method_148() || var1.compilerOptions().field_1928 < 3211264L || var17.method_148() || !this.initialization.isConstantValueOfTypeAssignableToType( var18, var1.environment().method_486(var17)))) { if ((var17.tagBits & 128L) == 0L) { var1.problemReporter() .typeMismatchError(var18, var17, this.initialization, (ASTNode) null); } } else { this.initialization.computeConversion(var1, var17, var18); if (this.initialization instanceof CastExpression && (this.initialization.field_446 & 16384) == 0) { CastExpression.checkNeedForAssignedCast( var1, var17, (CastExpression) this.initialization); } } } else { this.initialization.computeConversion(var1, var17, var18); if (var18.method_174(var17)) { var1.problemReporter().method_1806(this.initialization, var18, var17); } if (this.initialization instanceof CastExpression && (this.initialization.field_446 & 16384) == 0) { CastExpression.checkNeedForAssignedCast( var1, var17, (CastExpression) this.initialization); } } if (this.binding.method_409()) { this.binding.setConstant( this.initialization.constant.castTo( (this.binding.type.id << 4) + this.initialization.constant.typeID())); } } else { this.binding.setConstant(Constant.NotAConstant); } if (this.binding == Assignment.method_944(this.initialization)) { var1.problemReporter().assignmentHasNoEffect(this, this.name); } } if (this.binding != null && this.binding.declaringClass != null && !this.binding.declaringClass.method_158()) { int var16 = this.binding.field_300 & 7; ProblemReporter var19 = var1.problemReporter(); int var7 = var19.computeSeverity(-1610612250); if (var7 != -1) { if (var2 != null) { var16 = Util.computeOuterMostVisibility(var2.referenceType(), var16); } int var8 = this.binding.field_300 & -8 | var16; } } } finally { var1.initializedField = var12; var1.field_407 = var14; if (this.binding.constant() == null) { this.binding.setConstant(Constant.NotAConstant); } } } } }
public TypeBinding resolveType(BlockScope scope) { // added for code assist...cannot occur with 'normal' code if (this.anonymousType == null && this.enclosingInstance == null) { return super.resolveType(scope); } // Propagate the type checking to the arguments, and checks if the constructor is defined. // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' // ClassBodyopt // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' // ClassBodyopt this.constant = Constant.NotAConstant; TypeBinding enclosingInstanceType = null; ReferenceBinding enclosingInstanceReference = null; TypeBinding receiverType = null; boolean hasError = false; boolean enclosingInstanceContainsCast = false; boolean argsContainCast = false; if (this.enclosingInstance != null) { if (this.enclosingInstance instanceof CastExpression) { this.enclosingInstance.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on enclosingInstanceContainsCast = true; } if ((enclosingInstanceType = this.enclosingInstance.resolveType(scope)) == null) { hasError = true; } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) { scope .problemReporter() .illegalPrimitiveOrArrayTypeForEnclosingInstance( enclosingInstanceType, this.enclosingInstance); hasError = true; } else if (this.type instanceof QualifiedTypeReference) { scope .problemReporter() .illegalUsageOfQualifiedTypeReference((QualifiedTypeReference) this.type); hasError = true; } else if (!(enclosingInstanceReference = (ReferenceBinding) enclosingInstanceType) .canBeSeenBy(scope)) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=317212 enclosingInstanceType = new ProblemReferenceBinding( enclosingInstanceReference.compoundName, enclosingInstanceReference, ProblemReasons.NotVisible); scope.problemReporter().invalidType(this.enclosingInstance, enclosingInstanceType); hasError = true; } else { receiverType = ((SingleTypeReference) this.type) .resolveTypeEnclosing(scope, (ReferenceBinding) enclosingInstanceType); if (receiverType != null && enclosingInstanceContainsCast) { CastExpression.checkNeedForEnclosingInstanceCast( scope, this.enclosingInstance, enclosingInstanceType, receiverType); } } } else { if (this.type == null) { // initialization of an enum constant receiverType = scope.enclosingSourceType(); } else { receiverType = this.type.resolveType(scope, true /* check bounds*/); checkParameterizedAllocation: { if (receiverType == null || !receiverType.isValidBinding()) break checkParameterizedAllocation; if (this.type instanceof ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>() ReferenceBinding currentType = (ReferenceBinding) receiverType; do { // isStatic() is answering true for toplevel types if ((currentType.modifiers & ClassFileConstants.AccStatic) != 0) break checkParameterizedAllocation; if (currentType.isRawType()) break checkParameterizedAllocation; } while ((currentType = currentType.enclosingType()) != null); ParameterizedQualifiedTypeReference qRef = (ParameterizedQualifiedTypeReference) this.type; for (int i = qRef.typeArguments.length - 2; i >= 0; i--) { if (qRef.typeArguments[i] != null) { scope .problemReporter() .illegalQualifiedParameterizedTypeAllocation(this.type, receiverType); break; } } } } } } if (receiverType == null || !receiverType.isValidBinding()) { hasError = true; } // resolve type arguments (for generic constructor call) final boolean isDiamond = this.type != null && (this.type.bits & ASTNode.IsDiamond) != 0; if (this.typeArguments != null) { int length = this.typeArguments.length; boolean argHasError = scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5; this.genericTypeArguments = new TypeBinding[length]; for (int i = 0; i < length; i++) { TypeReference typeReference = this.typeArguments[i]; if ((this.genericTypeArguments[i] = typeReference.resolveType(scope, true /* check bounds*/)) == null) { argHasError = true; } if (argHasError && typeReference instanceof Wildcard) { scope.problemReporter().illegalUsageOfWildcard(typeReference); } } if (isDiamond) { scope.problemReporter().diamondNotWithExplicitTypeArguments(this.typeArguments); return null; } if (argHasError) { if (this.arguments != null) { // still attempt to resolve arguments for (int i = 0, max = this.arguments.length; i < max; i++) { this.arguments[i].resolveType(scope); } } return null; } } // will check for null after args are resolved TypeBinding[] argumentTypes = Binding.NO_PARAMETERS; if (this.arguments != null) { int length = this.arguments.length; argumentTypes = new TypeBinding[length]; for (int i = 0; i < length; i++) { Expression argument = this.arguments[i]; if (argument instanceof CastExpression) { argument.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on argsContainCast = true; } if ((argumentTypes[i] = argument.resolveType(scope)) == null) { hasError = true; } } } // limit of fault-tolerance if (hasError) { /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=345359, if arguments have errors, completely bail out in the <> case. No meaningful type resolution is possible since inference of the elided types is fully tied to argument types. Do not return the partially resolved type. */ if (isDiamond) { return null; // not the partially cooked this.resolvedType } if (receiverType instanceof ReferenceBinding) { ReferenceBinding referenceReceiver = (ReferenceBinding) receiverType; if (receiverType.isValidBinding()) { // record a best guess, for clients who need hint about possible contructor match int length = this.arguments == null ? 0 : this.arguments.length; TypeBinding[] pseudoArgs = new TypeBinding[length]; for (int i = length; --i >= 0; ) { pseudoArgs[i] = argumentTypes[i] == null ? TypeBinding.NULL : argumentTypes[i]; // replace args with errors with null type } this.binding = scope.findMethod(referenceReceiver, TypeConstants.INIT, pseudoArgs, this); if (this.binding != null && !this.binding.isValidBinding()) { MethodBinding closestMatch = ((ProblemMethodBinding) this.binding).closestMatch; // record the closest match, for clients who may still need hint about possible method // match if (closestMatch != null) { if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method // shouldn't return generic method outside its context, rather convert it to raw // method (175409) closestMatch = scope .environment() .createParameterizedGenericMethod( closestMatch.original(), (RawTypeBinding) null); } this.binding = closestMatch; MethodBinding closestMatchOriginal = closestMatch.original(); if (closestMatchOriginal.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(closestMatchOriginal)) { // ignore cases where method is used from within inside itself (e.g. direct // recursions) closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; } } } } if (this.anonymousType != null) { // insert anonymous type in scope (see // https://bugs.eclipse.org/bugs/show_bug.cgi?id=210070) scope.addAnonymousType(this.anonymousType, referenceReceiver); this.anonymousType.resolve(scope); return this.resolvedType = this.anonymousType.binding; } } return this.resolvedType = receiverType; } if (this.anonymousType == null) { // qualified allocation with no anonymous type if (!receiverType.canBeInstantiated()) { scope.problemReporter().cannotInstantiate(this.type, receiverType); return this.resolvedType = receiverType; } if (isDiamond) { TypeBinding[] inferredTypes = inferElidedTypes( ((ParameterizedTypeBinding) receiverType).genericType(), receiverType.enclosingType(), argumentTypes, scope); if (inferredTypes == null) { scope.problemReporter().cannotInferElidedTypes(this); return this.resolvedType = null; } receiverType = this.type.resolvedType = scope .environment() .createParameterizedType( ((ParameterizedTypeBinding) receiverType).genericType(), inferredTypes, ((ParameterizedTypeBinding) receiverType).enclosingType()); } ReferenceBinding allocationType = (ReferenceBinding) receiverType; if ((this.binding = scope.getConstructor(allocationType, argumentTypes, this)) .isValidBinding()) { if (isMethodUseDeprecated(this.binding, scope, true)) { scope.problemReporter().deprecatedMethod(this.binding, this); } if (checkInvocationArguments( scope, null, allocationType, this.binding, this.arguments, argumentTypes, argsContainCast, this)) { this.bits |= ASTNode.Unchecked; } if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) { scope .problemReporter() .unnecessaryTypeArgumentsForMethodInvocation( this.binding, this.genericTypeArguments, this.typeArguments); } } else { if (this.binding.declaringClass == null) { this.binding.declaringClass = allocationType; } if (this.type != null && !this.type.resolvedType.isValidBinding()) { // problem already got signaled on type reference, do not report secondary problem return null; } scope.problemReporter().invalidConstructor(this, this.binding); return this.resolvedType = receiverType; } if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { scope.problemReporter().missingTypeInConstructor(this, this.binding); } if (!isDiamond && receiverType.isParameterizedTypeWithActualArguments()) { checkTypeArgumentRedundancy( (ParameterizedTypeBinding) receiverType, receiverType.enclosingType(), argumentTypes, scope); } // The enclosing instance must be compatible with the innermost enclosing type ReferenceBinding expectedType = this.binding.declaringClass.enclosingType(); if (expectedType != enclosingInstanceType) // must call before computeConversion() and typeMismatchError() scope.compilationUnitScope().recordTypeConversion(expectedType, enclosingInstanceType); if (enclosingInstanceType.isCompatibleWith(expectedType) || scope.isBoxingCompatibleWith(enclosingInstanceType, expectedType)) { this.enclosingInstance.computeConversion(scope, expectedType, enclosingInstanceType); return this.resolvedType = receiverType; } scope .problemReporter() .typeMismatchError(enclosingInstanceType, expectedType, this.enclosingInstance, null); return this.resolvedType = receiverType; } else { if (isDiamond) { scope.problemReporter().diamondNotWithAnoymousClasses(this.type); return null; } } ReferenceBinding superType = (ReferenceBinding) receiverType; if (superType.isTypeVariable()) { superType = new ProblemReferenceBinding( new char[][] {superType.sourceName()}, superType, ProblemReasons.IllegalSuperTypeVariable); scope.problemReporter().invalidType(this, superType); return null; } else if (this.type != null && superType.isEnum()) { // tolerate enum constant body scope.problemReporter().cannotInstantiate(this.type, superType); return this.resolvedType = superType; } // anonymous type scenario // an anonymous class inherits from java.lang.Object when declared "after" an interface ReferenceBinding anonymousSuperclass = superType.isInterface() ? scope.getJavaLangObject() : superType; // insert anonymous type in scope scope.addAnonymousType(this.anonymousType, superType); this.anonymousType.resolve(scope); // find anonymous super constructor this.resolvedType = this.anonymousType.binding; // 1.2 change if ((this.resolvedType.tagBits & TagBits.HierarchyHasProblems) != 0) { return null; // stop secondary errors } MethodBinding inheritedBinding = scope.getConstructor(anonymousSuperclass, argumentTypes, this); if (!inheritedBinding.isValidBinding()) { if (inheritedBinding.declaringClass == null) { inheritedBinding.declaringClass = anonymousSuperclass; } if (this.type != null && !this.type.resolvedType.isValidBinding()) { // problem already got signaled on type reference, do not report secondary problem return null; } scope.problemReporter().invalidConstructor(this, inheritedBinding); return this.resolvedType; } if ((inheritedBinding.tagBits & TagBits.HasMissingType) != 0) { scope.problemReporter().missingTypeInConstructor(this, inheritedBinding); } if (this.enclosingInstance != null) { ReferenceBinding targetEnclosing = inheritedBinding.declaringClass.enclosingType(); if (targetEnclosing == null) { scope .problemReporter() .unnecessaryEnclosingInstanceSpecification(this.enclosingInstance, superType); return this.resolvedType; } else if (!enclosingInstanceType.isCompatibleWith(targetEnclosing) && !scope.isBoxingCompatibleWith(enclosingInstanceType, targetEnclosing)) { scope .problemReporter() .typeMismatchError( enclosingInstanceType, targetEnclosing, this.enclosingInstance, null); return this.resolvedType; } this.enclosingInstance.computeConversion(scope, targetEnclosing, enclosingInstanceType); } if (this.arguments != null) { if (checkInvocationArguments( scope, null, anonymousSuperclass, inheritedBinding, this.arguments, argumentTypes, argsContainCast, this)) { this.bits |= ASTNode.Unchecked; } } if (this.typeArguments != null && inheritedBinding.original().typeVariables == Binding.NO_TYPE_VARIABLES) { scope .problemReporter() .unnecessaryTypeArgumentsForMethodInvocation( inheritedBinding, this.genericTypeArguments, this.typeArguments); } // Update the anonymous inner class : superclass, interface this.binding = this.anonymousType.createDefaultConstructorWithBinding( inheritedBinding, (this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null); return this.resolvedType; }
public static boolean checkInvocationArguments( BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding method, Expression[] arguments, TypeBinding[] argumentTypes, boolean argsContainCast, InvocationSite invocationSite) { TypeBinding[] params = method.parameters; int paramLength = params.length; boolean isRawMemberInvocation = !method.isStatic() && !receiverType.isUnboundWildcard() && method.declaringClass.isRawType() && method.hasSubstitutedParameters(); boolean uncheckedBoundCheck = (method.tagBits & TagBits.HasUncheckedTypeArgumentForBoundCheck) != 0; MethodBinding rawOriginalGenericMethod = null; if (!isRawMemberInvocation) { if (method instanceof ParameterizedGenericMethodBinding) { ParameterizedGenericMethodBinding paramMethod = (ParameterizedGenericMethodBinding) method; if (paramMethod.isRaw && method.hasSubstitutedParameters()) { rawOriginalGenericMethod = method.original(); } } } int invocationStatus = INVOCATION_ARGUMENT_OK; if (arguments == null) { if (method.isVarargs()) { TypeBinding parameterType = ((ArrayBinding) params[paramLength - 1]) .elementsType(); // no element was supplied for vararg parameter if (!parameterType.isReifiable()) { scope .problemReporter() .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite); } } } else { if (method.isVarargs()) { // 4 possibilities exist for a call to the vararg method foo(int i, long ... value) : // foo(1), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new long[] {1, 2}) int lastIndex = paramLength - 1; for (int i = 0; i < lastIndex; i++) { TypeBinding originalRawParam = rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i]; invocationStatus |= checkInvocationArgument( scope, arguments[i], params[i], argumentTypes[i], originalRawParam); } int argLength = arguments.length; if (lastIndex < argLength) { // vararg argument was provided TypeBinding parameterType = params[lastIndex]; TypeBinding originalRawParam = null; if (paramLength != argLength || parameterType.dimensions() != argumentTypes[lastIndex].dimensions()) { parameterType = ((ArrayBinding) parameterType) .elementsType(); // single element was provided for vararg parameter if (!parameterType.isReifiable()) { scope .problemReporter() .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite); } originalRawParam = rawOriginalGenericMethod == null ? null : ((ArrayBinding) rawOriginalGenericMethod.parameters[lastIndex]) .elementsType(); } for (int i = lastIndex; i < argLength; i++) { invocationStatus |= checkInvocationArgument( scope, arguments[i], parameterType, argumentTypes[i], originalRawParam); } } if (paramLength == argLength) { // 70056 int varargsIndex = paramLength - 1; ArrayBinding varargsType = (ArrayBinding) params[varargsIndex]; TypeBinding lastArgType = argumentTypes[varargsIndex]; int dimensions; if (lastArgType == TypeBinding.NULL) { if (!(varargsType.leafComponentType().isBaseType() && varargsType.dimensions() == 1)) scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); } else if (varargsType.dimensions <= (dimensions = lastArgType.dimensions())) { if (lastArgType.leafComponentType().isBaseType()) { dimensions--; } if (varargsType.dimensions < dimensions) { scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); } else if (varargsType.dimensions == dimensions && lastArgType != varargsType && lastArgType.leafComponentType().erasure() != varargsType.leafComponentType.erasure() && lastArgType.isCompatibleWith(varargsType.elementsType()) && lastArgType.isCompatibleWith(varargsType)) { scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); } } } } else { for (int i = 0; i < paramLength; i++) { TypeBinding originalRawParam = rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i]; invocationStatus |= checkInvocationArgument( scope, arguments[i], params[i], argumentTypes[i], originalRawParam); } } if (argsContainCast) { CastExpression.checkNeedForArgumentCasts( scope, receiver, receiverType, method, arguments, argumentTypes, invocationSite); } } if ((invocationStatus & INVOCATION_ARGUMENT_WILDCARD) != 0) { scope .problemReporter() .wildcardInvocation((ASTNode) invocationSite, receiverType, method, argumentTypes); } else if (!method.isStatic() && !receiverType.isUnboundWildcard() && method.declaringClass.isRawType() && method.hasSubstitutedParameters()) { scope.problemReporter().unsafeRawInvocation((ASTNode) invocationSite, method); } else if (rawOriginalGenericMethod != null || uncheckedBoundCheck || ((invocationStatus & INVOCATION_ARGUMENT_UNCHECKED) != 0 && method instanceof ParameterizedGenericMethodBinding /*&& method.returnType != scope.environment().convertToRawType(method.returnType.erasure(), true)*/ )) { scope .problemReporter() .unsafeRawGenericMethodInvocation((ASTNode) invocationSite, method, argumentTypes); return true; } return false; }
public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) { // Array initializers can only occur on the right hand side of an assignment // expression, therefore the expected type contains the valid information // concerning the type that must be enforced by the elements of the array initializer. // this method is recursive... (the test on isArrayType is the stop case) this.constant = Constant.NotAConstant; if (expectedType instanceof ArrayBinding) { // allow new List<?>[5] if ((this.bits & IsAnnotationDefaultValue) == 0) { // annotation default value need only to be commensurate JLS9.7 // allow new List<?>[5] - only check for generic array when no initializer, since also // checked inside initializer resolution TypeBinding leafComponentType = expectedType.leafComponentType(); if (!leafComponentType.isReifiable()) { scope.problemReporter().illegalGenericArray(leafComponentType, this); } } this.resolvedType = this.binding = (ArrayBinding) expectedType; if (this.expressions == null) return this.binding; TypeBinding elementType = this.binding.elementsType(); for (int i = 0, length = this.expressions.length; i < length; i++) { Expression expression = this.expressions[i]; expression.setExpectedType(elementType); TypeBinding expressionType = expression instanceof ArrayInitializer ? expression.resolveTypeExpecting(scope, elementType) : expression.resolveType(scope); if (expressionType == null) continue; // Compile-time conversion required? if (elementType != expressionType) // must call before computeConversion() and typeMismatchError() scope.compilationUnitScope().recordTypeConversion(elementType, expressionType); if (expression.isConstantValueOfTypeAssignableToType(expressionType, elementType) || expressionType.isCompatibleWith(elementType)) { expression.computeConversion(scope, elementType, expressionType); } else if (scope.isBoxingCompatibleWith(expressionType, elementType) || (expressionType.isBaseType() // narrowing then boxing ? && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing && !elementType.isBaseType() && expression.isConstantValueOfTypeAssignableToType( expressionType, scope.environment().computeBoxingType(elementType)))) { expression.computeConversion(scope, elementType, expressionType); } else { scope.problemReporter().typeMismatchError(expressionType, elementType, expression, null); } } return this.binding; } // infer initializer type for error reporting based on first element TypeBinding leafElementType = null; int dim = 1; if (this.expressions == null) { leafElementType = scope.getJavaLangObject(); } else { Expression expression = this.expressions[0]; while (expression != null && expression instanceof ArrayInitializer) { dim++; Expression[] subExprs = ((ArrayInitializer) expression).expressions; if (subExprs == null) { leafElementType = scope.getJavaLangObject(); expression = null; break; } expression = ((ArrayInitializer) expression).expressions[0]; } if (expression != null) { leafElementType = expression.resolveType(scope); } // fault-tolerance - resolve other expressions as well for (int i = 1, length = this.expressions.length; i < length; i++) { expression = this.expressions[i]; if (expression != null) { expression.resolveType(scope); } } } if (leafElementType != null) { this.resolvedType = scope.createArrayType(leafElementType, dim); if (expectedType != null) scope.problemReporter().typeMismatchError(this.resolvedType, expectedType, this, null); } return null; }