Beispiel #1
0
  @Nullable
  public static OverrideCompatibilityInfo getBasicOverridabilityProblem(
      @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
    if (superDescriptor instanceof FunctionDescriptor
            && !(subDescriptor instanceof FunctionDescriptor)
        || superDescriptor instanceof PropertyDescriptor
            && !(subDescriptor instanceof PropertyDescriptor)) {
      return OverrideCompatibilityInfo.incompatible("Member kind mismatch");
    }

    if (!(superDescriptor instanceof FunctionDescriptor)
        && !(superDescriptor instanceof PropertyDescriptor)) {
      throw new IllegalArgumentException(
          "This type of CallableDescriptor cannot be checked for overridability: "
              + superDescriptor);
    }

    // TODO: check outside of this method
    if (!superDescriptor.getName().equals(subDescriptor.getName())) {
      return OverrideCompatibilityInfo.incompatible("Name mismatch");
    }

    OverrideCompatibilityInfo receiverAndParameterResult =
        checkReceiverAndParameterCount(superDescriptor, subDescriptor);
    if (receiverAndParameterResult != null) {
      return receiverAndParameterResult;
    }

    return null;
  }
Beispiel #2
0
  @NotNull
  public OverrideCompatibilityInfo isOverridableByWithoutExternalConditions(
      @NotNull CallableDescriptor superDescriptor,
      @NotNull CallableDescriptor subDescriptor,
      boolean checkReturnType) {
    OverrideCompatibilityInfo basicOverridability =
        getBasicOverridabilityProblem(superDescriptor, subDescriptor);
    if (basicOverridability != null) return basicOverridability;

    List<KotlinType> superValueParameters = compiledValueParameters(superDescriptor);
    List<KotlinType> subValueParameters = compiledValueParameters(subDescriptor);

    List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
    List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();

    if (superTypeParameters.size() != subTypeParameters.size()) {
      for (int i = 0; i < superValueParameters.size(); ++i) {
        // TODO: compare erasure
        if (!KotlinTypeChecker.DEFAULT.equalTypes(
            superValueParameters.get(i), subValueParameters.get(i))) {
          return OverrideCompatibilityInfo.incompatible("Type parameter number mismatch");
        }
      }
      return OverrideCompatibilityInfo.conflict("Type parameter number mismatch");
    }

    KotlinTypeChecker typeChecker = createTypeChecker(superTypeParameters, subTypeParameters);

    for (int i = 0; i < superTypeParameters.size(); i++) {
      if (!areTypeParametersEquivalent(
          superTypeParameters.get(i), subTypeParameters.get(i), typeChecker)) {
        return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch");
      }
    }

    for (int i = 0; i < superValueParameters.size(); i++) {
      if (!areTypesEquivalent(
          superValueParameters.get(i), subValueParameters.get(i), typeChecker)) {
        return OverrideCompatibilityInfo.incompatible("Value parameter type mismatch");
      }
    }

    if (checkReturnType) {
      KotlinType superReturnType = superDescriptor.getReturnType();
      KotlinType subReturnType = subDescriptor.getReturnType();

      if (superReturnType != null && subReturnType != null) {
        boolean bothErrors = subReturnType.isError() && superReturnType.isError();
        if (!bothErrors && !typeChecker.isSubtypeOf(subReturnType, superReturnType)) {
          return OverrideCompatibilityInfo.conflict("Return type mismatch");
        }
      }
    }

    return OverrideCompatibilityInfo.success();
  }
Beispiel #3
0
  @Nullable
  static OverrideCompatibilityInfo checkReceiverAndParameterCount(
      CallableDescriptor superDescriptor, CallableDescriptor subDescriptor) {
    if ((superDescriptor.getExtensionReceiverParameter() == null)
        != (subDescriptor.getExtensionReceiverParameter() == null)) {
      return OverrideCompatibilityInfo.incompatible("Receiver presence mismatch");
    }

    if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
      return OverrideCompatibilityInfo.incompatible("Value parameter number mismatch");
    }

    return null;
  }
Beispiel #4
0
  @NotNull
  private OverrideCompatibilityInfo isOverridableBy(
      @NotNull CallableDescriptor superDescriptor,
      @NotNull CallableDescriptor subDescriptor,
      boolean checkReturnType) {
    for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
      ExternalOverridabilityCondition.Result result =
          externalCondition.isOverridable(superDescriptor, subDescriptor);
      switch (result) {
        case OVERRIDABLE:
          return OverrideCompatibilityInfo.success();
        case CONFLICT:
          return OverrideCompatibilityInfo.conflict("External condition failed");
        case INCOMPATIBLE:
          return OverrideCompatibilityInfo.incompatible("External condition");
        case UNKNOWN:
          // do nothing
          // go to the next external condition or default override check
      }
    }

    return isOverridableByWithoutExternalConditions(
        superDescriptor, subDescriptor, checkReturnType);
  }
Beispiel #5
0
  @NotNull
  public OverrideCompatibilityInfo isOverridableByWithoutExternalConditions(
      @NotNull CallableDescriptor superDescriptor,
      @NotNull CallableDescriptor subDescriptor,
      boolean checkReturnType) {
    if (superDescriptor instanceof FunctionDescriptor
            && !(subDescriptor instanceof FunctionDescriptor)
        || superDescriptor instanceof PropertyDescriptor
            && !(subDescriptor instanceof PropertyDescriptor)) {
      return OverrideCompatibilityInfo.incompatible("Member kind mismatch");
    }

    if (!(superDescriptor instanceof FunctionDescriptor)
        && !(superDescriptor instanceof PropertyDescriptor)) {
      throw new IllegalArgumentException(
          "This type of CallableDescriptor cannot be checked for overridability: "
              + superDescriptor);
    }

    // TODO: check outside of this method
    if (!superDescriptor.getName().equals(subDescriptor.getName())) {
      return OverrideCompatibilityInfo.incompatible("Name mismatch");
    }

    OverrideCompatibilityInfo receiverAndParameterResult =
        checkReceiverAndParameterCount(superDescriptor, subDescriptor);
    if (receiverAndParameterResult != null) {
      return receiverAndParameterResult;
    }

    List<KotlinType> superValueParameters = compiledValueParameters(superDescriptor);
    List<KotlinType> subValueParameters = compiledValueParameters(subDescriptor);

    List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
    List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();

    if (superTypeParameters.size() != subTypeParameters.size()) {
      for (int i = 0; i < superValueParameters.size(); ++i) {
        // TODO: compare erasure
        if (!KotlinTypeChecker.DEFAULT.equalTypes(
            superValueParameters.get(i), subValueParameters.get(i))) {
          return OverrideCompatibilityInfo.incompatible("Type parameter number mismatch");
        }
      }
      return OverrideCompatibilityInfo.conflict("Type parameter number mismatch");
    }

    KotlinTypeChecker typeChecker = createTypeChecker(superTypeParameters, subTypeParameters);

    for (int i = 0; i < superTypeParameters.size(); i++) {
      if (!areTypeParametersEquivalent(
          superTypeParameters.get(i), subTypeParameters.get(i), typeChecker)) {
        return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch");
      }
    }

    for (int i = 0; i < superValueParameters.size(); i++) {
      if (!areTypesEquivalent(
          superValueParameters.get(i), subValueParameters.get(i), typeChecker)) {
        return OverrideCompatibilityInfo.incompatible("Value parameter type mismatch");
      }
    }

    if (checkReturnType) {
      KotlinType superReturnType = superDescriptor.getReturnType();
      KotlinType subReturnType = subDescriptor.getReturnType();

      if (superReturnType != null && subReturnType != null) {
        boolean bothErrors = subReturnType.isError() && superReturnType.isError();
        if (!bothErrors && !typeChecker.isSubtypeOf(subReturnType, superReturnType)) {
          return OverrideCompatibilityInfo.conflict("Return type mismatch");
        }
      }
    }

    return OverrideCompatibilityInfo.success();
  }
Beispiel #6
0
  @NotNull
  public OverrideCompatibilityInfo isOverridableBy(
      @NotNull CallableDescriptor superDescriptor,
      @NotNull CallableDescriptor subDescriptor,
      @Nullable ClassDescriptor subClassDescriptor,
      boolean checkReturnType) {
    OverrideCompatibilityInfo basicResult =
        isOverridableByWithoutExternalConditions(superDescriptor, subDescriptor, checkReturnType);
    boolean wasSuccess = basicResult.getResult() == OVERRIDABLE;

    for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
      // Do not run CONFLICTS_ONLY while there was no success
      if (externalCondition.getContract()
          == ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY) continue;
      if (wasSuccess
          && externalCondition.getContract()
              == ExternalOverridabilityCondition.Contract.SUCCESS_ONLY) continue;

      ExternalOverridabilityCondition.Result result =
          externalCondition.isOverridable(superDescriptor, subDescriptor, subClassDescriptor);

      switch (result) {
        case OVERRIDABLE:
          wasSuccess = true;
          break;
        case CONFLICT:
          return OverrideCompatibilityInfo.conflict("External condition failed");
        case INCOMPATIBLE:
          return OverrideCompatibilityInfo.incompatible("External condition");
        case UNKNOWN:
          // do nothing
          // go to the next external condition or default override check
      }
    }

    if (!wasSuccess) {
      return basicResult;
    }

    // Search for conflicts from external conditions
    for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
      // Run all conditions that was not run before (i.e. CONFLICTS_ONLY)
      if (externalCondition.getContract()
          != ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY) continue;

      ExternalOverridabilityCondition.Result result =
          externalCondition.isOverridable(superDescriptor, subDescriptor, subClassDescriptor);
      switch (result) {
        case CONFLICT:
          return OverrideCompatibilityInfo.conflict("External condition failed");
        case INCOMPATIBLE:
          return OverrideCompatibilityInfo.incompatible("External condition");
        case OVERRIDABLE:
          throw new IllegalStateException(
              "Contract violation in "
                  + externalCondition.getClass().getName()
                  + " condition. It's not supposed to end with success");
        case UNKNOWN:
          // do nothing
          // go to the next external condition or default override check
      }
    }

    return OverrideCompatibilityInfo.success();
  }