/** * This method is used by {@link * org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.CallinMethodMappingsAttribute * CallinMethodMappingsAttribute} for decoding a mapping from its bytecode attribute. * * @param method * @return the bytecode level signature of the given method (yet retrenched) */ public static char[] signature(MethodBinding method, WeavingScheme weavingScheme) { StringBuffer buffer = new StringBuffer(); buffer.append('('); // synthetic args for static role method? MethodBinding orig = method.copyInheritanceSrc != null ? method.copyInheritanceSrc : method; // normalize to copyInhSrc so reading a callin-attr. from bytes can more // easily find the method if (weavingScheme == WeavingScheme.OTDRE && orig.declaringClass.isRole() && orig.isStatic()) { buffer.append('I'); buffer.append(String.valueOf(orig.declaringClass.enclosingType().signature())); } // manual retrenching? boolean shouldRetrench = weavingScheme == WeavingScheme.OTRE && method.isCallin(); int offset = shouldRetrench ? MethodSignatureEnhancer.getEnhancingArgLen(weavingScheme) : 0; int paramLen = method.parameters.length; for (int i = offset; i < paramLen; i++) { // 'weaken' to that erasure that was used in the tsuper version: TypeBinding targetParameter = method.getCodeGenType(i); buffer.append(targetParameter.signature()); } buffer.append(')'); TypeBinding sourceReturnType = shouldRetrench ? MethodModel.getReturnType(method) : method.returnType; // 'weaken' to that erasure that was used in the tsuper version: MethodBinding tsuperOriginal = (method.tagBits & TagBits.IsCopyOfParameterized) != 0 ? method.copyInheritanceSrc.original() : null; TypeBinding returnType = (tsuperOriginal != null && tsuperOriginal.returnType.isTypeVariable() && !sourceReturnType.isTypeVariable()) ? tsuperOriginal.returnType : sourceReturnType; if (returnType.isTypeVariable() && method instanceof ParameterizedGenericMethodBinding) returnType = ((ParameterizedGenericMethodBinding) method) .reverseSubstitute((TypeVariableBinding) returnType); buffer.append(returnType.erasure().signature()); int nameLength = buffer.length(); char[] signature = new char[nameLength]; buffer.getChars(0, nameLength, signature, 0); return signature; }
/** * 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; }