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