public void resolve(BlockScope scope) { if (this.expression != null) { if (this.expression.resolveType(scope) != null) { TypeBinding javaLangClass = scope.getJavaLangClass(); if (!javaLangClass.isValidBinding()) { scope .problemReporter() .codeSnippetMissingClass( "java.lang.Class", this.sourceStart, this.sourceEnd); // $NON-NLS-1$ return; } TypeBinding javaLangObject = scope.getJavaLangObject(); if (!javaLangObject.isValidBinding()) { scope .problemReporter() .codeSnippetMissingClass( "java.lang.Object", this.sourceStart, this.sourceEnd); // $NON-NLS-1$ return; } TypeBinding[] argumentTypes = new TypeBinding[] {javaLangObject, javaLangClass}; this.setResultMethod = scope.getImplicitMethod(SETRESULT_SELECTOR, argumentTypes, this); if (!this.setResultMethod.isValidBinding()) { scope .problemReporter() .codeSnippetMissingMethod( ROOT_FULL_CLASS_NAME, new String(SETRESULT_SELECTOR), new String(SETRESULT_ARGUMENTS), this.sourceStart, this.sourceEnd); return; } // in constant case, the implicit conversion cannot be left uninitialized if (this.expression.constant != Constant.NotAConstant) { // fake 'no implicit conversion' (the return type is always void) this.expression.implicitConversion = this.expression.constant.typeID() << 4; } } } }
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]); } } } }
public TypeBinding resolveType(BlockScope scope) { // Answer the signature return type // Base type promotion this.constant = Constant.NotAConstant; boolean receiverCast = false, argsContainCast = false; if (this.receiver instanceof CastExpression) { this.receiver.bits |= DisableUnnecessaryCastCheck; // will check later on receiverCast = true; } this.actualReceiverType = this.receiver.resolveType(scope); if (receiverCast && this.actualReceiverType != null) { // due to change of declaring class with receiver type, only identity cast should be notified if (((CastExpression) this.receiver).expression.resolvedType == this.actualReceiverType) { scope.problemReporter().unnecessaryCast((CastExpression) this.receiver); } } // resolve type arguments (for generic constructor call) if (this.typeArguments != null) { int length = this.typeArguments.length; boolean argHasError = false; // typeChecks all arguments this.genericTypeArguments = new TypeBinding[length]; for (int i = 0; i < length; i++) { if ((this.genericTypeArguments[i] = this.typeArguments[i].resolveType(scope, true /* check bounds*/)) == null) { argHasError = true; } } if (argHasError) { return null; } } // will check for null after args are resolved TypeBinding[] argumentTypes = Binding.NO_PARAMETERS; if (this.arguments != null) { boolean argHasError = false; // typeChecks all arguments 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 |= DisableUnnecessaryCastCheck; // will check later on argsContainCast = true; } if ((argumentTypes[i] = this.arguments[i].resolveType(scope)) == null) argHasError = true; } if (argHasError) { if (this.actualReceiverType instanceof ReferenceBinding) { // record any selector match, for clients who may still need hint about possible method // match this.binding = scope.findMethod( (ReferenceBinding) this.actualReceiverType, this.selector, new TypeBinding[] {}, this); } return null; } } if (this.actualReceiverType == null) { return null; } // base type cannot receive any message if (this.actualReceiverType.isBaseType()) { scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes); return null; } this.binding = this.receiver.isImplicitThis() ? scope.getImplicitMethod(this.selector, argumentTypes, this) : scope.getMethod(this.actualReceiverType, this.selector, argumentTypes, this); if (!this.binding.isValidBinding()) { if (this.binding instanceof ProblemMethodBinding && ((ProblemMethodBinding) this.binding).problemId() == ProblemReasons.NotVisible) { if (this.evaluationContext.declaringTypeName != null) { this.delegateThis = scope.getField(scope.enclosingSourceType(), EvaluationConstants.DELEGATE_THIS, this); if (this.delegateThis == null) { // if not found then internal error, field should have been found this.constant = Constant.NotAConstant; scope.problemReporter().invalidMethod(this, this.binding); return null; } } else { this.constant = Constant.NotAConstant; scope.problemReporter().invalidMethod(this, this.binding); return null; } CodeSnippetScope localScope = new CodeSnippetScope(scope); MethodBinding privateBinding = this.receiver instanceof CodeSnippetThisReference && ((CodeSnippetThisReference) this.receiver).isImplicit ? localScope.getImplicitMethod( (ReferenceBinding) this.delegateThis.type, this.selector, argumentTypes, this) : localScope.getMethod(this.delegateThis.type, this.selector, argumentTypes, this); if (!privateBinding.isValidBinding()) { if (this.binding.declaringClass == null) { if (this.actualReceiverType instanceof ReferenceBinding) { this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType; } else { // really bad error .... scope .problemReporter() .errorNoMethodFor(this, this.actualReceiverType, argumentTypes); return null; } } scope.problemReporter().invalidMethod(this, this.binding); return null; } else { this.binding = privateBinding; } } else { if (this.binding.declaringClass == null) { if (this.actualReceiverType instanceof ReferenceBinding) { this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType; } else { // really bad error .... scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes); return null; } } scope.problemReporter().invalidMethod(this, this.binding); return null; } } if (!this.binding.isStatic()) { // the "receiver" must not be a type, in other words, a NameReference that the TC has bound to // a Type if (this.receiver instanceof NameReference && (((NameReference) this.receiver).bits & Binding.TYPE) != 0) { scope.problemReporter().mustUseAStaticMethod(this, this.binding); } else { // handle indirect inheritance thru variable secondary bound // receiver may receive generic cast, as part of implicit conversion TypeBinding oldReceiverType = this.actualReceiverType; this.actualReceiverType = this.actualReceiverType.getErasureCompatibleType(this.binding.declaringClass); this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType); if (this.actualReceiverType != oldReceiverType && this.receiver.postConversionType(scope) != this .actualReceiverType) { // record need for explicit cast at codegen since // receiver could not handle it this.bits |= NeedReceiverGenericCast; } } } if (checkInvocationArguments( scope, this.receiver, this.actualReceiverType, this.binding, this.arguments, argumentTypes, argsContainCast, this)) { this.bits |= ASTNode.Unchecked; } // -------message send that are known to fail at compile time----------- if (this.binding.isAbstract()) { if (this.receiver.isSuper()) { scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding); } // abstract private methods cannot occur nor abstract static............ } if (isMethodUseDeprecated(this.binding, scope, true)) scope.problemReporter().deprecatedMethod(this.binding, this); // from 1.5 compliance on, array#clone() returns the array type (but binding still shows Object) if (this.actualReceiverType.isArrayType() && this.binding.parameters == Binding.NO_PARAMETERS && scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5 && CharOperation.equals(this.binding.selector, CLONE)) { this.resolvedType = this.actualReceiverType; } else { TypeBinding returnType = this.binding.returnType; if (returnType != null) { if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) { returnType = scope.environment().convertToRawType(returnType.erasure(), true); } returnType = returnType.capture(scope, this.sourceEnd); } this.resolvedType = returnType; } return this.resolvedType; }
public TypeBinding resolveType(BlockScope scope) { // Answer the signature return type // Base type promotion this.constant = Constant.NotAConstant; boolean receiverCast = false, argsContainCast = false; if (this.receiver instanceof CastExpression) { this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on receiverCast = true; } this.actualReceiverType = this.receiver.resolveType(scope); boolean receiverIsType = this.receiver instanceof NameReference && (((NameReference) this.receiver).bits & Binding.TYPE) != 0; if (receiverCast && this.actualReceiverType != null) { // due to change of declaring class with receiver type, only identity cast should be notified if (((CastExpression) this.receiver).expression.resolvedType == this.actualReceiverType) { scope.problemReporter().unnecessaryCast((CastExpression) this.receiver); } } // resolve type arguments (for generic constructor call) if (this.typeArguments != null) { int length = this.typeArguments.length; boolean argHasError = scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5; // typeChecks all arguments 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 (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) { boolean argHasError = false; // typeChecks all arguments 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) { argHasError = true; } } if (argHasError) { if (this.actualReceiverType instanceof ReferenceBinding) { // record a best guess, for clients who need hint about possible method match 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 = this.receiver.isImplicitThis() ? scope.getImplicitMethod(this.selector, pseudoArgs, this) : scope.findMethod( (ReferenceBinding) this.actualReceiverType, this.selector, 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; } } } } return null; } } if (this.actualReceiverType == null) { return null; } // base type cannot receive any message if (this.actualReceiverType.isBaseType()) { scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes); return null; } this.binding = this.receiver.isImplicitThis() ? scope.getImplicitMethod(this.selector, argumentTypes, this) : scope.getMethod(this.actualReceiverType, this.selector, argumentTypes, this); if (!this.binding.isValidBinding()) { if (this.binding.declaringClass == null) { if (this.actualReceiverType instanceof ReferenceBinding) { this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType; } else { scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes); return null; } } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=245007 avoid secondary errors in case of // missing super type for anonymous classes ... ReferenceBinding declaringClass = this.binding.declaringClass; boolean avoidSecondary = declaringClass != null && declaringClass.isAnonymousType() && declaringClass.superclass() instanceof MissingTypeBinding; if (!avoidSecondary) scope.problemReporter().invalidMethod(this, this.binding); MethodBinding closestMatch = ((ProblemMethodBinding) this.binding).closestMatch; switch (this.binding.problemId()) { case ProblemReasons.Ambiguous: break; // no resilience on ambiguous case ProblemReasons.NotVisible: case ProblemReasons.NonStaticReferenceInConstructorInvocation: case ProblemReasons.NonStaticReferenceInStaticContext: case ProblemReasons.ReceiverTypeNotVisible: case ProblemReasons.ParameterBoundMismatch: // only steal returnType in cases listed above if (closestMatch != null) this.resolvedType = closestMatch.returnType; break; } // record the closest match, for clients who may still need hint about possible method match if (closestMatch != 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; } } return (this.resolvedType != null && (this.resolvedType.tagBits & TagBits.HasMissingType) == 0) ? this.resolvedType : null; } final CompilerOptions compilerOptions = scope.compilerOptions(); if (compilerOptions.complianceLevel <= ClassFileConstants.JDK1_6 && this.binding.isPolymorphic()) { scope.problemReporter().polymorphicMethodNotBelow17(this); return null; } if (((this.bits & ASTNode.InsideExpressionStatement) != 0) && this.binding.isPolymorphic()) { // we only set the return type to be void if this method invocation is used inside an // expression statement this.binding = scope .environment() .updatePolymorphicMethodReturnType( (PolymorphicMethodBinding) this.binding, TypeBinding.VOID); } if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { scope.problemReporter().missingTypeInMethod(this, this.binding); } if (!this.binding.isStatic()) { // the "receiver" must not be a type if (receiverIsType) { scope.problemReporter().mustUseAStaticMethod(this, this.binding); if (this.actualReceiverType.isRawType() && (this.receiver.bits & ASTNode.IgnoreRawTypeCheck) == 0 && compilerOptions.getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore) { scope.problemReporter().rawTypeReference(this.receiver, this.actualReceiverType); } } else { // handle indirect inheritance thru variable secondary bound // receiver may receive generic cast, as part of implicit conversion TypeBinding oldReceiverType = this.actualReceiverType; this.actualReceiverType = this.actualReceiverType.getErasureCompatibleType(this.binding.declaringClass); this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType); if (this.actualReceiverType != oldReceiverType && this.receiver.postConversionType(scope) != this .actualReceiverType) { // record need for explicit cast at codegen since // receiver could not handle it this.bits |= NeedReceiverGenericCast; } } } else { // static message invoked through receiver? legal but unoptimal (optional warning). if (!(this.receiver.isImplicitThis() || this.receiver.isSuper() || receiverIsType)) { scope.problemReporter().nonStaticAccessToStaticMethod(this, this.binding); } if (!this.receiver.isImplicitThis() && this.binding.declaringClass != this.actualReceiverType) { scope.problemReporter().indirectAccessToStaticMethod(this, this.binding); } } if (checkInvocationArguments( scope, this.receiver, this.actualReceiverType, this.binding, this.arguments, argumentTypes, argsContainCast, this)) { this.bits |= ASTNode.Unchecked; } // -------message send that are known to fail at compile time----------- if (this.binding.isAbstract()) { if (this.receiver.isSuper()) { scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding); } // abstract private methods cannot occur nor abstract static............ } if (isMethodUseDeprecated(this.binding, scope, true)) scope.problemReporter().deprecatedMethod(this.binding, this); // from 1.5 source level on, array#clone() returns the array type (but binding still shows // Object) if (this.binding == scope.environment().arrayClone && compilerOptions.sourceLevel >= ClassFileConstants.JDK1_5) { this.resolvedType = this.actualReceiverType; } else { TypeBinding returnType; if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=277643, align with javac on JLS 15.12.2.6 returnType = this.binding.returnType; if (returnType != null) { returnType = scope.environment().convertToRawType(returnType.erasure(), true); } } else { returnType = this.binding.returnType; if (returnType != null) { returnType = returnType.capture(scope, this.sourceEnd); } } this.resolvedType = returnType; } if (this.receiver.isSuper() && compilerOptions.getSeverity(CompilerOptions.OverridingMethodWithoutSuperInvocation) != ProblemSeverities.Ignore) { final ReferenceContext referenceContext = scope.methodScope().referenceContext; if (referenceContext instanceof AbstractMethodDeclaration) { final AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) referenceContext; MethodBinding enclosingMethodBinding = abstractMethodDeclaration.binding; if (enclosingMethodBinding.isOverriding() && CharOperation.equals(this.binding.selector, enclosingMethodBinding.selector) && this.binding.areParametersEqual(enclosingMethodBinding)) { abstractMethodDeclaration.bits |= ASTNode.OverridingMethodWithSupercall; } } } if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) { scope .problemReporter() .unnecessaryTypeArgumentsForMethodInvocation( this.binding, this.genericTypeArguments, this.typeArguments); } return (this.resolvedType.tagBits & TagBits.HasMissingType) == 0 ? this.resolvedType : null; }