Created extension point for overridability checks.
This commit is contained in:
+1
@@ -0,0 +1 @@
|
|||||||
|
org.jetbrains.jet.lang.resolve.java.sam.SamAdapterOverridabilityCondition
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
package org.jetbrains.jet.lang.resolve.java.sam;
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.Pair;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||||
|
import org.jetbrains.jet.lang.resolve.ExternalOverridabilityCondition;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
||||||
|
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SamAdapterOverridabilityCondition implements ExternalOverridabilityCondition {
|
||||||
|
@Override
|
||||||
|
public boolean isOverridable(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
|
||||||
|
if (subDescriptor instanceof PropertyDescriptor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleFunctionDescriptor superOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) superDescriptor);
|
||||||
|
SimpleFunctionDescriptor subOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) subDescriptor);
|
||||||
|
if (superOriginal == null || subOriginal == null) { // super or sub is/overrides DECLARATION
|
||||||
|
return subOriginal == null; // DECLARATION can override anything
|
||||||
|
}
|
||||||
|
|
||||||
|
// inheritor if SYNTHESIZED can override inheritor of SYNTHESIZED if their originals have same erasure
|
||||||
|
return equalErasure(superOriginal, subOriginal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean equalErasure(@NotNull FunctionDescriptor fun1, @NotNull FunctionDescriptor fun2) {
|
||||||
|
List<ValueParameterDescriptor> parameters1 = fun1.getValueParameters();
|
||||||
|
List<ValueParameterDescriptor> parameters2 = fun2.getValueParameters();
|
||||||
|
|
||||||
|
for (ValueParameterDescriptor param1 : parameters1) {
|
||||||
|
ValueParameterDescriptor param2 = parameters2.get(param1.getIndex());
|
||||||
|
if (!TypeUtils.equalClasses(param2.getType(), param1.getType())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if function is or overrides declaration, returns null; otherwise, return original of sam adapter with substituted type parameters
|
||||||
|
@Nullable
|
||||||
|
private static SimpleFunctionDescriptor getOriginalOfSamAdapterFunction(@NotNull SimpleFunctionDescriptor callable) {
|
||||||
|
DeclarationDescriptor containingDeclaration = callable.getContainingDeclaration();
|
||||||
|
if (!(containingDeclaration instanceof ClassDescriptor)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Pair<SimpleFunctionDescriptor, JetType> declarationOrSynthesized =
|
||||||
|
getNearestDeclarationOrSynthesized(callable, ((ClassDescriptor) containingDeclaration).getDefaultType());
|
||||||
|
|
||||||
|
if (declarationOrSynthesized == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleFunctionDescriptor fun = declarationOrSynthesized.first;
|
||||||
|
if (fun.getKind() != CallableMemberDescriptor.Kind.SYNTHESIZED) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleFunctionDescriptor originalOfSynthesized = ((SimpleFunctionDescriptorImpl) fun.getOriginal())
|
||||||
|
.getOriginalOfSynthesized();
|
||||||
|
if (originalOfSynthesized == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((SimpleFunctionDescriptor) originalOfSynthesized.substitute(TypeSubstitutor.create(declarationOrSynthesized.second)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static Pair<SimpleFunctionDescriptor, JetType> getNearestDeclarationOrSynthesized(
|
||||||
|
@NotNull SimpleFunctionDescriptor samAdapter,
|
||||||
|
@NotNull JetType ownerType
|
||||||
|
) {
|
||||||
|
if (samAdapter.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||||
|
return Pair.create(samAdapter, ownerType);
|
||||||
|
}
|
||||||
|
for (CallableMemberDescriptor overridden : samAdapter.getOverriddenDescriptors()) {
|
||||||
|
ClassDescriptor containingClass = (ClassDescriptor) overridden.getContainingDeclaration();
|
||||||
|
|
||||||
|
for (JetType immediateSupertype : TypeUtils.getImmediateSupertypes(ownerType)) {
|
||||||
|
if (containingClass != immediateSupertype.getConstructor().getDeclarationDescriptor()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pair<SimpleFunctionDescriptor, JetType> found =
|
||||||
|
getNearestDeclarationOrSynthesized((SimpleFunctionDescriptor) overridden, immediateSupertype);
|
||||||
|
if (found != null) {
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package org.jetbrains.jet.lang.resolve;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
|
|
||||||
|
public interface ExternalOverridabilityCondition {
|
||||||
|
boolean isOverridable(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor);
|
||||||
|
}
|
||||||
@@ -185,8 +185,11 @@ public class OverridingUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isOverridableSynthesized(superDescriptor, subDescriptor)) {
|
for (ExternalOverridabilityCondition externalCondition : ServiceLoader
|
||||||
return OverrideCompatibilityInfo.synthesizedAndDeclarationIncompatible();
|
.load(ExternalOverridabilityCondition.class)) {
|
||||||
|
if (!externalCondition.isOverridable(superDescriptor, subDescriptor)) {
|
||||||
|
return OverrideCompatibilityInfo.externalConditionFailed(externalCondition.getClass());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -301,89 +304,6 @@ public class OverridingUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isOverridableSynthesized(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
|
|
||||||
if (subDescriptor instanceof PropertyDescriptor) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleFunctionDescriptor superOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) superDescriptor);
|
|
||||||
SimpleFunctionDescriptor subOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) subDescriptor);
|
|
||||||
if (superOriginal == null || subOriginal == null) { // super or sub is/overrides DECLARATION
|
|
||||||
return subOriginal == null; // DECLARATION can override anything
|
|
||||||
}
|
|
||||||
|
|
||||||
// inheritor if SYNTHESIZED can override inheritor of SYNTHESIZED if their originals have same erasure
|
|
||||||
return equalErasure(superOriginal, subOriginal);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean equalErasure(@NotNull FunctionDescriptor fun1, @NotNull FunctionDescriptor fun2) {
|
|
||||||
List<ValueParameterDescriptor> parameters1 = fun1.getValueParameters();
|
|
||||||
List<ValueParameterDescriptor> parameters2 = fun2.getValueParameters();
|
|
||||||
|
|
||||||
for (ValueParameterDescriptor param1 : parameters1) {
|
|
||||||
ValueParameterDescriptor param2 = parameters2.get(param1.getIndex());
|
|
||||||
if (!TypeUtils.equalClasses(param2.getType(), param1.getType())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if function is or overrides declaration, returns null; otherwise, return original of sam adapter with substituted type parameters
|
|
||||||
@Nullable
|
|
||||||
private static SimpleFunctionDescriptor getOriginalOfSamAdapterFunction(@NotNull SimpleFunctionDescriptor callable) {
|
|
||||||
DeclarationDescriptor containingDeclaration = callable.getContainingDeclaration();
|
|
||||||
if (!(containingDeclaration instanceof ClassDescriptor)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Pair<SimpleFunctionDescriptor, JetType> declarationOrSynthesized =
|
|
||||||
getNearestDeclarationOrSynthesized(callable, ((ClassDescriptor) containingDeclaration).getDefaultType());
|
|
||||||
|
|
||||||
if (declarationOrSynthesized == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleFunctionDescriptor fun = declarationOrSynthesized.first;
|
|
||||||
if (fun.getKind() != CallableMemberDescriptor.Kind.SYNTHESIZED) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleFunctionDescriptor originalOfSynthesized = ((SimpleFunctionDescriptorImpl) fun.getOriginal())
|
|
||||||
.getOriginalOfSynthesized();
|
|
||||||
if (originalOfSynthesized == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((SimpleFunctionDescriptor) originalOfSynthesized.substitute(TypeSubstitutor.create(declarationOrSynthesized.second)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static Pair<SimpleFunctionDescriptor, JetType> getNearestDeclarationOrSynthesized(
|
|
||||||
@NotNull SimpleFunctionDescriptor samAdapter,
|
|
||||||
@NotNull JetType ownerType
|
|
||||||
) {
|
|
||||||
if (samAdapter.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
|
||||||
return Pair.create(samAdapter, ownerType);
|
|
||||||
}
|
|
||||||
for (CallableMemberDescriptor overridden : samAdapter.getOverriddenDescriptors()) {
|
|
||||||
ClassDescriptor containingClass = (ClassDescriptor) overridden.getContainingDeclaration();
|
|
||||||
|
|
||||||
for (JetType immediateSupertype : TypeUtils.getImmediateSupertypes(ownerType)) {
|
|
||||||
if (containingClass != immediateSupertype.getConstructor().getDeclarationDescriptor()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pair<SimpleFunctionDescriptor, JetType> found =
|
|
||||||
getNearestDeclarationOrSynthesized((SimpleFunctionDescriptor) overridden, immediateSupertype);
|
|
||||||
if (found != null) {
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class OverrideCompatibilityInfo {
|
public static class OverrideCompatibilityInfo {
|
||||||
|
|
||||||
public enum Result {
|
public enum Result {
|
||||||
@@ -445,8 +365,8 @@ public class OverridingUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static OverrideCompatibilityInfo synthesizedAndDeclarationIncompatible() {
|
public static OverrideCompatibilityInfo externalConditionFailed(Class<? extends ExternalOverridabilityCondition> conditionClass) {
|
||||||
return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "synthesizedAndDeclarationIncompatible"); // TODO
|
return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "externalConditionFailed: " + conditionClass.getName()); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
Reference in New Issue
Block a user