예제 #1
0
파일: ASTNode.java 프로젝트: beefeather/ohl
  /* Answer true if the method use is considered deprecated.
   * An access in the same compilation unit is allowed.
   */
  public final boolean isMethodUseDeprecated(
      MethodBinding method, Scope scope, boolean isExplicitUse) {
    // ignore references insing Javadoc comments
    if ((this.bits & ASTNode.InsideJavadoc) == 0
        && method.isOrEnclosedByPrivateType()
        && !scope.isDefinedInMethod(method)) {
      // ignore cases where method is used from inside itself (e.g. direct recursions)
      method.original().modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
    }

    // TODO (maxime) consider separating concerns between deprecation and access restriction.
    // 				 Caveat: this was not the case when access restriction funtion was added.
    if (isExplicitUse && (method.modifiers & ExtraCompilerModifiers.AccRestrictedAccess) != 0) {
      // note: explicit constructors calls warnings are kept despite the 'new C1()' case (two
      //       warnings, one on type, the other on constructor), because of the 'super()' case.
      AccessRestriction restriction =
          scope.environment().getAccessRestriction(method.declaringClass.erasure());
      if (restriction != null) {
        scope
            .problemReporter()
            .forbiddenReference(
                method,
                this,
                restriction.classpathEntryType,
                restriction.classpathEntryName,
                restriction.getProblemId());
      }
    }

    if (!method.isViewedAsDeprecated()) return false;

    // inside same unit - no report
    if (scope.isDefinedInSameUnit(method.declaringClass)) return false;

    // non explicit use and non explicitly deprecated - no report
    if (!isExplicitUse && (method.modifiers & ClassFileConstants.AccDeprecated) == 0) {
      return false;
    }

    // if context is deprecated, may avoid reporting
    if (!scope.compilerOptions().reportDeprecationInsideDeprecatedCode
        && scope.isInsideDeprecatedCode()) return false;
    return true;
  }
예제 #2
0
파일: ASTNode.java 프로젝트: beefeather/ohl
  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;
  }
  /**
   * The main algorithm in this class.
   *
   * @param currentMethod focus method
   * @param srcMethod AST of 'currentMethod' if present
   * @param hasReturnNonNullDefault is a @NonNull default applicable for the return type of
   *     currentMethod?
   * @param hasParameterNonNullDefault is a @NonNull default applicable for parameters of
   *     currentMethod?
   * @param shouldComplain should we report any errors found? (see also comment about flows into
   *     this method, below).
   * @param inheritedMethod one overridden method from a super type
   * @param allInheritedMethods look here to see if nonnull-unannotated conflict already exists in
   *     one super type
   * @param scope provides context for error reporting etc.
   * @param inheritedNonNullnessInfos if non-null, this array of non-null elements is used for
   *     interim recording of nullness information from inheritedMethod rather than prematurely
   *     updating currentMethod. Index position 0 is used for the return type, positions i+1 for
   *     argument i.
   */
  void checkNullSpecInheritance(
      MethodBinding currentMethod,
      AbstractMethodDeclaration srcMethod,
      boolean hasReturnNonNullDefault,
      boolean hasParameterNonNullDefault,
      boolean shouldComplain,
      MethodBinding inheritedMethod,
      MethodBinding[] allInheritedMethods,
      Scope scope,
      InheritedNonNullnessInfo[] inheritedNonNullnessInfos) {
    // Note that basically two different flows lead into this method:
    // (1) during MethodVerifyer15.checkMethods() we want to report errors (against srcMethod or
    // against the current type)
    //     In this case this method is directly called from MethodVerifier15
    // (checkAgainstInheritedMethod / checkConcreteInheritedMethod)
    // (2) during on-demand invocation we are mainly interested in the side effects of copying
    // inherited null annotations
    //     In this case this method is called via checkImplicitNullAnnotations from
    //     - MessageSend.resolveType(..)
    //     - SourceTypeBinding.createArgumentBindings(..)
    //     - recursive calls within this class
    //     Still we *might* want to complain about problems found (controlled by 'complain')

    if ((inheritedMethod.tagBits & TagBits.IsNullnessKnown) == 0) {
      // TODO (stephan): even here we may need to report problems? How to discriminate?
      this.buddyImplicitNullAnnotationsVerifier.checkImplicitNullAnnotations(
          inheritedMethod, null, false, scope);
    }
    boolean useTypeAnnotations = this.environment.usesNullTypeAnnotations();
    long inheritedNullnessBits = getReturnTypeNullnessTagBits(inheritedMethod, useTypeAnnotations);
    long currentNullnessBits = getReturnTypeNullnessTagBits(currentMethod, useTypeAnnotations);

    boolean shouldInherit = this.inheritNullAnnotations;

    // return type:
    returnType:
    {
      if (currentMethod.returnType == null || currentMethod.returnType.isBaseType())
        break returnType; // no nullness for primitive types
      if (currentNullnessBits == 0) {
        // unspecified, may fill in either from super or from default
        if (shouldInherit) {
          if (inheritedNullnessBits != 0) {
            if (hasReturnNonNullDefault) {
              // both inheritance and default: check for conflict?
              if (shouldComplain && inheritedNullnessBits == TagBits.AnnotationNullable)
                scope
                    .problemReporter()
                    .conflictingNullAnnotations(
                        currentMethod, ((MethodDeclaration) srcMethod).returnType, inheritedMethod);
              // 	still use the inherited bits to avoid incompatibility
            }
            if (inheritedNonNullnessInfos != null && srcMethod != null) {
              recordDeferredInheritedNullness(
                  scope,
                  ((MethodDeclaration) srcMethod).returnType,
                  inheritedMethod,
                  Boolean.valueOf(inheritedNullnessBits == TagBits.AnnotationNonNull),
                  inheritedNonNullnessInfos[0]);
            } else {
              // no need to defer, record this info now:
              applyReturnNullBits(currentMethod, inheritedNullnessBits);
            }
            break returnType; // compatible by construction, skip complain phase below
          }
        }
        if (hasReturnNonNullDefault
            && (!useTypeAnnotations
                || currentMethod.returnType
                    .acceptsNonNullDefault())) { // conflict with inheritance already checked
          currentNullnessBits = TagBits.AnnotationNonNull;
          applyReturnNullBits(currentMethod, currentNullnessBits);
        }
      }
      if (shouldComplain) {
        if ((inheritedNullnessBits & TagBits.AnnotationNonNull) != 0
            && currentNullnessBits != TagBits.AnnotationNonNull) {
          if (srcMethod != null) {
            scope
                .problemReporter()
                .illegalReturnRedefinition(
                    srcMethod, inheritedMethod, this.environment.getNonNullAnnotationName());
            break returnType;
          } else {
            scope
                .problemReporter()
                .cannotImplementIncompatibleNullness(
                    currentMethod, inheritedMethod, useTypeAnnotations);
            return;
          }
        }
        if (useTypeAnnotations) {
          TypeBinding substituteReturnType =
              null; // for TVB identity checks inside NullAnnotationMatching.analyze()
          TypeVariableBinding[] typeVariables = inheritedMethod.original().typeVariables;
          if (typeVariables != null && currentMethod.returnType.id != TypeIds.T_void) {
            ParameterizedGenericMethodBinding substitute =
                this.environment.createParameterizedGenericMethod(currentMethod, typeVariables);
            substituteReturnType = substitute.returnType;
          }
          if (NullAnnotationMatching.analyse(
                  inheritedMethod.returnType,
                  currentMethod.returnType,
                  substituteReturnType,
                  0,
                  CheckMode.OVERRIDE)
              .isAnyMismatch()) {
            if (srcMethod != null)
              scope
                  .problemReporter()
                  .illegalReturnRedefinition(
                      srcMethod, inheritedMethod, this.environment.getNonNullAnnotationName());
            else
              scope
                  .problemReporter()
                  .cannotImplementIncompatibleNullness(
                      currentMethod, inheritedMethod, useTypeAnnotations);
            return;
          }
        }
      }
    }

    // parameters:
    TypeBinding[] substituteParameters =
        null; // for TVB identity checks inside NullAnnotationMatching.analyze()
    if (shouldComplain) {
      TypeVariableBinding[] typeVariables = currentMethod.original().typeVariables;
      if (typeVariables != Binding.NO_TYPE_VARIABLES) {
        ParameterizedGenericMethodBinding substitute =
            this.environment.createParameterizedGenericMethod(inheritedMethod, typeVariables);
        substituteParameters = substitute.parameters;
      }
    }

    Argument[] currentArguments = srcMethod == null ? null : srcMethod.arguments;

    int length = 0;
    if (currentArguments != null) length = currentArguments.length;
    if (useTypeAnnotations) // need to look for type annotations on all parameters:
    length = currentMethod.parameters.length;
    else if (inheritedMethod.parameterNonNullness != null)
      length = inheritedMethod.parameterNonNullness.length;
    else if (currentMethod.parameterNonNullness != null)
      length = currentMethod.parameterNonNullness.length;

    parameterLoop:
    for (int i = 0; i < length; i++) {
      if (currentMethod.parameters[i].isBaseType()) continue;

      Argument currentArgument = currentArguments == null ? null : currentArguments[i];
      Boolean inheritedNonNullNess =
          getParameterNonNullness(inheritedMethod, i, useTypeAnnotations);
      Boolean currentNonNullNess = getParameterNonNullness(currentMethod, i, useTypeAnnotations);

      if (currentNonNullNess == null) {
        // unspecified, may fill in either from super or from default
        if (inheritedNonNullNess != null) {
          if (shouldInherit) {
            if (hasParameterNonNullDefault) {
              // both inheritance and default: check for conflict?
              if (shouldComplain
                  && inheritedNonNullNess == Boolean.FALSE
                  && currentArgument != null) {
                scope
                    .problemReporter()
                    .conflictingNullAnnotations(currentMethod, currentArgument, inheritedMethod);
              }
              // 	still use the inherited info to avoid incompatibility
            }
            if (inheritedNonNullnessInfos != null && srcMethod != null) {
              recordDeferredInheritedNullness(
                  scope,
                  srcMethod.arguments[i].type,
                  inheritedMethod,
                  inheritedNonNullNess,
                  inheritedNonNullnessInfos[i + 1]);
            } else {
              // no need to defer, record this info now:
              if (!useTypeAnnotations)
                recordArgNonNullness(
                    currentMethod, length, i, currentArgument, inheritedNonNullNess);
              else
                recordArgNonNullness18(
                    currentMethod, i, currentArgument, inheritedNonNullNess, this.environment);
            }
            continue; // compatible by construction, skip complain phase below
          }
        }
        if (hasParameterNonNullDefault) { // conflict with inheritance already checked
          currentNonNullNess = Boolean.TRUE;
          if (!useTypeAnnotations)
            recordArgNonNullness(currentMethod, length, i, currentArgument, Boolean.TRUE);
          else if (currentMethod.parameters[i].acceptsNonNullDefault())
            recordArgNonNullness18(
                currentMethod, i, currentArgument, Boolean.TRUE, this.environment);
          else currentNonNullNess = null; // cancel if parameter doesn't accept the default
        }
      }
      if (shouldComplain) {
        char[][] annotationName;
        if (inheritedNonNullNess == Boolean.TRUE) {
          annotationName = this.environment.getNonNullAnnotationName();
        } else {
          annotationName = this.environment.getNullableAnnotationName();
        }
        if (inheritedNonNullNess != Boolean.TRUE // super parameter is not restricted to @NonNull
            && currentNonNullNess == Boolean.TRUE) // current parameter is restricted to @NonNull
        {
          // incompatible
          if (currentArgument != null) {
            scope
                .problemReporter()
                .illegalRedefinitionToNonNullParameter(
                    currentArgument,
                    inheritedMethod.declaringClass,
                    (inheritedNonNullNess == null)
                        ? null
                        : this.environment.getNullableAnnotationName());
          } else {
            scope
                .problemReporter()
                .cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false);
          }
          continue;
        } else if (currentNonNullNess == null) {
          // unannotated strictly conflicts only with inherited @Nullable
          if (inheritedNonNullNess == Boolean.FALSE) {
            if (currentArgument != null) {
              scope
                  .problemReporter()
                  .parameterLackingNullableAnnotation(
                      currentArgument, inheritedMethod.declaringClass, annotationName);
            } else {
              scope
                  .problemReporter()
                  .cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false);
            }
            continue;
          } else if (inheritedNonNullNess == Boolean.TRUE) {
            // not strictly a conflict, but a configurable warning is given anyway:
            if (allInheritedMethods != null) {
              // avoid this optional warning if the conflict already existed in one supertype
              // (merging of two methods into one?)
              for (MethodBinding one : allInheritedMethods)
                if (TypeBinding.equalsEquals(inheritedMethod.declaringClass, one.declaringClass)
                    && getParameterNonNullness(one, i, useTypeAnnotations) != Boolean.TRUE)
                  continue parameterLoop;
            }
            scope
                .problemReporter()
                .parameterLackingNonnullAnnotation(
                    currentArgument, inheritedMethod.declaringClass, annotationName);
            continue;
          }
        }
        if (useTypeAnnotations) {
          TypeBinding inheritedParameter = inheritedMethod.parameters[i];
          TypeBinding substituteParameter =
              substituteParameters != null ? substituteParameters[i] : null;
          if (NullAnnotationMatching.analyse(
                  currentMethod.parameters[i],
                  inheritedParameter,
                  substituteParameter,
                  0,
                  CheckMode.OVERRIDE)
              .isAnyMismatch()) {
            if (currentArgument != null)
              scope
                  .problemReporter()
                  .illegalParameterRedefinition(
                      currentArgument, inheritedMethod.declaringClass, inheritedParameter);
            else
              scope
                  .problemReporter()
                  .cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false);
          }
        }
      }
    }
  }
  /**
   * Check and fill in implicit annotations from overridden methods and from default. Precondition:
   * caller has checked whether annotation-based null analysis is enabled.
   */
  public void checkImplicitNullAnnotations(
      MethodBinding currentMethod,
      AbstractMethodDeclaration srcMethod,
      boolean complain,
      Scope scope) {
    // check inherited nullness from superclass and superInterfaces
    try {
      ReferenceBinding currentType = currentMethod.declaringClass;
      if (currentType.id == TypeIds.T_JavaLangObject) {
        return;
      }
      boolean usesTypeAnnotations = scope.environment().usesNullTypeAnnotations();
      boolean needToApplyReturnNonNullDefault =
          currentMethod.hasNonNullDefaultFor(
              Binding.DefaultLocationReturnType, usesTypeAnnotations);
      boolean needToApplyParameterNonNullDefault =
          currentMethod.hasNonNullDefaultFor(Binding.DefaultLocationParameter, usesTypeAnnotations);
      boolean needToApplyNonNullDefault =
          needToApplyReturnNonNullDefault | needToApplyParameterNonNullDefault;
      // compatibility & inheritance do not consider constructors / static methods:
      boolean isInstanceMethod = !currentMethod.isConstructor() && !currentMethod.isStatic();
      complain &= isInstanceMethod;
      if (!needToApplyNonNullDefault
          && !complain
          && !(this.inheritNullAnnotations && isInstanceMethod)) {
        return; // short cut, no work to be done
      }

      if (isInstanceMethod) {
        List superMethodList = new ArrayList();

        // need super types connected:
        if (currentType instanceof SourceTypeBinding
            && !currentType.isHierarchyConnected()
            && !currentType.isAnonymousType()) {
          ((SourceTypeBinding) currentType).scope.connectTypeHierarchy();
        }

        int paramLen = currentMethod.parameters.length;
        findAllOverriddenMethods(
            currentMethod.original(),
            currentMethod.selector,
            paramLen,
            currentType,
            new HashSet(),
            superMethodList);

        // prepare interim storage for nullness info so we don't pollute currentMethod before we
        // know its conflict-free:
        InheritedNonNullnessInfo[] inheritedNonNullnessInfos =
            new InheritedNonNullnessInfo[paramLen + 1]; // index 0 is for the return type
        for (int i = 0; i < paramLen + 1; i++)
          inheritedNonNullnessInfos[i] = new InheritedNonNullnessInfo();

        int length = superMethodList.size();
        for (int i = length; --i >= 0; ) {
          MethodBinding currentSuper = (MethodBinding) superMethodList.get(i);
          if ((currentSuper.tagBits & TagBits.IsNullnessKnown) == 0) {
            // recurse to prepare currentSuper
            checkImplicitNullAnnotations(
                currentSuper,
                null,
                false,
                scope); // TODO (stephan) complain=true if currentSuper is source method??
          }
          checkNullSpecInheritance(
              currentMethod,
              srcMethod,
              needToApplyReturnNonNullDefault,
              needToApplyParameterNonNullDefault,
              complain,
              currentSuper,
              null,
              scope,
              inheritedNonNullnessInfos);
          needToApplyNonNullDefault = false;
        }

        // transfer collected information into currentMethod:
        InheritedNonNullnessInfo info = inheritedNonNullnessInfos[0];
        if (!info.complained) {
          long tagBits = 0;
          if (info.inheritedNonNullness == Boolean.TRUE) {
            tagBits = TagBits.AnnotationNonNull;
          } else if (info.inheritedNonNullness == Boolean.FALSE) {
            tagBits = TagBits.AnnotationNullable;
          }
          if (tagBits != 0) {
            if (!usesTypeAnnotations) {
              currentMethod.tagBits |= tagBits;
            } else {
              if (!currentMethod.returnType.isBaseType()) {
                LookupEnvironment env = scope.environment();
                currentMethod.returnType =
                    env.createAnnotatedType(
                        currentMethod.returnType, env.nullAnnotationsFromTagBits(tagBits));
              }
            }
          }
        }
        for (int i = 0; i < paramLen; i++) {
          info = inheritedNonNullnessInfos[i + 1];
          if (!info.complained && info.inheritedNonNullness != null) {
            Argument currentArg = srcMethod == null ? null : srcMethod.arguments[i];
            if (!usesTypeAnnotations)
              recordArgNonNullness(
                  currentMethod, paramLen, i, currentArg, info.inheritedNonNullness);
            else
              recordArgNonNullness18(
                  currentMethod, i, currentArg, info.inheritedNonNullness, scope.environment());
          }
        }
      }
      if (needToApplyNonNullDefault) {
        if (!usesTypeAnnotations) currentMethod.fillInDefaultNonNullness(srcMethod);
        else currentMethod.fillInDefaultNonNullness18(srcMethod, scope.environment());
      }
    } finally {
      currentMethod.tagBits |= TagBits.IsNullnessKnown;
    }
  }
  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;
  }