@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); }
@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; }
@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; }
/** * 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; }
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); }
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); }