Move some members from OverrideResolver to OverridingUtil
This commit is contained in:
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo
|
||||
|
||||
object DescriptorEquivalenceForOverrides {
|
||||
|
||||
fun areEquivalent(a: DeclarationDescriptor?, b: DeclarationDescriptor?): Boolean {
|
||||
return when {
|
||||
a is ClassDescriptor &&
|
||||
b is ClassDescriptor -> areClassesEquivalent(a, b)
|
||||
|
||||
a is TypeParameterDescriptor &&
|
||||
b is TypeParameterDescriptor -> areTypeParametersEquivalent(a, b)
|
||||
|
||||
a is CallableDescriptor &&
|
||||
b is CallableDescriptor -> areCallableDescriptorsEquivalent(a, b)
|
||||
|
||||
a is PackageFragmentDescriptor &&
|
||||
b is PackageFragmentDescriptor -> (a).fqName == (b).fqName
|
||||
|
||||
else -> a == b
|
||||
}
|
||||
}
|
||||
|
||||
private fun areClassesEquivalent(a: ClassDescriptor, b: ClassDescriptor): Boolean {
|
||||
// type constructors are compared by fqName
|
||||
return a.typeConstructor == b.typeConstructor
|
||||
}
|
||||
|
||||
private fun areTypeParametersEquivalent(
|
||||
a: TypeParameterDescriptor,
|
||||
b: TypeParameterDescriptor,
|
||||
equivalentCallables: (DeclarationDescriptor?, DeclarationDescriptor?) -> Boolean = {x, y -> false}
|
||||
): Boolean {
|
||||
if (a == b) return true
|
||||
if (a.containingDeclaration == b.containingDeclaration) return false
|
||||
|
||||
if (!ownersEquivalent(a, b, equivalentCallables)) return false
|
||||
|
||||
return a.index == b.index // We ignore type parameter names
|
||||
}
|
||||
|
||||
fun areCallableDescriptorsEquivalent(
|
||||
a: CallableDescriptor,
|
||||
b: CallableDescriptor,
|
||||
ignoreReturnType: Boolean = false
|
||||
): Boolean {
|
||||
if (a == b) return true
|
||||
if (a.name != b.name) return false
|
||||
if (a.containingDeclaration == b.containingDeclaration) return false
|
||||
|
||||
// Distinct locals are not equivalent
|
||||
if (DescriptorUtils.isLocal(a) || DescriptorUtils.isLocal(b)) return false
|
||||
|
||||
if (!ownersEquivalent(a, b, {x, y -> false})) return false
|
||||
|
||||
val overridingUtil = OverridingUtil.createWithEqualityAxioms eq@ {
|
||||
c1, c2 ->
|
||||
if (c1 == c2) return@eq true
|
||||
|
||||
val d1 = c1.declarationDescriptor
|
||||
val d2 = c2.declarationDescriptor
|
||||
|
||||
if (d1 !is TypeParameterDescriptor || d2 !is TypeParameterDescriptor) return@eq false
|
||||
|
||||
areTypeParametersEquivalent(d1, d2, {x, y -> x == a && y == b})
|
||||
}
|
||||
|
||||
return overridingUtil.isOverridableBy(a, b, null, !ignoreReturnType).result == OverrideCompatibilityInfo.Result.OVERRIDABLE
|
||||
&& overridingUtil.isOverridableBy(b, a, null, !ignoreReturnType).result == OverrideCompatibilityInfo.Result.OVERRIDABLE
|
||||
|
||||
}
|
||||
|
||||
private fun ownersEquivalent(
|
||||
a: DeclarationDescriptor,
|
||||
b: DeclarationDescriptor,
|
||||
equivalentCallables: (DeclarationDescriptor?, DeclarationDescriptor?) -> Boolean
|
||||
): Boolean {
|
||||
val aOwner = a.containingDeclaration
|
||||
val bOwner = b.containingDeclaration
|
||||
|
||||
// This check is needed when we call areTypeParametersEquivalent() from areCallableMemberDescriptorsEquivalent:
|
||||
// if the type parameter owners are, e.g., functions, we'll go into infinite recursion here
|
||||
if (aOwner is CallableMemberDescriptor || bOwner is CallableMemberDescriptor) {
|
||||
return equivalentCallables(aOwner, bOwner)
|
||||
}
|
||||
else {
|
||||
return areEquivalent(aOwner, bOwner)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeConstructor;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeCheckerImpl;
|
||||
import org.jetbrains.kotlin.utils.FunctionsKt;
|
||||
import org.jetbrains.kotlin.utils.SmartSet;
|
||||
|
||||
import java.util.*;
|
||||
@@ -64,6 +65,91 @@ public class OverridingUtil {
|
||||
equalityAxioms = axioms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a set of descriptors, returns a set containing all the given descriptors except those which _are overridden_ by at least
|
||||
* one other descriptor from the original set.
|
||||
*/
|
||||
@NotNull
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <D extends CallableDescriptor> Set<D> filterOutOverridden(@NotNull Set<D> candidateSet) {
|
||||
return filterOverrides(candidateSet, FunctionsKt.<CallableDescriptor>identity());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <D> Set<D> filterOverrides(
|
||||
@NotNull Set<D> candidateSet,
|
||||
@NotNull Function1<? super D, ? extends CallableDescriptor> transform
|
||||
) {
|
||||
if (candidateSet.size() <= 1) return candidateSet;
|
||||
|
||||
Set<D> result = new LinkedHashSet<D>();
|
||||
outerLoop:
|
||||
for (D meD : candidateSet) {
|
||||
CallableDescriptor me = transform.invoke(meD);
|
||||
for (Iterator<D> iterator = result.iterator(); iterator.hasNext(); ) {
|
||||
D otherD = iterator.next();
|
||||
CallableDescriptor other = transform.invoke(otherD);
|
||||
if (overrides(me, other)) {
|
||||
iterator.remove();
|
||||
}
|
||||
else if (overrides(other, me)) {
|
||||
continue outerLoop;
|
||||
}
|
||||
}
|
||||
result.add(meD);
|
||||
}
|
||||
|
||||
assert !result.isEmpty() : "All candidates filtered out from " + candidateSet;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
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.getOriginal())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return overridden real descriptors (not fake overrides). Note that most usages of this method should be followed by calling
|
||||
* {@link #filterOutOverridden(Set)}, because some of the declarations can override the other.
|
||||
*/
|
||||
@NotNull
|
||||
public static Set<CallableMemberDescriptor> getOverriddenDeclarations(@NotNull CallableMemberDescriptor descriptor) {
|
||||
Set<CallableMemberDescriptor> result = new LinkedHashSet<CallableMemberDescriptor>();
|
||||
collectOverriddenDeclarations(descriptor, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void collectOverriddenDeclarations(
|
||||
@NotNull CallableMemberDescriptor descriptor,
|
||||
@NotNull Set<CallableMemberDescriptor> result
|
||||
) {
|
||||
if (descriptor.getKind().isReal()) {
|
||||
result.add(descriptor);
|
||||
}
|
||||
else {
|
||||
if (descriptor.getOverriddenDescriptors().isEmpty()) {
|
||||
throw new IllegalStateException("No overridden descriptors found for (fake override) " + descriptor);
|
||||
}
|
||||
for (CallableMemberDescriptor overridden : descriptor.getOverriddenDescriptors()) {
|
||||
collectOverriddenDeclarations(overridden, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public OverrideCompatibilityInfo isOverridableBy(
|
||||
@NotNull CallableDescriptor superDescriptor,
|
||||
|
||||
Reference in New Issue
Block a user