public TypeBinding resolveType(BlockScope scope) {
    // Propagate the type checking to the arguments, and check if the constructor is defined.
    this.constant = Constant.NotAConstant;
    if (this.type == null) {
      // initialization of an enum constant
      this.resolvedType = scope.enclosingReceiverType();
    } else {
      this.resolvedType = this.type.resolveType(scope, true /* check bounds*/);
      checkParameterizedAllocation:
      {
        if (this.type
            instanceof ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>()
          ReferenceBinding currentType = (ReferenceBinding) this.resolvedType;
          if (currentType == null) return currentType;
          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, this.resolvedType);
              break;
            }
          }
        }
      }
    }
    // will check for null after args are resolved

    final boolean isDiamond = this.type != null && (this.type.bits & ASTNode.IsDiamond) != 0;
    // resolve type arguments (for generic constructor call)
    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;
      }
    }

    // buffering the arguments' types
    boolean argsContainCast = false;
    TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
    if (this.arguments != null) {
      boolean argHasError = false;
      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] = argument.resolveType(scope)) == null) {
          argHasError = true;
        }
      }
      if (argHasError) {
        /* 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 (this.resolvedType instanceof ReferenceBinding) {
          // record a best guess, for clients who need hint about possible constructor match
          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(
                  (ReferenceBinding) this.resolvedType, 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;
              }
            }
          }
        }
        return this.resolvedType;
      }
    }
    if (this.resolvedType == null || !this.resolvedType.isValidBinding()) {
      return null;
    }

    // null type denotes fake allocation for enum constant inits
    if (this.type != null && !this.resolvedType.canBeInstantiated()) {
      scope.problemReporter().cannotInstantiate(this.type, this.resolvedType);
      return this.resolvedType;
    }
    if (isDiamond) {
      TypeBinding[] inferredTypes =
          inferElidedTypes(
              ((ParameterizedTypeBinding) this.resolvedType).genericType(),
              null,
              argumentTypes,
              scope);
      if (inferredTypes == null) {
        scope.problemReporter().cannotInferElidedTypes(this);
        return this.resolvedType = null;
      }
      this.resolvedType =
          this.type.resolvedType =
              scope
                  .environment()
                  .createParameterizedType(
                      ((ParameterizedTypeBinding) this.resolvedType).genericType(),
                      inferredTypes,
                      ((ParameterizedTypeBinding) this.resolvedType).enclosingType());
    }
    ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType;
    if (!(this.binding = scope.getConstructor(allocationType, argumentTypes, this))
        .isValidBinding()) {
      if (this.binding.declaringClass == null) {
        this.binding.declaringClass = allocationType;
      }
      if (this.type != null && !this.type.resolvedType.isValidBinding()) {
        return null;
      }
      scope.problemReporter().invalidConstructor(this, this.binding);
      return this.resolvedType;
    }
    if ((this.binding.tagBits & TagBits.HasMissingType) != 0) {
      scope.problemReporter().missingTypeInConstructor(this, this.binding);
    }
    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);
    }
    if (!isDiamond && this.resolvedType.isParameterizedTypeWithActualArguments()) {
      checkTypeArgumentRedundancy(
          (ParameterizedTypeBinding) this.resolvedType, null, argumentTypes, scope);
    }
    final CompilerOptions compilerOptions = scope.compilerOptions();
    if (compilerOptions.isAnnotationBasedNullAnalysisEnabled
        && (this.binding.tagBits & TagBits.IsNullnessKnown) == 0) {
      new ImplicitNullAnnotationVerifier(
              scope.environment(), compilerOptions.inheritNullAnnotations)
          .checkImplicitNullAnnotations(this.binding, null /*srcMethod*/, false, scope);
    }
    return allocationType;
  }
Пример #2
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;
  }