001 package org.jetbrains.jet.lang.resolve.java.sam;
002
003 import com.intellij.openapi.util.Pair;
004 import org.jetbrains.annotations.NotNull;
005 import org.jetbrains.annotations.Nullable;
006 import org.jetbrains.jet.lang.descriptors.*;
007 import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
008 import org.jetbrains.jet.lang.resolve.ExternalOverridabilityCondition;
009 import org.jetbrains.jet.lang.types.JetType;
010 import org.jetbrains.jet.lang.types.TypeSubstitutor;
011 import org.jetbrains.jet.lang.types.TypeUtils;
012
013 import java.util.List;
014
015 public class SamAdapterOverridabilityCondition implements ExternalOverridabilityCondition {
016 @Override
017 public boolean isOverridable(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
018 if (subDescriptor instanceof PropertyDescriptor) {
019 return true;
020 }
021
022 SimpleFunctionDescriptor superOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) superDescriptor);
023 SimpleFunctionDescriptor subOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) subDescriptor);
024 if (superOriginal == null || subOriginal == null) { // super or sub is/overrides DECLARATION
025 return subOriginal == null; // DECLARATION can override anything
026 }
027
028 // inheritor if SYNTHESIZED can override inheritor of SYNTHESIZED if their originals have same erasure
029 return equalErasure(superOriginal, subOriginal);
030 }
031
032 private static boolean equalErasure(@NotNull FunctionDescriptor fun1, @NotNull FunctionDescriptor fun2) {
033 List<ValueParameterDescriptor> parameters1 = fun1.getValueParameters();
034 List<ValueParameterDescriptor> parameters2 = fun2.getValueParameters();
035
036 for (ValueParameterDescriptor param1 : parameters1) {
037 ValueParameterDescriptor param2 = parameters2.get(param1.getIndex());
038 if (!TypeUtils.equalClasses(param2.getType(), param1.getType())) {
039 return false;
040 }
041 }
042 return true;
043 }
044
045 // if function is or overrides declaration, returns null; otherwise, return original of sam adapter with substituted type parameters
046 @Nullable
047 private static SimpleFunctionDescriptor getOriginalOfSamAdapterFunction(@NotNull SimpleFunctionDescriptor callable) {
048 DeclarationDescriptor containingDeclaration = callable.getContainingDeclaration();
049 if (!(containingDeclaration instanceof ClassDescriptor)) {
050 return null;
051 }
052 Pair<SimpleFunctionDescriptor, JetType> declarationOrSynthesized =
053 getNearestDeclarationOrSynthesized(callable, ((ClassDescriptor) containingDeclaration).getDefaultType());
054
055 if (declarationOrSynthesized == null) {
056 return null;
057 }
058
059 SimpleFunctionDescriptor fun = declarationOrSynthesized.first;
060 if (fun.getKind() != CallableMemberDescriptor.Kind.SYNTHESIZED) {
061 return null;
062 }
063
064 SimpleFunctionDescriptor originalOfSynthesized = ((SimpleFunctionDescriptorImpl) fun.getOriginal())
065 .getOriginalOfSynthesized();
066 if (originalOfSynthesized == null) {
067 return null;
068 }
069
070 return ((SimpleFunctionDescriptor) originalOfSynthesized.substitute(TypeSubstitutor.create(declarationOrSynthesized.second)));
071 }
072
073 @Nullable
074 private static Pair<SimpleFunctionDescriptor, JetType> getNearestDeclarationOrSynthesized(
075 @NotNull SimpleFunctionDescriptor samAdapter,
076 @NotNull JetType ownerType
077 ) {
078 if (samAdapter.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
079 return Pair.create(samAdapter, ownerType);
080 }
081 for (CallableMemberDescriptor overridden : samAdapter.getOverriddenDescriptors()) {
082 ClassDescriptor containingClass = (ClassDescriptor) overridden.getContainingDeclaration();
083
084 for (JetType immediateSupertype : TypeUtils.getImmediateSupertypes(ownerType)) {
085 if (containingClass != immediateSupertype.getConstructor().getDeclarationDescriptor()) {
086 continue;
087 }
088
089 Pair<SimpleFunctionDescriptor, JetType> found =
090 getNearestDeclarationOrSynthesized((SimpleFunctionDescriptor) overridden, immediateSupertype);
091 if (found != null) {
092 return found;
093 }
094 }
095
096 }
097 return null;
098 }
099
100 }