Пример #1
0
  /**
   * Complain if assigned expression is cast, but not actually used as such, e.g. Object o = (List)
   * object;
   */
  public static void checkNeedForAssignedCast(
      BlockScope scope, TypeBinding expectedType, CastExpression rhs) {
    if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck)
        == ProblemSeverities.Ignore) return;

    TypeBinding castedExpressionType = rhs.expression.resolvedType;
    //	int i = (byte) n; // cast still had side effect
    // double d = (float) n; // cast to float is unnecessary
    if (castedExpressionType == null || rhs.resolvedType.isBaseType()) return;
    // if (castedExpressionType.id == T_null) return; // tolerate null expression cast
    if (castedExpressionType.isCompatibleWith(expectedType)) {
      scope.problemReporter().unnecessaryCast(rhs);
    }
  }
Пример #2
0
  /**
   * Complain if assigned expression is cast, but not actually used as such, e.g. Object o = (List)
   * object;
   */
  public static void checkNeedForAssignedCast(
      BlockScope scope, TypeBinding expectedType, CastExpression rhs) {
    CompilerOptions compilerOptions = scope.compilerOptions();
    if (compilerOptions.getSeverity(CompilerOptions.UnnecessaryTypeCheck)
        == ProblemSeverities.Ignore) return;

    TypeBinding castedExpressionType = rhs.expression.resolvedType;
    //	int i = (byte) n; // cast still had side effect
    // double d = (float) n; // cast to float is unnecessary
    if (castedExpressionType == null || rhs.resolvedType.isBaseType()) return;
    // if (castedExpressionType.id == T_null) return; // tolerate null expression cast
    if (castedExpressionType.isCompatibleWith(expectedType, scope)) {
      if (scope.environment().usesNullTypeAnnotations()) {
        // are null annotations compatible, too?
        if (NullAnnotationMatching.analyse(expectedType, castedExpressionType, -1).isAnyMismatch())
          return; // already reported unchecked cast (nullness), say no more.
      }
      scope.problemReporter().unnecessaryCast(rhs);
    }
  }
Пример #3
0
  private static List<MethodBinding> getApplicableExtensionMethodsDefinedInProvider(
      EclipseNode typeNode,
      ReferenceBinding extensionMethodProviderBinding,
      TypeBinding receiverType) {

    List<MethodBinding> extensionMethods = new ArrayList<MethodBinding>();
    CompilationUnitScope cuScope = ((CompilationUnitDeclaration) typeNode.top().get()).scope;
    for (MethodBinding method : extensionMethodProviderBinding.methods()) {
      if (!method.isStatic()) continue;
      if (!method.isPublic()) continue;
      if (method.parameters == null || method.parameters.length == 0) continue;
      TypeBinding firstArgType = method.parameters[0];
      if (receiverType.isProvablyDistinct(firstArgType)
          && !receiverType.isCompatibleWith(firstArgType.erasure())) continue;
      TypeBinding[] argumentTypes =
          Arrays.copyOfRange(method.parameters, 1, method.parameters.length);
      if ((receiverType instanceof ReferenceBinding)
          && ((ReferenceBinding) receiverType)
                  .getExactMethod(method.selector, argumentTypes, cuScope)
              != null) continue;
      extensionMethods.add(method);
    }
    return extensionMethods;
  }
Пример #4
0
  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]);
        }
      }
    }
  }
Пример #5
0
 /** Analysing arguments of MessageSend, ExplicitConstructorCall, AllocationExpression. */
 protected void analyseArguments(
     BlockScope currentScope,
     FlowContext flowContext,
     FlowInfo flowInfo,
     MethodBinding methodBinding,
     Expression[] arguments) {
   // compare actual null-status against parameter annotations of the called method:
   if (arguments != null) {
     CompilerOptions compilerOptions = currentScope.compilerOptions();
     boolean considerTypeAnnotations =
         compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8
             && compilerOptions.isAnnotationBasedNullAnalysisEnabled;
     boolean hasJDK15NullAnnotations = methodBinding.parameterNonNullness != null;
     int numParamsToCheck = methodBinding.parameters.length;
     if (considerTypeAnnotations || hasJDK15NullAnnotations) {
       // check if varargs need special treatment:
       boolean passThrough = false;
       if (methodBinding.isVarargs()) {
         int varArgPos = numParamsToCheck - 1;
         // this if-block essentially copied from generateArguments(..):
         if (numParamsToCheck == arguments.length) {
           TypeBinding varArgsType = methodBinding.parameters[varArgPos];
           TypeBinding lastType = arguments[varArgPos].resolvedType;
           if (lastType == TypeBinding.NULL
               || (varArgsType.dimensions() == lastType.dimensions()
                   && lastType.isCompatibleWith(varArgsType)))
             passThrough = true; // pass directly as-is
         }
         if (!passThrough)
           numParamsToCheck--; // with non-passthrough varargs last param is fed from individual
         // args -> don't check
       }
     }
     if (considerTypeAnnotations) {
       for (int i = 0; i < numParamsToCheck; i++) {
         TypeBinding expectedType = methodBinding.parameters[i];
         Expression argument = arguments[i];
         // prefer check based on type annotations:
         int severity = findNullTypeAnnotationMismatch(expectedType, argument.resolvedType);
         if (severity > 0) {
           // immediate reporting:
           currentScope
               .problemReporter()
               .nullityMismatchingTypeAnnotation(
                   argument,
                   argument.resolvedType,
                   expectedType,
                   severity == 1,
                   currentScope.environment());
           // next check flow-based null status against null JDK15-style annotations:
         } else if (hasJDK15NullAnnotations
             && methodBinding.parameterNonNullness[i] == Boolean.TRUE) {
           int nullStatus =
               argument.nullStatus(
                   flowInfo,
                   flowContext); // slight loss of precision: should also use the null info from
           // the receiver.
           if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided
           flowContext.recordNullityMismatch(
                 currentScope, argument, argument.resolvedType, expectedType, nullStatus);
         }
       }
     } else if (hasJDK15NullAnnotations) {
       for (int i = 0; i < numParamsToCheck; i++) {
         if (methodBinding.parameterNonNullness[i] == Boolean.TRUE) {
           TypeBinding expectedType = methodBinding.parameters[i];
           Expression argument = arguments[i];
           int nullStatus =
               argument.nullStatus(
                   flowInfo,
                   flowContext); // slight loss of precision: should also use the null info from
           // the receiver.
           if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided
           flowContext.recordNullityMismatch(
                 currentScope, argument, argument.resolvedType, expectedType, nullStatus);
         }
       }
     }
   }
 }
Пример #6
0
  /** Generate invocation arguments, considering varargs methods */
  public void generateArguments(
      MethodBinding binding,
      Expression[] arguments,
      BlockScope currentScope,
      CodeStream codeStream) {
    if (binding.isVarargs()) {
      // 5 possibilities exist for a call to the vararg method foo(int i, int ... value) :
      //      foo(1), foo(1, null), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new int[] {1, 2})
      TypeBinding[] params = binding.parameters;
      int paramLength = params.length;
      int varArgIndex = paramLength - 1;
      for (int i = 0; i < varArgIndex; i++) {
        arguments[i].generateCode(currentScope, codeStream, true);
      }
      ArrayBinding varArgsType =
          (ArrayBinding) params[varArgIndex]; // parameterType has to be an array type
      ArrayBinding codeGenVarArgsType = (ArrayBinding) binding.parameters[varArgIndex].erasure();
      int elementsTypeID = varArgsType.elementsType().id;
      int argLength = arguments == null ? 0 : arguments.length;

      if (argLength > paramLength) {
        // right number but not directly compatible or too many arguments - wrap extra into array
        // called with (argLength - lastIndex) elements : foo(1, 2) or foo(1, 2, 3, 4)
        // need to gen elements into an array, then gen each remaining element into created array
        codeStream.generateInlinedValue(argLength - varArgIndex);
        codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array
        for (int i = varArgIndex; i < argLength; i++) {
          codeStream.dup();
          codeStream.generateInlinedValue(i - varArgIndex);
          arguments[i].generateCode(currentScope, codeStream, true);
          codeStream.arrayAtPut(elementsTypeID, false);
        }
      } else if (argLength == paramLength) {
        // right number of arguments - could be inexact - pass argument as is
        TypeBinding lastType = arguments[varArgIndex].resolvedType;
        if (lastType == TypeBinding.NULL
            || (varArgsType.dimensions() == lastType.dimensions()
                && lastType.isCompatibleWith(varArgsType))) {
          // foo(1, new int[]{2, 3}) or foo(1, null) --> last arg is passed as-is
          arguments[varArgIndex].generateCode(currentScope, codeStream, true);
        } else {
          // right number but not directly compatible or too many arguments - wrap extra into array
          // need to gen elements into an array, then gen each remaining element into created array
          codeStream.generateInlinedValue(1);
          codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array
          codeStream.dup();
          codeStream.generateInlinedValue(0);
          arguments[varArgIndex].generateCode(currentScope, codeStream, true);
          codeStream.arrayAtPut(elementsTypeID, false);
        }
      } else { // not enough arguments - pass extra empty array
        // scenario: foo(1) --> foo(1, new int[0])
        // generate code for an empty array of parameterType
        codeStream.generateInlinedValue(0);
        codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array
      }
    } else if (arguments != null) { // standard generation for method arguments
      for (int i = 0, max = arguments.length; i < max; i++)
        arguments[i].generateCode(currentScope, codeStream, true);
    }
  }
  /** Check whether the baseSpec has a result compatible via replace. */
  public void checkResultForReplace(MethodSpec baseSpec) {
    boolean typeIdentityRequired = true; // default unless return is type variable
    // covariant return requires a fresh type parameter for the role's return type:
    if (baseSpec.covariantReturn && this.roleMethodSpec.returnType != null) {
      TypeBinding resolvedRoleReturn = this.roleMethodSpec.returnType.resolvedType;
      if (resolvedRoleReturn != null) {
        if (!resolvedRoleReturn.isTypeVariable()) {
          this.scope
              .problemReporter()
              .covariantReturnRequiresTypeParameter(this.roleMethodSpec.returnType);
          this.binding.tagBits |= TagBits.HasMappingIncompatibility;
        } else {
          // is the type parameter "fresh"?
          for (Argument arg : this.roleMethodSpec.arguments) {
            if (typeUsesTypeVariable(
                arg.type.resolvedType.leafComponentType(), resolvedRoleReturn)) {
              this.scope
                  .problemReporter()
                  .duplicateUseOfTypeVariableInCallin(
                      this.roleMethodSpec.returnType, resolvedRoleReturn);
              this.binding.tagBits |= TagBits.HasMappingIncompatibility;
              break;
            }
          }
        }
      }
    }
    TypeVariableBinding returnVariable =
        MethodModel.checkedGetReturnTypeVariable(this.roleMethodSpec.resolvedMethod);
    if (returnVariable != null) {
      // unbounded type variable always matches:
      if (returnVariable.firstBound == null) return;
      // in case of type variable only one-way compatibility is needed even for replace:
      typeIdentityRequired = false;
    }

    // now go for the actual type checking:
    TypeBinding baseReturn = baseSpec.resolvedMethod.returnType;
    TypeBinding roleReturn = MethodModel.getReturnType(this.roleMethodSpec.resolvedMethod);
    TypeBinding roleReturnLeaf = roleReturn != null ? roleReturn.leafComponentType() : null;
    if (roleReturnLeaf instanceof ReferenceBinding
        && ((ReferenceBinding) roleReturnLeaf).isRole()) {
      // strengthen:
      roleReturnLeaf =
          TeamModel.strengthenRoleType(this.scope.enclosingSourceType(), roleReturnLeaf);
      if (roleReturnLeaf == null) { // FIXME(SH): testcase and better handling
        String roleReturnName =
            roleReturn != null
                ? new String(roleReturn.readableName())
                : "null return type"; //$NON-NLS-1$
        throw new InternalCompilerError(
            "role strengthening for " + roleReturnName + " -> null"); // $NON-NLS-1$ //$NON-NLS-2$
      }

      // bound roles use their topmost bound super:
      if (((ReferenceBinding) roleReturnLeaf).baseclass() != null)
        roleReturnLeaf =
            RoleModel.getTopmostBoundRole(this.scope, (ReferenceBinding) roleReturnLeaf);

      // need the RTB:
      if (!(roleReturnLeaf instanceof DependentTypeBinding))
        roleReturnLeaf =
            RoleTypeCreator.maybeWrapUnqualifiedRoleType(
                roleReturnLeaf, this.scope.enclosingSourceType());

      // array?
      int dims = roleReturn != null ? roleReturn.dimensions() : 0;
      if (dims == 0) {
        roleReturn = roleReturnLeaf;
        this.realRoleReturn = roleReturnLeaf;
      } else {
        roleReturn = ((DependentTypeBinding) roleReturnLeaf).getArrayType(dims);
        this.realRoleReturn = ((DependentTypeBinding) roleReturnLeaf).getArrayType(dims);
      }
    }
    if (baseReturn == null || baseReturn == TypeBinding.VOID) {
      // OTJLD 4.4(b): "A callin method bound with replace
      //                to a base method returning void
      //                must not declare a non-void result."
      if (!(roleReturn == null || roleReturn == TypeBinding.VOID)) {
        this.scope.problemReporter().callinIllegalRoleReturnReturn(baseSpec, this.roleMethodSpec);
        this.binding.tagBits |= TagBits.HasMappingIncompatibility;
      }
    } else {
      if (roleReturn == null || roleReturn == TypeBinding.VOID) {
        this.baseMethodNeedingResultFromBasecall = baseSpec;
        // will be reported in checkBaseResult().
        return;
      }

      TypeBinding baseLeaf = baseReturn.leafComponentType();
      if (baseLeaf instanceof DependentTypeBinding) {
        // instantiate relative to Role._OT$base:
        ReferenceBinding enclosingRole = this.scope.enclosingSourceType();
        FieldBinding baseField = enclosingRole.getField(IOTConstants._OT_BASE, true);
        if (baseField != null && baseField.isValidBinding())
          baseReturn =
              baseField.getRoleTypeBinding((ReferenceBinding) baseLeaf, baseReturn.dimensions());
      }

      // check auto(un)boxing:
      if (this.scope.isBoxingCompatibleWith(roleReturn, baseReturn)) return;

      Config oldConfig = Config.createOrResetConfig(this);
      try {
        if (!roleReturn.isCompatibleWith(baseReturn)) {
          if (typeIdentityRequired) {
            this.scope
                .problemReporter()
                .callinIncompatibleReturnType(baseSpec, this.roleMethodSpec);
            this.binding.tagBits |= TagBits.HasMappingIncompatibility;
            return;
          }
          // else we still needed the lowering test
        }
        // callin replace requires two way compatibility:
        baseSpec.returnNeedsTranslation = Config.getLoweringRequired();

      } finally {
        Config.removeOrRestore(oldConfig, this);
      }
      // from now on don't bother with arrays any more (dimensions have been checked):
      roleReturn = roleReturn.leafComponentType();
      baseReturn = baseReturn.leafComponentType();
      TypeBinding translatedReturn =
          baseSpec.returnNeedsTranslation
              ? ((ReferenceBinding) roleReturn).baseclass()
              : roleReturn;
      if (translatedReturn.isTypeVariable()) {
        TypeBinding firstBound = ((TypeVariableBinding) translatedReturn).firstBound;
        if (firstBound != null) translatedReturn = firstBound;
      }
      if (!baseReturn.isCompatibleWith(translatedReturn)) {
        this.scope
            .problemReporter()
            .callinIncompatibleReturnTypeBaseCall(baseSpec, this.roleMethodSpec);
        this.binding.tagBits |= TagBits.HasMappingIncompatibility;
      }
    }
  }
  /**
   * Check all parameters in methodSpec against the resolved role method. Also record which
   * parameters (including result) need translation (lifting/lowering).
   *
   * <p>Pre: not called if parameter mappings are present.
   *
   * @param methodSpec
   */
  protected boolean internalCheckParametersCompatibility(
      MethodSpec methodSpec, TypeBinding[] roleParams, TypeBinding[] baseParams) {
    if (baseParams.length < roleParams.length) {
      this.scope
          .problemReporter()
          .tooFewArgumentsInMethodMapping(this.roleMethodSpec, methodSpec, false /*callout*/);
      this.binding.tagBits |= TagBits.HasMappingIncompatibility;
      return false;
    } else {
      // before modifying the parameters array copy it:
      System.arraycopy(
          this.roleMethodSpec.parameters,
          0,
          this.roleMethodSpec.parameters = new TypeBinding[roleParams.length],
          0,
          roleParams.length);
      for (int j = 0; j < roleParams.length; j++) {
        TypeBinding baseParam = baseParams[j];
        TypeBinding roleParam = roleParams[j];
        if (baseParam.dimensions() != roleParam.dimensions()) {
          this.scope
              .problemReporter()
              .incompatibleMappedArgument(
                  baseParam, roleParam, this.roleMethodSpec, j, /*callout*/ false);
          this.binding.tagBits |= TagBits.HasMappingIncompatibility;
          continue; // no real type checking needed.
        }
        TypeBinding baseLeaf = baseParam.leafComponentType();
        TypeBinding roleLeaf = roleParam.leafComponentType();
        ASTNode location =
            (methodSpec.hasSignature) ? (ASTNode) methodSpec.arguments[j] : methodSpec;
        boolean compatibilityViaBaseAnchor = false;
        boolean hasReportedError = false;
        boolean isTypeVariable = false;
        try { // capture continue exits

          // unbound type variable matches everything:
          if (roleParam.isTypeVariable()) {
            TypeVariableBinding typeVariableBinding = (TypeVariableBinding) roleParam;
            if (typeVariableBinding.firstBound == null) continue;
            // use bound for type checking below, yet need not check two-way compatibility:
            isTypeVariable = true;
            roleLeaf = typeVariableBinding.firstBound.leafComponentType();
          }

          int dimensions = roleParam.dimensions();
          if (baseLeaf.isCompatibleWith(roleLeaf)) {
            this.roleMethodSpec.parameters[j] = roleParam;
            continue;
          }
          if (RoleTypeCreator.isCompatibleViaBaseAnchor(
              this.scope, baseLeaf, roleLeaf, TokenNameBINDIN)) {
            this.roleMethodSpec.parameters[j] = roleParam;
            compatibilityViaBaseAnchor = true;
            continue;
          }

          TypeBinding roleToLiftTo = null;
          if (isReplaceCallin()) {
            TypeBinding roleSideType = roleLeaf;
            if (roleSideType.isRole()) {
              ReferenceBinding roleRef = (ReferenceBinding) roleSideType;
              roleRef =
                  (ReferenceBinding)
                      TeamModel.strengthenRoleType(this.scope.enclosingReceiverType(), roleRef);
              if (TypeBinding.equalsEquals(roleRef.baseclass(), baseLeaf)) {
                if (dimensions > 0) {
                  if (roleRef instanceof DependentTypeBinding)
                    roleToLiftTo = ((DependentTypeBinding) roleRef).getArrayType(dimensions);
                  else
                    roleToLiftTo =
                        this.scope.createArrayType(roleRef, dimensions); // FIXME(SH): is this OK?
                } else {
                  roleToLiftTo = roleRef;
                }
              }
            }
          } else {
            // this uses OTJLD 2.3.3(a) adaptation which is not reversible, ie., not usable for
            // replace:
            roleToLiftTo =
                TeamModel.getRoleToLiftTo(this.scope, baseParam, roleParam, false, location);
          }
          if (roleToLiftTo != null) {
            // success by translation
            methodSpec.argNeedsTranslation[j] = true;
            this.roleMethodSpec.argNeedsTranslation[j] = true;
            this.roleMethodSpec.parameters[j] = roleToLiftTo; // this applies to all bindings

            // still need to check for ambiguity/abstract role:
            ReferenceBinding enclosingTeam = this.scope.enclosingSourceType().enclosingType();
            int iProblem =
                enclosingTeam
                    .getTeamModel()
                    .canLiftingFail((ReferenceBinding) roleToLiftTo.leafComponentType());
            if (iProblem > 0)
              addRoleLiftingProblem((ReferenceBinding) roleToLiftTo.leafComponentType(), iProblem);

            continue;
          }
          // check auto(un)boxing:
          if (this.scope.isBoxingCompatibleWith(baseLeaf, roleLeaf)) continue;

          if (roleParam instanceof ReferenceBinding) {
            ReferenceBinding roleRef = (ReferenceBinding) roleParam;
            if (roleRef.isRole() && roleRef.baseclass() != null) {
              this.scope
                  .problemReporter()
                  .typeMismatchErrorPotentialLift(
                      location, baseParam, roleParam, roleRef.baseclass());
              hasReportedError = true;
              continue;
            }
          }
          // no compatibility detected:
          this.scope
              .problemReporter()
              .incompatibleMappedArgument(
                  baseParam, roleParam, this.roleMethodSpec, j, /*callout*/ false);
          hasReportedError = true;
        } finally {
          if (hasReportedError) this.binding.tagBits |= TagBits.HasMappingIncompatibility;
          // regardless of continue, check this last because it is the least precise message:
          if (!hasReportedError && baseLeaf.isCompatibleWith(roleLeaf)) {
            if (isReplaceCallin() && !isTypeVariable) {
              boolean twowayCompatible =
                  compatibilityViaBaseAnchor
                      ? RoleTypeCreator.isCompatibleViaBaseAnchor(
                          this.scope, baseLeaf, roleLeaf, TokenNameBINDOUT)
                      : roleLeaf.isCompatibleWith(baseLeaf);
              if (!twowayCompatible) {
                // requires two-way compatibility (see additional paragraph in 4.5(d))
                this.scope
                    .problemReporter()
                    .typesNotTwowayCompatibleInReplace(baseParam, roleParam, location, j);
              }
            }
          }
        }
      }
    }
    return true; // unused in the callin case
  }
 public int boundCheck(Substitution var1, TypeBinding var2) {
   if (var2 != TypeBinding.field_187 && var2 != this) {
     boolean var3 = var1 != null;
     if (!(var2 instanceof ReferenceBinding) && !var2.method_147()) {
       return 2;
     } else if (this.superclass == null) {
       return 0;
     } else {
       TypeBinding var8;
       if (var2.kind() != 516) {
         boolean var14 = false;
         if (this.superclass.id != 1) {
           Object var15 = var3 ? Scope.substitute(var1, this.superclass) : this.superclass;
           if (var15 != var2) {
             if (!var2.isCompatibleWith((TypeBinding) var15)) {
               return 2;
             }
             TypeBinding var18 = var2.method_140((TypeBinding) var15);
             if (var18 != null && var18.method_166() && ((TypeBinding) var15).method_149()) {
               var14 = true;
             }
           }
         }
         int var16 = 0;
         for (int var17 = this.superInterfaces.length; var16 < var17; ++var16) {
           Object var19 =
               var3
                   ? Scope.substitute(var1, this.superInterfaces[var16])
                   : this.superInterfaces[var16];
           if (var19 != var2) {
             if (!var2.isCompatibleWith((TypeBinding) var19)) {
               return 2;
             }
             var8 = var2.method_140((TypeBinding) var19);
             if (var8 != null && var8.method_166() && ((TypeBinding) var19).method_149()) {
               var14 = true;
             }
           }
         }
         return var14 ? 1 : 0;
       } else {
         WildcardBinding var4 = (WildcardBinding) var2;
         switch (var4.field_215) {
           case 1:
             TypeBinding var5 = var4.bound;
             if (var5 == this) {
               return 0;
             } else {
               ReferenceBinding var6 =
                   var3
                       ? (ReferenceBinding) Scope.substitute(var1, this.superclass)
                       : this.superclass;
               boolean var7 = var5.method_147();
               if (!var5.method_157() && var6.id != 1) {
                 if (var7) {
                   if (!var5.isCompatibleWith(var6)) {
                     return 2;
                   }
                 } else {
                   var8 = var5.method_140(var6);
                   if (var8 != null) {
                     if (var6.method_164(var8)) {
                       return 2;
                     }
                   } else {
                     var8 = var6.method_140(var5);
                     if (var8 != null) {
                       if (var8.method_164(var5)) {
                         return 2;
                       }
                     } else if (!var5.method_169() && !var6.method_169()) {
                       return 2;
                     }
                   }
                 }
               }
               ReferenceBinding[] var20 =
                   var3 ? Scope.substitute(var1, this.superInterfaces) : this.superInterfaces;
               int var9 = var20.length;
               boolean var10 = var7 || ((ReferenceBinding) var5).method_221();
               for (int var11 = 0; var11 < var9; ++var11) {
                 ReferenceBinding var12 = var20[var11];
                 if (var7) {
                   if (!var5.isCompatibleWith(var12)) {
                     return 2;
                   }
                 } else {
                   TypeBinding var13 = var5.method_140(var12);
                   if (var13 != null) {
                     if (var12.method_164(var13)) {
                       return 2;
                     }
                   } else if (var10) {
                     return 2;
                   }
                 }
               }
             }
           case 0:
           default:
             return 0;
           case 2:
             return this.boundCheck(var1, var4.bound);
         }
       }
     }
   } else {
     return 0;
   }
 }
 public void resolve(MethodScope var1) {
   if ((this.field_446 & 16) == 0) {
     if (this.binding != null && this.binding.isValidBinding()) {
       this.field_446 |= 16;
       ClassScope var2 = var1.method_582();
       if (var2 != null) {
         label338:
         {
           SourceTypeBinding var3 = var2.enclosingSourceType();
           if (var3.superclass != null) {
             FieldBinding var4 = var2.findField(var3.superclass, this.name, this, false);
             if (var4 != null && var4.isValidBinding()) {
               label334:
               {
                 if (var4 instanceof FieldBinding) {
                   FieldBinding var5 = (FieldBinding) var4;
                   if (var5.original() == this.binding || !var5.canBeSeenBy(var3, this, var1)) {
                     break label334;
                   }
                 }
                 var1.problemReporter().fieldHiding(this, var4);
                 break label338;
               }
             }
           }
           Scope var13 = var2.parent;
           if (var13.kind != 4) {
             Binding var15 = var13.getBinding(this.name, 3, this, false);
             if (var15 != null && var15.isValidBinding() && var15 != this.binding) {
               label323:
               {
                 if (var15 instanceof FieldBinding) {
                   FieldBinding var6 = (FieldBinding) var15;
                   if (var6.original() == this.binding
                       || !var6.method_431() && var3.method_226()) {
                     break label323;
                   }
                 }
                 var1.problemReporter().fieldHiding(this, var15);
               }
             }
           }
         }
       }
       if (this.type != null) {
         this.type.resolvedType = this.binding.type;
       }
       FieldBinding var12 = var1.initializedField;
       int var14 = var1.field_407;
       try {
         var1.initializedField = this.binding;
         var1.field_407 = this.binding.field_304;
         method_761(var1, this.annotations, this.binding);
         if ((this.binding.getAnnotationTagBits() & 70368744177664L) == 0L
             && (this.binding.field_300 & 1048576) != 0
             && var1.compilerOptions().field_1928 >= 3211264L) {
           var1.problemReporter().method_1675(this);
         }
         if (this.initialization == null) {
           this.binding.setConstant(Constant.NotAConstant);
         } else {
           this.binding.setConstant(Constant.NotAConstant);
           TypeBinding var17 = this.binding.type;
           this.initialization.setExpectedType(var17);
           TypeBinding var18;
           if (this.initialization instanceof ArrayInitializer) {
             if ((var18 = this.initialization.resolveTypeExpecting(var1, var17)) != null) {
               ((ArrayInitializer) this.initialization).binding = (ArrayBinding) var18;
               this.initialization.computeConversion(var1, var17, var18);
             }
           } else if ((var18 = this.initialization.resolveType(var1)) != null) {
             if (var17 != var18) {
               var1.compilationUnitScope().recordTypeConversion(var17, var18);
             }
             if (!this.initialization.isConstantValueOfTypeAssignableToType(var18, var17)
                 && (!var17.method_148() || !BaseTypeBinding.method_185(var17.id, var18.id))
                 && !var18.isCompatibleWith(var17)) {
               if (!var1.isBoxingCompatibleWith(var18, var17)
                   && (!var18.method_148()
                       || var1.compilerOptions().field_1928 < 3211264L
                       || var17.method_148()
                       || !this.initialization.isConstantValueOfTypeAssignableToType(
                           var18, var1.environment().method_486(var17)))) {
                 if ((var17.tagBits & 128L) == 0L) {
                   var1.problemReporter()
                       .typeMismatchError(var18, var17, this.initialization, (ASTNode) null);
                 }
               } else {
                 this.initialization.computeConversion(var1, var17, var18);
                 if (this.initialization instanceof CastExpression
                     && (this.initialization.field_446 & 16384) == 0) {
                   CastExpression.checkNeedForAssignedCast(
                       var1, var17, (CastExpression) this.initialization);
                 }
               }
             } else {
               this.initialization.computeConversion(var1, var17, var18);
               if (var18.method_174(var17)) {
                 var1.problemReporter().method_1806(this.initialization, var18, var17);
               }
               if (this.initialization instanceof CastExpression
                   && (this.initialization.field_446 & 16384) == 0) {
                 CastExpression.checkNeedForAssignedCast(
                     var1, var17, (CastExpression) this.initialization);
               }
             }
             if (this.binding.method_409()) {
               this.binding.setConstant(
                   this.initialization.constant.castTo(
                       (this.binding.type.id << 4) + this.initialization.constant.typeID()));
             }
           } else {
             this.binding.setConstant(Constant.NotAConstant);
           }
           if (this.binding == Assignment.method_944(this.initialization)) {
             var1.problemReporter().assignmentHasNoEffect(this, this.name);
           }
         }
         if (this.binding != null
             && this.binding.declaringClass != null
             && !this.binding.declaringClass.method_158()) {
           int var16 = this.binding.field_300 & 7;
           ProblemReporter var19 = var1.problemReporter();
           int var7 = var19.computeSeverity(-1610612250);
           if (var7 != -1) {
             if (var2 != null) {
               var16 = Util.computeOuterMostVisibility(var2.referenceType(), var16);
             }
             int var8 = this.binding.field_300 & -8 | var16;
           }
         }
       } finally {
         var1.initializedField = var12;
         var1.field_407 = var14;
         if (this.binding.constant() == null) {
           this.binding.setConstant(Constant.NotAConstant);
         }
       }
     }
   }
 }
  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;
  }
Пример #12
0
  public static boolean checkInvocationArguments(
      BlockScope scope,
      Expression receiver,
      TypeBinding receiverType,
      MethodBinding method,
      Expression[] arguments,
      TypeBinding[] argumentTypes,
      boolean argsContainCast,
      InvocationSite invocationSite) {
    TypeBinding[] params = method.parameters;
    int paramLength = params.length;
    boolean isRawMemberInvocation =
        !method.isStatic()
            && !receiverType.isUnboundWildcard()
            && method.declaringClass.isRawType()
            && method.hasSubstitutedParameters();

    boolean uncheckedBoundCheck =
        (method.tagBits & TagBits.HasUncheckedTypeArgumentForBoundCheck) != 0;
    MethodBinding rawOriginalGenericMethod = null;
    if (!isRawMemberInvocation) {
      if (method instanceof ParameterizedGenericMethodBinding) {
        ParameterizedGenericMethodBinding paramMethod = (ParameterizedGenericMethodBinding) method;
        if (paramMethod.isRaw && method.hasSubstitutedParameters()) {
          rawOriginalGenericMethod = method.original();
        }
      }
    }
    int invocationStatus = INVOCATION_ARGUMENT_OK;
    if (arguments == null) {
      if (method.isVarargs()) {
        TypeBinding parameterType =
            ((ArrayBinding) params[paramLength - 1])
                .elementsType(); // no element was supplied for vararg parameter
        if (!parameterType.isReifiable()) {
          scope
              .problemReporter()
              .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite);
        }
      }
    } else {
      if (method.isVarargs()) {
        // 4 possibilities exist for a call to the vararg method foo(int i, long ... value) :
        // foo(1), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new long[] {1, 2})
        int lastIndex = paramLength - 1;
        for (int i = 0; i < lastIndex; i++) {
          TypeBinding originalRawParam =
              rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i];
          invocationStatus |=
              checkInvocationArgument(
                  scope, arguments[i], params[i], argumentTypes[i], originalRawParam);
        }
        int argLength = arguments.length;
        if (lastIndex < argLength) { // vararg argument was provided
          TypeBinding parameterType = params[lastIndex];
          TypeBinding originalRawParam = null;

          if (paramLength != argLength
              || parameterType.dimensions() != argumentTypes[lastIndex].dimensions()) {
            parameterType =
                ((ArrayBinding) parameterType)
                    .elementsType(); // single element was provided for vararg parameter
            if (!parameterType.isReifiable()) {
              scope
                  .problemReporter()
                  .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite);
            }
            originalRawParam =
                rawOriginalGenericMethod == null
                    ? null
                    : ((ArrayBinding) rawOriginalGenericMethod.parameters[lastIndex])
                        .elementsType();
          }
          for (int i = lastIndex; i < argLength; i++) {
            invocationStatus |=
                checkInvocationArgument(
                    scope, arguments[i], parameterType, argumentTypes[i], originalRawParam);
          }
        }
        if (paramLength == argLength) { // 70056
          int varargsIndex = paramLength - 1;
          ArrayBinding varargsType = (ArrayBinding) params[varargsIndex];
          TypeBinding lastArgType = argumentTypes[varargsIndex];
          int dimensions;
          if (lastArgType == TypeBinding.NULL) {
            if (!(varargsType.leafComponentType().isBaseType() && varargsType.dimensions() == 1))
              scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite);
          } else if (varargsType.dimensions <= (dimensions = lastArgType.dimensions())) {
            if (lastArgType.leafComponentType().isBaseType()) {
              dimensions--;
            }
            if (varargsType.dimensions < dimensions) {
              scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite);
            } else if (varargsType.dimensions == dimensions
                && lastArgType != varargsType
                && lastArgType.leafComponentType().erasure()
                    != varargsType.leafComponentType.erasure()
                && lastArgType.isCompatibleWith(varargsType.elementsType())
                && lastArgType.isCompatibleWith(varargsType)) {
              scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite);
            }
          }
        }
      } else {
        for (int i = 0; i < paramLength; i++) {
          TypeBinding originalRawParam =
              rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i];
          invocationStatus |=
              checkInvocationArgument(
                  scope, arguments[i], params[i], argumentTypes[i], originalRawParam);
        }
      }
      if (argsContainCast) {
        CastExpression.checkNeedForArgumentCasts(
            scope, receiver, receiverType, method, arguments, argumentTypes, invocationSite);
      }
    }
    if ((invocationStatus & INVOCATION_ARGUMENT_WILDCARD) != 0) {
      scope
          .problemReporter()
          .wildcardInvocation((ASTNode) invocationSite, receiverType, method, argumentTypes);
    } else if (!method.isStatic()
        && !receiverType.isUnboundWildcard()
        && method.declaringClass.isRawType()
        && method.hasSubstitutedParameters()) {
      scope.problemReporter().unsafeRawInvocation((ASTNode) invocationSite, method);
    } else if (rawOriginalGenericMethod != null
        || uncheckedBoundCheck
        || ((invocationStatus & INVOCATION_ARGUMENT_UNCHECKED) != 0
            && method instanceof ParameterizedGenericMethodBinding
        /*&& method.returnType != scope.environment().convertToRawType(method.returnType.erasure(), true)*/ )) {
      scope
          .problemReporter()
          .unsafeRawGenericMethodInvocation((ASTNode) invocationSite, method, argumentTypes);
      return true;
    }
    return false;
  }
Пример #13
0
  public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) {
    // Array initializers can only occur on the right hand side of an assignment
    // expression, therefore the expected type contains the valid information
    // concerning the type that must be enforced by the elements of the array initializer.

    // this method is recursive... (the test on isArrayType is the stop case)

    this.constant = Constant.NotAConstant;

    if (expectedType instanceof ArrayBinding) {
      // allow new List<?>[5]
      if ((this.bits & IsAnnotationDefaultValue)
          == 0) { // annotation default value need only to be commensurate JLS9.7
        // allow new List<?>[5] - only check for generic array when no initializer, since also
        // checked inside initializer resolution
        TypeBinding leafComponentType = expectedType.leafComponentType();
        if (!leafComponentType.isReifiable()) {
          scope.problemReporter().illegalGenericArray(leafComponentType, this);
        }
      }
      this.resolvedType = this.binding = (ArrayBinding) expectedType;
      if (this.expressions == null) return this.binding;
      TypeBinding elementType = this.binding.elementsType();
      for (int i = 0, length = this.expressions.length; i < length; i++) {
        Expression expression = this.expressions[i];
        expression.setExpectedType(elementType);
        TypeBinding expressionType =
            expression instanceof ArrayInitializer
                ? expression.resolveTypeExpecting(scope, elementType)
                : expression.resolveType(scope);
        if (expressionType == null) continue;

        // Compile-time conversion required?
        if (elementType
            != expressionType) // must call before computeConversion() and typeMismatchError()
        scope.compilationUnitScope().recordTypeConversion(elementType, expressionType);

        if (expression.isConstantValueOfTypeAssignableToType(expressionType, elementType)
            || expressionType.isCompatibleWith(elementType)) {
          expression.computeConversion(scope, elementType, expressionType);
        } else if (scope.isBoxingCompatibleWith(expressionType, elementType)
            || (expressionType.isBaseType() // narrowing then boxing ?
                && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing
                && !elementType.isBaseType()
                && expression.isConstantValueOfTypeAssignableToType(
                    expressionType, scope.environment().computeBoxingType(elementType)))) {
          expression.computeConversion(scope, elementType, expressionType);
        } else {
          scope.problemReporter().typeMismatchError(expressionType, elementType, expression, null);
        }
      }
      return this.binding;
    }

    // infer initializer type for error reporting based on first element
    TypeBinding leafElementType = null;
    int dim = 1;
    if (this.expressions == null) {
      leafElementType = scope.getJavaLangObject();
    } else {
      Expression expression = this.expressions[0];
      while (expression != null && expression instanceof ArrayInitializer) {
        dim++;
        Expression[] subExprs = ((ArrayInitializer) expression).expressions;
        if (subExprs == null) {
          leafElementType = scope.getJavaLangObject();
          expression = null;
          break;
        }
        expression = ((ArrayInitializer) expression).expressions[0];
      }
      if (expression != null) {
        leafElementType = expression.resolveType(scope);
      }
      // fault-tolerance - resolve other expressions as well
      for (int i = 1, length = this.expressions.length; i < length; i++) {
        expression = this.expressions[i];
        if (expression != null) {
          expression.resolveType(scope);
        }
      }
    }
    if (leafElementType != null) {
      this.resolvedType = scope.createArrayType(leafElementType, dim);
      if (expectedType != null)
        scope.problemReporter().typeMismatchError(this.resolvedType, expectedType, this, null);
    }
    return null;
  }