예제 #1
0
  /**
   * If 'hasSignature' check the return type of the bound method against the declared return type.
   */
  public boolean checkRoleReturnType(CallinCalloutScope scope, boolean isCallout) {
    TypeBinding methodReturn = boundMethodReturnType();
    TypeBinding resolvedReturnType = this.returnType.resolvedType;
    TypeBinding firstBound = null;
    if (resolvedReturnType.isTypeVariable()) {
      firstBound = ((TypeVariableBinding) resolvedReturnType).firstBound;

      // if declared return type is a type variable, so must the return type of the resolved method:
      if (!isMethodReturnTypeVariable(this.resolvedMethod)) {
        scope.problemReporter().differentReturnInMethodSpec(this, /*isCallout*/ false);
        return false;
      }
    }
    // the role side of a callout may indeed refine the return type
    // of its inherited role method:
    if (isCallout) if (this.returnType.resolvedType.isCompatibleWith(methodReturn)) return true;
    // in other cases types have to be identical:
    if (!MethodModel.hasUnboundedReturnType(
            this.resolvedMethod) // unbounded type variable always matches
        && !TypeAnalyzer.isSameType(scope.enclosingSourceType(), resolvedReturnType, methodReturn)
        && !TypeAnalyzer.isSameType(scope.enclosingSourceType(), firstBound, methodReturn)) {
      scope
          .problemReporter()
          .differentReturnInMethodSpec(
              this, ((AbstractMethodMappingDeclaration) scope.referenceContext).isCallout());
      return false;
    }
    return true;
  }
예제 #2
0
  /**
   * If 'hasSignature' check the return type of the bound method against the declared return type.
   */
  public boolean checkBaseReturnType(CallinCalloutScope scope, int bindDir) {
    TypeBinding methodReturn = boundMethodReturnType();
    if (!TypeAnalyzer.isSameType(
        scope.enclosingSourceType(), this.returnType.resolvedType, methodReturn)) {
      if (RoleTypeCreator.isCompatibleViaBaseAnchor(
          scope, methodReturn, this.returnType.resolvedType, bindDir)) return true;

      if ((methodReturn.tagBits & TagBits.HasMissingType) == 0)
        scope
            .problemReporter()
            .differentReturnInMethodSpec(
                this, ((AbstractMethodMappingDeclaration) scope.referenceContext).isCallout());
      return false;
    }
    return true;
  }
예제 #3
0
 /**
  * If 'hasSignature' check the parameter types of the bound method against the declared parameter
  * types.
  */
 public boolean checkParameterTypes(CallinCalloutScope scope, boolean isBase) {
   // retrieve (un-enhanced) parameters from the actual resolved method:
   TypeBinding[] realParameters = this.resolvedMethod.getSourceParameters();
   for (int i = 0; i < realParameters.length; i++) {
     TypeReference specifiedArgType = this.arguments[i].type;
     TypeBinding realParameter = realParameters[i];
     if (!realParameter.isValidBinding() || specifiedArgType.resolvedType == null) continue;
     ReferenceBinding baseclass = scope.enclosingReceiverType().baseclass();
     if (isBase && baseclass != null && baseclass.isTeam() && realParameter.isRole())
       realParameter = TeamModel.strengthenRoleType(baseclass, realParameter);
     if (!TypeAnalyzer.isSameType(
         scope.enclosingSourceType(), specifiedArgType.resolvedType, realParameter)) {
       scope
           .problemReporter()
           .differentParamInMethodSpec(
               this,
               specifiedArgType,
               realParameter,
               ((AbstractMethodMappingDeclaration) scope.referenceContext).isCallout());
       return false;
     }
   }
   return true;
 }
예제 #4
0
  /**
   * 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;
  }