Exemple #1
0
  @NotNull
  public static <H> H selectMostSpecificMember(
      @NotNull Collection<H> overridables,
      @NotNull Function1<H, CallableDescriptor> descriptorByHandle) {
    assert !overridables.isEmpty() : "Should have at least one overridable descriptor";

    if (overridables.size() == 1) {
      return CollectionsKt.first(overridables);
    }

    Collection<H> candidates = new ArrayList<H>(2);
    List<CallableDescriptor> callableMemberDescriptors =
        CollectionsKt.map(overridables, descriptorByHandle);

    H transitivelyMostSpecific = CollectionsKt.first(overridables);
    CallableDescriptor transitivelyMostSpecificDescriptor =
        descriptorByHandle.invoke(transitivelyMostSpecific);

    for (H overridable : overridables) {
      CallableDescriptor descriptor = descriptorByHandle.invoke(overridable);
      if (isMoreSpecificThenAllOf(descriptor, callableMemberDescriptors)) {
        candidates.add(overridable);
      }
      if (isMoreSpecific(descriptor, transitivelyMostSpecificDescriptor)
          && !isMoreSpecific(transitivelyMostSpecificDescriptor, descriptor)) {
        transitivelyMostSpecific = overridable;
      }
    }

    if (candidates.isEmpty()) {
      return transitivelyMostSpecific;
    } else if (candidates.size() == 1) {
      return CollectionsKt.first(candidates);
    }

    H firstNonFlexible = null;
    for (H candidate : candidates) {
      //noinspection ConstantConditions
      if (!FlexibleTypesKt.isFlexible(descriptorByHandle.invoke(candidate).getReturnType())) {
        firstNonFlexible = candidate;
        break;
      }
    }
    if (firstNonFlexible != null) {
      return firstNonFlexible;
    }

    return CollectionsKt.first(candidates);
  }
Exemple #2
0
 @Nullable
 public static Visibility findMaxVisibility(
     @NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
   if (descriptors.isEmpty()) {
     return Visibilities.DEFAULT_VISIBILITY;
   }
   Visibility maxVisibility = null;
   for (CallableMemberDescriptor descriptor : descriptors) {
     Visibility visibility = descriptor.getVisibility();
     assert visibility != Visibilities.INHERITED
         : "Visibility should have been computed for " + descriptor;
     if (maxVisibility == null) {
       maxVisibility = visibility;
       continue;
     }
     Integer compareResult = Visibilities.compare(visibility, maxVisibility);
     if (compareResult == null) {
       maxVisibility = null;
     } else if (compareResult > 0) {
       maxVisibility = visibility;
     }
   }
   if (maxVisibility == null) {
     return null;
   }
   for (CallableMemberDescriptor descriptor : descriptors) {
     Integer compareResult = Visibilities.compare(maxVisibility, descriptor.getVisibility());
     if (compareResult == null || compareResult < 0) {
       return null;
     }
   }
   return maxVisibility;
 }
Exemple #3
0
 @Nullable
 private static Visibility findMaxVisibility(
     @NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
   if (descriptors.isEmpty()) {
     return Visibilities.INTERNAL;
   }
   Visibility maxVisibility = null;
   for (CallableMemberDescriptor descriptor : descriptors) {
     Visibility visibility = descriptor.getVisibility();
     assert visibility != Visibilities.INHERITED
         : "Visibility should have been computed for " + descriptor;
     if (maxVisibility == null) {
       maxVisibility = visibility;
       continue;
     }
     Integer compareResult = Visibilities.compare(visibility, maxVisibility);
     if (compareResult == null) {
       maxVisibility = null;
     } else if (compareResult > 0) {
       maxVisibility = visibility;
     }
   }
   // TODO: IDEA seems to issue an incorrect warning here
   //noinspection ConstantConditions
   if (maxVisibility == null) {
     return null;
   }
   for (CallableMemberDescriptor descriptor : descriptors) {
     Integer compareResult = Visibilities.compare(maxVisibility, descriptor.getVisibility());
     if (compareResult == null || compareResult < 0) {
       return null;
     }
   }
   return maxVisibility;
 }
Exemple #4
0
 /**
  * Given a fake override, finds any declaration of it in the overridden descriptors. Keep in mind
  * that there may be many declarations of the fake override in the supertypes, this method finds
  * just the only one. TODO: probably all call-sites of this method are wrong, they should handle
  * all super-declarations
  */
 @NotNull
 @SuppressWarnings("unchecked")
 public static <D extends CallableMemberDescriptor> D unwrapFakeOverride(@NotNull D descriptor) {
   while (descriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
     Collection<? extends CallableMemberDescriptor> overridden =
         descriptor.getOverriddenDescriptors();
     if (overridden.isEmpty()) {
       throw new IllegalStateException(
           "Fake override should have at least one overridden descriptor: " + descriptor);
     }
     descriptor = (D) overridden.iterator().next();
   }
   return descriptor;
 }
Exemple #5
0
  private static void createAndBindFakeOverride(
      @NotNull Collection<CallableMemberDescriptor> overridables,
      @NotNull ClassDescriptor current,
      @NotNull DescriptorSink sink) {
    Collection<CallableMemberDescriptor> visibleOverridables =
        filterVisibleFakeOverrides(current, overridables);
    boolean allInvisible = visibleOverridables.isEmpty();
    Collection<CallableMemberDescriptor> effectiveOverridden =
        allInvisible ? overridables : visibleOverridables;

    Modality modality = getMinimalModality(effectiveOverridden);
    Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED;
    CallableMemberDescriptor mostSpecific = selectMostSpecificMemberFromSuper(effectiveOverridden);
    CallableMemberDescriptor fakeOverride =
        mostSpecific.copy(
            current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
    for (CallableMemberDescriptor descriptor : effectiveOverridden) {
      fakeOverride.addOverriddenDescriptor(descriptor);
    }
    sink.addFakeOverride(fakeOverride);
  }
Exemple #6
0
  private static void createAndBindFakeOverride(
      @NotNull Collection<CallableMemberDescriptor> overridables,
      @NotNull ClassDescriptor current,
      @NotNull OverridingStrategy strategy) {
    Collection<CallableMemberDescriptor> visibleOverridables =
        filterVisibleFakeOverrides(current, overridables);
    boolean allInvisible = visibleOverridables.isEmpty();
    Collection<CallableMemberDescriptor> effectiveOverridden =
        allInvisible ? overridables : visibleOverridables;

    Modality modality = determineModality(effectiveOverridden);
    Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED;

    // FIXME doesn't work as expected for flexible types: should create a refined signature.
    // Current algorithm produces bad results in presence of annotated Java signatures such as:
    //      J: foo(s: String!): String -- @NotNull String foo(String s);
    //      K: foo(s: String): String?
    //  --> 'foo(s: String!): String' as an inherited signature with most specific return type.
    // This is bad because it can be overridden by 'foo(s: String?): String', which is not
    // override-equivalent with K::foo above.
    // Should be 'foo(s: String): String'.
    CallableMemberDescriptor mostSpecific =
        selectMostSpecificMember(
            effectiveOverridden,
            new Function1<CallableMemberDescriptor, CallableDescriptor>() {
              @Override
              public CallableMemberDescriptor invoke(CallableMemberDescriptor descriptor) {
                return descriptor;
              }
            });
    CallableMemberDescriptor fakeOverride =
        mostSpecific.copy(
            current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
    strategy.setOverriddenDescriptors(fakeOverride, effectiveOverridden);
    assert !fakeOverride.getOverriddenDescriptors().isEmpty()
        : "Overridden descriptors should be set for " + CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
    strategy.addFakeOverride(fakeOverride);
  }