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    }