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.KotlinType;
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        @NotNull
032        @Override
033        public Result isOverridable(
034                @NotNull CallableDescriptor superDescriptor,
035                @NotNull CallableDescriptor subDescriptor,
036                @Nullable ClassDescriptor subClassDescriptor
037        ) {
038            if (!(subDescriptor instanceof SimpleFunctionDescriptor) || !(superDescriptor instanceof SimpleFunctionDescriptor)) {
039                return Result.UNKNOWN;
040            }
041    
042            SimpleFunctionDescriptor superOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) superDescriptor);
043            SimpleFunctionDescriptor subOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) subDescriptor);
044            if (superOriginal == null || subOriginal == null) { // super or sub is/overrides DECLARATION
045                return subOriginal == null ? Result.UNKNOWN : Result.INCOMPATIBLE; // DECLARATION can override anything
046            }
047    
048            // inheritor if SYNTHESIZED can override inheritor of SYNTHESIZED if their originals have same erasure
049            return equalErasure(superOriginal, subOriginal) ? Result.UNKNOWN : Result.INCOMPATIBLE;
050        }
051    
052        private static boolean equalErasure(@NotNull FunctionDescriptor fun1, @NotNull FunctionDescriptor fun2) {
053            List<ValueParameterDescriptor> parameters1 = fun1.getValueParameters();
054            List<ValueParameterDescriptor> parameters2 = fun2.getValueParameters();
055    
056            for (ValueParameterDescriptor param1 : parameters1) {
057                ValueParameterDescriptor param2 = parameters2.get(param1.getIndex());
058                if (differentClasses(param2.getType(), param1.getType())) {
059                    return false;
060                }
061            }
062            return true;
063        }
064    
065        private static boolean differentClasses(@NotNull KotlinType type1, @NotNull KotlinType type2) {
066            DeclarationDescriptor declarationDescriptor1 = type1.getConstructor().getDeclarationDescriptor();
067            if (declarationDescriptor1 == null) return true; // No class, classes are not equal
068            DeclarationDescriptor declarationDescriptor2 = type2.getConstructor().getDeclarationDescriptor();
069            if (declarationDescriptor2 == null) return true; // Class of type1 is not null
070    
071            if (declarationDescriptor1 instanceof TypeParameterDescriptor && declarationDescriptor2 instanceof TypeParameterDescriptor) {
072                // if type of value parameter is some generic parameter then their equality was checked by OverridingUtil before calling ExternalOverridabilityCondition
073                // Note that it's true unless we generate sam adapter for type parameter with SAM interface as upper bound:
074                // <K extends Runnable >void foo(K runnable) {}
075                return false;
076            }
077    
078            return !declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal());
079        }
080    
081        // if function is or overrides declaration, returns null; otherwise, return original of sam adapter with substituted type parameters
082        @Nullable
083        private static SimpleFunctionDescriptor getOriginalOfSamAdapterFunction(@NotNull SimpleFunctionDescriptor callable) {
084            DeclarationDescriptor containingDeclaration = callable.getContainingDeclaration();
085            if (!(containingDeclaration instanceof ClassDescriptor)) {
086                return null;
087            }
088            SamAdapterInfo declarationOrSynthesized =
089                    getNearestDeclarationOrSynthesized(callable, ((ClassDescriptor) containingDeclaration).getDefaultType());
090    
091            if (declarationOrSynthesized == null) {
092                return null;
093            }
094    
095            SimpleFunctionDescriptorImpl fun = (SimpleFunctionDescriptorImpl) declarationOrSynthesized.samAdapter.getOriginal();
096            if (!(fun instanceof SamAdapterFunctionDescriptor)) {
097                return null;
098            }
099    
100            SimpleFunctionDescriptor originalDeclarationOfSam = ((SamAdapterFunctionDescriptor) fun).getOriginForSam();
101    
102            return ((SimpleFunctionDescriptor) originalDeclarationOfSam.substitute(TypeSubstitutor.create(declarationOrSynthesized.ownerType)));
103        }
104    
105        @Nullable
106        private static SamAdapterInfo getNearestDeclarationOrSynthesized(
107                @NotNull SimpleFunctionDescriptor samAdapter,
108                @NotNull KotlinType ownerType
109        ) {
110            if (samAdapter.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
111                return new SamAdapterInfo(samAdapter, ownerType);
112            }
113    
114            for (CallableMemberDescriptor overridden : samAdapter.getOverriddenDescriptors()) {
115                ClassDescriptor containingClass = (ClassDescriptor) overridden.getContainingDeclaration();
116    
117                for (KotlinType immediateSupertype : TypeUtils.getImmediateSupertypes(ownerType)) {
118                    if (containingClass != immediateSupertype.getConstructor().getDeclarationDescriptor()) {
119                        continue;
120                    }
121    
122                    SamAdapterInfo found = getNearestDeclarationOrSynthesized((SimpleFunctionDescriptor) overridden, immediateSupertype);
123                    if (found != null) {
124                        return found;
125                    }
126                }
127            }
128    
129            return null;
130        }
131    
132        private static class SamAdapterInfo {
133            private final SimpleFunctionDescriptor samAdapter;
134            private final KotlinType ownerType;
135    
136            private SamAdapterInfo(@NotNull SimpleFunctionDescriptor samAdapter, @NotNull KotlinType ownerType) {
137                this.samAdapter = samAdapter;
138                this.ownerType = ownerType;
139            }
140        }
141    }