public TypeBinding resolveType(BlockScope scope) {
    // compute a new constant if the cast is effective

    this.constant = Constant.NotAConstant;
    this.implicitConversion = TypeIds.T_undefined;

    boolean exprContainCast = false;

    TypeBinding castType = this.resolvedType = this.type.resolveType(scope);
    if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) {
      this.expression.setExpressionContext(CASTING_CONTEXT);
      if (this.expression instanceof FunctionalExpression) {
        this.expression.setExpectedType(this.resolvedType);
        this.bits |= ASTNode.DisableUnnecessaryCastCheck;
      }
    }
    if (this.expression instanceof CastExpression) {
      this.expression.bits |= ASTNode.DisableUnnecessaryCastCheck;
      exprContainCast = true;
    }
    TypeBinding expressionType = this.expression.resolveType(scope);
    if (this.expression instanceof MessageSend) {
      MessageSend messageSend = (MessageSend) this.expression;
      MethodBinding methodBinding = messageSend.binding;
      if (methodBinding != null && methodBinding.isPolymorphic()) {
        messageSend.binding =
            scope
                .environment()
                .updatePolymorphicMethodReturnType(
                    (PolymorphicMethodBinding) methodBinding, castType);
        if (TypeBinding.notEquals(expressionType, castType)) {
          expressionType = castType;
          this.bits |= ASTNode.DisableUnnecessaryCastCheck;
        }
      }
    }
    if (castType != null) {
      if (expressionType != null) {

        boolean nullAnnotationMismatch =
            scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled
                && NullAnnotationMatching.analyse(castType, expressionType, -1).isAnyMismatch();

        boolean isLegal =
            checkCastTypesCompatibility(scope, castType, expressionType, this.expression);
        if (isLegal) {
          this.expression.computeConversion(scope, castType, expressionType);
          if ((this.bits & ASTNode.UnsafeCast) != 0) { // unsafe cast
            if (scope.compilerOptions().reportUnavoidableGenericTypeProblems
                || !(expressionType.isRawType()
                    && this.expression.forcedToBeRaw(scope.referenceContext()))) {
              scope.problemReporter().unsafeCast(this, scope);
            }
          } else if (nullAnnotationMismatch) {
            // report null annotation issue at medium priority
            scope.problemReporter().unsafeNullnessCast(this, scope);
          } else {
            if (castType.isRawType()
                && scope.compilerOptions().getSeverity(CompilerOptions.RawTypeReference)
                    != ProblemSeverities.Ignore) {
              scope.problemReporter().rawTypeReference(this.type, castType);
            }
            if ((this.bits & (ASTNode.UnnecessaryCast | ASTNode.DisableUnnecessaryCastCheck))
                == ASTNode.UnnecessaryCast) { // unnecessary cast
              if (!isIndirectlyUsed()) // used for generic type inference or boxing ?
              scope.problemReporter().unnecessaryCast(this);
            }
          }
        } else { // illegal cast
          if ((castType.tagBits & TagBits.HasMissingType) == 0) { // no complaint if secondary error
            scope.problemReporter().typeCastError(this, castType, expressionType);
          }
          this.bits |= ASTNode.DisableUnnecessaryCastCheck; // disable further secondary diagnosis
        }
      }
      this.resolvedType =
          castType.capture(
              scope,
              this.type.sourceStart,
              this.type
                  .sourceEnd); // make it unique, a cast expression shares source end with the
                               // expression.
      if (exprContainCast) {
        checkNeedForCastCast(scope, this);
      }
    }
    return this.resolvedType;
  }
示例#2
0
  public static TypeBinding resolveType(
      TypeBinding resolvedType, MessageSend methodCall, BlockScope scope) {
    List<Extension> extensions = new ArrayList<Extension>();
    TypeDeclaration decl = scope.classScope().referenceContext;

    EclipseNode owningType = null;

    for (EclipseNode typeNode = getTypeNode(decl);
        typeNode != null;
        typeNode = upToType(typeNode)) {
      Annotation ann = getAnnotation(ExtensionMethod.class, typeNode);
      if (ann != null) {
        extensions.addAll(
            0, getApplicableExtensionMethods(typeNode, ann, methodCall.receiver.resolvedType));
        if (owningType == null) owningType = typeNode;
      }
    }

    boolean skip = false;

    if (methodCall.receiver instanceof ThisReference
        && (((ThisReference) methodCall.receiver).bits & ASTNode.IsImplicitThis) != 0) skip = true;
    if (methodCall.receiver instanceof SuperReference) skip = true;
    if (methodCall.receiver instanceof NameReference) {
      Binding binding = ((NameReference) methodCall.receiver).binding;
      if (binding instanceof TypeBinding) skip = true;
    }

    if (!skip)
      for (Extension extension : extensions) {
        if (!extension.suppressBaseMethods && !(methodCall.binding instanceof ProblemMethodBinding))
          continue;
        for (MethodBinding extensionMethod : extension.extensionMethods) {
          if (!Arrays.equals(methodCall.selector, extensionMethod.selector)) continue;
          MessageSend_postponedErrors.clear(methodCall);
          if (methodCall.receiver instanceof ThisReference) {
            methodCall.receiver.bits &= ~ASTNode.IsImplicitThis;
          }
          List<Expression> arguments = new ArrayList<Expression>();
          arguments.add(methodCall.receiver);
          if (methodCall.arguments != null) arguments.addAll(Arrays.asList(methodCall.arguments));
          List<TypeBinding> argumentTypes = new ArrayList<TypeBinding>();
          for (Expression argument : arguments) {
            if (argument.resolvedType != null) argumentTypes.add(argument.resolvedType);
            // TODO: Instead of just skipping nulls entirely, there is probably a 'unresolved type'
            // placeholder. THAT is what we ought to be adding here!
          }
          Expression[] originalArgs = methodCall.arguments;
          methodCall.arguments = arguments.toArray(new Expression[0]);
          MethodBinding fixedBinding =
              scope.getMethod(
                  extensionMethod.declaringClass,
                  methodCall.selector,
                  argumentTypes.toArray(new TypeBinding[0]),
                  methodCall);
          if (fixedBinding instanceof ProblemMethodBinding) {
            methodCall.arguments = originalArgs;
            if (fixedBinding.declaringClass != null) {
              scope.problemReporter().invalidMethod(methodCall, fixedBinding);
            }
          } else {
            for (int i = 0, iend = arguments.size(); i < iend; i++) {
              Expression arg = arguments.get(i);
              if (fixedBinding.parameters[i].isArrayType() != arg.resolvedType.isArrayType()) break;
              if (arg instanceof MessageSend) {
                ((MessageSend) arg).valueCast = arg.resolvedType;
              }
              if (!fixedBinding.parameters[i].isBaseType() && arg.resolvedType.isBaseType()) {
                int id = arg.resolvedType.id;
                arg.implicitConversion = TypeIds.BOXING | (id + (id << 4)); // magic see TypeIds
              } else if (fixedBinding.parameters[i].isBaseType()
                  && !arg.resolvedType.isBaseType()) {
                int id = fixedBinding.parameters[i].id;
                arg.implicitConversion = TypeIds.UNBOXING | (id + (id << 4)); // magic see TypeIds
              }
            }

            methodCall.receiver = createNameRef(extensionMethod.declaringClass, methodCall);
            methodCall.actualReceiverType = extensionMethod.declaringClass;
            methodCall.binding = fixedBinding;
            methodCall.resolvedType = methodCall.binding.returnType;
          }
          return methodCall.resolvedType;
        }
      }

    PostponedError error = MessageSend_postponedErrors.get(methodCall);
    if (error != null) error.fire();

    MessageSend_postponedErrors.clear(methodCall);
    return resolvedType;
  }