001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.load.java.sam;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.descriptors.*;
022    import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
023    import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition;
024    import org.jetbrains.kotlin.types.JetType;
025    import org.jetbrains.kotlin.types.TypeSubstitutor;
026    import org.jetbrains.kotlin.types.TypeUtils;
027    
028    import java.util.List;
029    
030    public class SamAdapterOverridabilityCondition implements ExternalOverridabilityCondition {
031        @Override
032        public boolean isOverridable(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
033            if (!(subDescriptor instanceof SimpleFunctionDescriptor)) {
034                return true;
035            }
036    
037            SimpleFunctionDescriptor superOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) superDescriptor);
038            SimpleFunctionDescriptor subOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) subDescriptor);
039            if (superOriginal == null || subOriginal == null) { // super or sub is/overrides DECLARATION
040                return subOriginal == null; // DECLARATION can override anything
041            }
042    
043            // inheritor if SYNTHESIZED can override inheritor of SYNTHESIZED if their originals have same erasure
044            return equalErasure(superOriginal, subOriginal);
045        }
046    
047        private static boolean equalErasure(@NotNull FunctionDescriptor fun1, @NotNull FunctionDescriptor fun2) {
048            List<ValueParameterDescriptor> parameters1 = fun1.getValueParameters();
049            List<ValueParameterDescriptor> parameters2 = fun2.getValueParameters();
050    
051            for (ValueParameterDescriptor param1 : parameters1) {
052                ValueParameterDescriptor param2 = parameters2.get(param1.getIndex());
053                if (differentClasses(param2.getType(), param1.getType())) {
054                    return false;
055                }
056            }
057            return true;
058        }
059    
060        private static boolean differentClasses(@NotNull JetType type1, @NotNull JetType type2) {
061            DeclarationDescriptor declarationDescriptor1 = type1.getConstructor().getDeclarationDescriptor();
062            if (declarationDescriptor1 == null) return true; // No class, classes are not equal
063            DeclarationDescriptor declarationDescriptor2 = type2.getConstructor().getDeclarationDescriptor();
064            if (declarationDescriptor2 == null) return true; // Class of type1 is not null
065    
066            if (declarationDescriptor1 instanceof TypeParameterDescriptor && declarationDescriptor2 instanceof TypeParameterDescriptor) {
067                // if type of value parameter is some generic parameter then their equality was checked by OverridingUtil before calling ExternalOverridabilityCondition
068                // Note that it's true unless we generate sam adapter for type parameter with SAM interface as upper bound:
069                // <K extends Runnable >void foo(K runnable) {}
070                return false;
071            }
072    
073            return !declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal());
074        }
075    
076        // if function is or overrides declaration, returns null; otherwise, return original of sam adapter with substituted type parameters
077        @Nullable
078        private static SimpleFunctionDescriptor getOriginalOfSamAdapterFunction(@NotNull SimpleFunctionDescriptor callable) {
079            DeclarationDescriptor containingDeclaration = callable.getContainingDeclaration();
080            if (!(containingDeclaration instanceof ClassDescriptor)) {
081                return null;
082            }
083            SamAdapterInfo declarationOrSynthesized =
084                    getNearestDeclarationOrSynthesized(callable, ((ClassDescriptor) containingDeclaration).getDefaultType());
085    
086            if (declarationOrSynthesized == null) {
087                return null;
088            }
089    
090            SimpleFunctionDescriptorImpl fun = (SimpleFunctionDescriptorImpl) declarationOrSynthesized.samAdapter.getOriginal();
091            if (!(fun instanceof SamAdapterFunctionDescriptor)) {
092                return null;
093            }
094    
095            SimpleFunctionDescriptor originalDeclarationOfSam = ((SamAdapterFunctionDescriptor) fun).getOriginForSam();
096    
097            return ((SimpleFunctionDescriptor) originalDeclarationOfSam.substitute(TypeSubstitutor.create(declarationOrSynthesized.ownerType)));
098        }
099    
100        @Nullable
101        private static SamAdapterInfo getNearestDeclarationOrSynthesized(
102                @NotNull SimpleFunctionDescriptor samAdapter,
103                @NotNull JetType ownerType
104        ) {
105            if (samAdapter.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
106                return new SamAdapterInfo(samAdapter, ownerType);
107            }
108    
109            for (CallableMemberDescriptor overridden : samAdapter.getOverriddenDescriptors()) {
110                ClassDescriptor containingClass = (ClassDescriptor) overridden.getContainingDeclaration();
111    
112                for (JetType immediateSupertype : TypeUtils.getImmediateSupertypes(ownerType)) {
113                    if (containingClass != immediateSupertype.getConstructor().getDeclarationDescriptor()) {
114                        continue;
115                    }
116    
117                    SamAdapterInfo found = getNearestDeclarationOrSynthesized((SimpleFunctionDescriptor) overridden, immediateSupertype);
118                    if (found != null) {
119                        return found;
120                    }
121                }
122            }
123    
124            return null;
125        }
126    
127        private static class SamAdapterInfo {
128            private final SimpleFunctionDescriptor samAdapter;
129            private final JetType ownerType;
130    
131            private SamAdapterInfo(@NotNull SimpleFunctionDescriptor samAdapter, @NotNull JetType ownerType) {
132                this.samAdapter = samAdapter;
133                this.ownerType = ownerType;
134            }
135        }
136    }