@NotNull @SuppressWarnings("unchecked") public static <D extends CallableDescriptor> Set<D> getAllOverriddenDescriptors(@NotNull D f) { Set<D> result = new LinkedHashSet<D>(); collectAllOverriddenDescriptors((D) f.getOriginal(), result); return result; }
private static <D extends CallableDescriptor> void collectAllOverriddenDescriptors( @NotNull D current, @NotNull Set<D> result) { if (result.contains(current)) return; for (CallableDescriptor callableDescriptor : current.getOriginal().getOverriddenDescriptors()) { @SuppressWarnings("unchecked") D descriptor = (D) callableDescriptor; collectAllOverriddenDescriptors(descriptor, result); result.add(descriptor); } }
/** @return whether f overrides g */ public static <D extends CallableDescriptor> boolean overrides(@NotNull D f, @NotNull D g) { // In a multi-module project different "copies" of the same class may be present in different // libraries, // that's why we use structural equivalence for members (DescriptorEquivalenceForOverrides). // This first check cover the case of duplicate classes in different modules: // when B is defined in modules m1 and m2, and C (indirectly) inherits from both versions, // we'll be getting sets of members that do not override each other, but are structurally // equivalent. // As other code relies on no equal descriptors passed here, we guard against f == g, but this // may not be necessary // Note that this is needed for the usage of this function in the IDE code if (!f.equals(g) && DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent( f.getOriginal(), g.getOriginal())) return true; CallableDescriptor originalG = g.getOriginal(); for (D overriddenFunction : DescriptorUtils.getAllOverriddenDescriptors(f)) { if (DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(originalG, overriddenFunction)) return true; } return false; }