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