public void resolveMethodSpecs( RoleModel role, ReferenceBinding baseType, boolean resolveBaseMethods) { super.resolveMethodSpecs(role, baseType, resolveBaseMethods); if (this.roleMethodSpec.isValid() && this.roleMethodSpec.isStatic()) if (this.predicate != null) makeMethodStatic(this.predicate); if (!resolveBaseMethods) return; MethodBinding[] baseMethods = new MethodBinding[this.baseMethodSpecs.length]; for (int i = 0; i < this.baseMethodSpecs.length; i++) { if (this.baseMethodSpecs[i].resolvedMethod != null) { baseMethods[i] = this.baseMethodSpecs[i].resolvedMethod; if (isDangerousMethod(baseMethods[i])) this.scope.problemReporter().dangerousCallinBinding(this.baseMethodSpecs[i]); } else { MethodSpec spec = this.baseMethodSpecs[i]; baseMethods[i] = new ProblemMethodBinding(spec.selector, null, baseType, 0); } } for (MethodBinding aBaseMethod : baseMethods) { if (aBaseMethod.isValidBinding() && aBaseMethod.returnType != TypeBinding.VOID) { if (this.callinModifier == TerminalTokens.TokenNameafter && this.roleMethodSpec.isValid() && this.roleMethodSpec.resolvedType() != TypeBinding.VOID) this.scope.problemReporter().ignoringRoleMethodReturn(this.roleMethodSpec); break; } } this.binding._baseMethods = baseMethods; }
public TypeBinding resolveType(BlockScope scope) { TypeBinding type = super.resolveType(scope); if (type instanceof PolyTypeBinding) return type; MethodBinding method = getMethodBinding(); if (method != null && method.isValidBinding() && !method.isSynthetic()) throw new SelectionNodeFound(this.actualMethodBinding); throw new SelectionNodeFound(); }
public TypeBinding[] inferElidedTypes( ReferenceBinding allocationType, ReferenceBinding enclosingType, TypeBinding[] argumentTypes, final BlockScope scope) { /* Given the allocation type and the arguments to the constructor, see if we can synthesize a generic static factory method that would, given the argument types and the invocation site, manufacture a parameterized object of type allocationType. If we are successful then by design and construction, the parameterization of the return type of the factory method is identical to the types elided in the <>. */ MethodBinding factory = scope.getStaticFactory(allocationType, enclosingType, argumentTypes, this); if (factory instanceof ParameterizedGenericMethodBinding && factory.isValidBinding()) { ParameterizedGenericMethodBinding genericFactory = (ParameterizedGenericMethodBinding) factory; this.inferredReturnType = genericFactory.inferredReturnType; return ((ParameterizedTypeBinding) factory.returnType).arguments; } return null; }
protected int matchMethod(MethodBinding method, boolean skipImpossibleArg) { if (!matchesName(this.pattern.selector, method.selector)) return IMPOSSIBLE_MATCH; int level = ACCURATE_MATCH; // look at return type only if declaring type is not specified if (this.pattern.declaringSimpleName == null) { // TODO (frederic) use this call to refine accuracy on return type // int newLevel = resolveLevelForType(this.pattern.returnSimpleName, // this.pattern.returnQualification, this.pattern.returnTypeArguments, 0, method.returnType); int newLevel = resolveLevelForType( this.pattern.returnSimpleName, this.pattern.returnQualification, method.returnType); if (level > newLevel) { if (newLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH; level = newLevel; // can only be downgraded } } // parameter types int parameterCount = this.pattern.parameterSimpleNames == null ? -1 : this.pattern.parameterSimpleNames.length; if (parameterCount > -1) { // global verification if (method.parameters == null) return INACCURATE_MATCH; if (parameterCount != method.parameters.length) return IMPOSSIBLE_MATCH; if (!method.isValidBinding() && ((ProblemMethodBinding) method).problemId() == ProblemReasons.Ambiguous) { // return inaccurate match for ambiguous call (bug 80890) return INACCURATE_MATCH; } // verify each parameter for (int i = 0; i < parameterCount; i++) { TypeBinding argType = method.parameters[i]; int newLevel = IMPOSSIBLE_MATCH; if (argType.isMemberType()) { // only compare source name for member type (bug 41018) newLevel = CharOperation.match( this.pattern.parameterSimpleNames[i], argType.sourceName(), this.isCaseSensitive) ? ACCURATE_MATCH : IMPOSSIBLE_MATCH; } else { // TODO (frederic) use this call to refine accuracy on parameter types // newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i], // this.pattern.parameterQualifications[i], this.pattern.parametersTypeArguments[i], 0, // argType); newLevel = resolveLevelForType( this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i], argType); } if (level > newLevel) { if (newLevel == IMPOSSIBLE_MATCH) { if (skipImpossibleArg) { // Do not consider match as impossible while finding declarations and source level >= // 1.5 // (see bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990, 96761, 96763) newLevel = level; } else { return IMPOSSIBLE_MATCH; } } level = newLevel; // can only be downgraded } } } return level; }
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 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; }
/** * Resolve the method or field (see FieldAccessSpec). * * @param receiverType receiver of the method call. * @param scope * @param callinExpected whether this method spec is the LHS of a replace callin. * @param isBaseSide whether this method spec is the RHS (any binding kind) * @param allowEnclosing whether a method may be found in an enclosing type of receiverType * @return the resolved method (may be problem method) or null */ public MethodBinding resolveFeature( ReferenceBinding receiverType, BlockScope scope, boolean callinExpected, boolean isBaseSide, boolean allowEnclosing) { // getRealClass() is used, because decapsulation needs to find private methods, // which for roles are found only in the class part. ReferenceBinding receiverClass = receiverType.getRealClass(); boolean isConstructorSpec = CharOperation.equals(this.selector, receiverClass.sourceName()); char[] realSelector = isConstructorSpec ? TypeConstants.INIT : this.selector; if (this.hasSignature) { TypeBinding[] enhancedParameters = this.parameters; // first chance: try enhanced: enhancedParameters = MethodSignatureEnhancer.enhanceParameters(scope, this.parameters); CompilationResult compilationResult = scope.referenceContext().compilationResult(); CheckPoint cp = compilationResult.getCheckPoint(scope.referenceContext()); this.resolvedMethod = TypeAnalyzer.findMethod( scope, receiverClass, realSelector, enhancedParameters, isBaseSide, isBaseSide ? this : null); if (!this.resolvedMethod.isValidBinding() && this.resolvedMethod.problemId() == ProblemReasons.NotFound) { // second+ chance: try plain: while (receiverClass != null) { compilationResult.rollBack(cp); MethodBinding plainMethod = TypeAnalyzer.findMethod( scope, receiverClass, realSelector, this.parameters, isBaseSide, isBaseSide ? this : null); if (!callinExpected) { this.resolvedMethod = plainMethod; } else { if (plainMethod != null && plainMethod.isValidBinding()) scope.problemReporter().replaceMappingToNonCallin(this, plainMethod); // mark the ProblemMethodBinding consistently to what we have been looking for last: this.resolvedMethod.modifiers |= ExtraCompilerModifiers.AccCallin | ClassFileConstants.AccStatic; } if (plainMethod != null && plainMethod.isValidBinding()) break; if (allowEnclosing) receiverClass = receiverClass.enclosingType(); else receiverClass = null; } } } else { CompilationResult compilationResult = scope.referenceContext().compilationResult(); CheckPoint cp = compilationResult.getCheckPoint(scope.referenceContext()); while (receiverClass != null) { this.resolvedMethod = receiverClass.getMethod(scope, realSelector); if (this.resolvedMethod != null && this.resolvedMethod.isValidBinding()) break; // good if (!allowEnclosing) break; // bad compilationResult.rollBack(cp); receiverClass = receiverClass.enclosingType(); } } if (this.resolvedMethod != null) { if (this.resolvedMethod.isValidBinding()) { // check visibility of role-side in callin: if (!isBaseSide && scope.referenceContext() instanceof CallinMappingDeclaration && !this.resolvedMethod.canBeSeenBy(this, scope)) { scope.problemReporter().invisibleMethod(this, this.resolvedMethod); this.resolvedMethod = new ProblemMethodBinding( this.resolvedMethod, this.selector, this.parameters, ProblemReasons.NotVisible); } } if (!this.resolvedMethod.isValidBinding() && this.resolvedMethod.declaringClass == null) this.resolvedMethod.declaringClass = receiverClass; // needed for computeUniqueKey (via // CallinCalloutBinding.computeUniqueKey) } return this.resolvedMethod; }