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 PropertyDescriptor) {
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 (!equalClasses(param2.getType(), param1.getType())) {
054                    return false;
055                }
056            }
057            return true;
058        }
059    
060        private static boolean equalClasses(@NotNull JetType type1, @NotNull JetType type2) {
061            DeclarationDescriptor declarationDescriptor1 = type1.getConstructor().getDeclarationDescriptor();
062            if (declarationDescriptor1 == null) return false; // No class, classes are not equal
063            DeclarationDescriptor declarationDescriptor2 = type2.getConstructor().getDeclarationDescriptor();
064            if (declarationDescriptor2 == null) return false; // Class of type1 is not null
065            return declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal());
066        }
067    
068        // if function is or overrides declaration, returns null; otherwise, return original of sam adapter with substituted type parameters
069        @Nullable
070        private static SimpleFunctionDescriptor getOriginalOfSamAdapterFunction(@NotNull SimpleFunctionDescriptor callable) {
071            DeclarationDescriptor containingDeclaration = callable.getContainingDeclaration();
072            if (!(containingDeclaration instanceof ClassDescriptor)) {
073                return null;
074            }
075            SamAdapterInfo declarationOrSynthesized =
076                    getNearestDeclarationOrSynthesized(callable, ((ClassDescriptor) containingDeclaration).getDefaultType());
077    
078            if (declarationOrSynthesized == null) {
079                return null;
080            }
081    
082            SimpleFunctionDescriptorImpl fun = (SimpleFunctionDescriptorImpl) declarationOrSynthesized.samAdapter.getOriginal();
083            if (!(fun instanceof SamAdapterFunctionDescriptor)) {
084                return null;
085            }
086    
087            SimpleFunctionDescriptor originalDeclarationOfSam = ((SamAdapterFunctionDescriptor) fun).getOriginForSam();
088    
089            return ((SimpleFunctionDescriptor) originalDeclarationOfSam.substitute(TypeSubstitutor.create(declarationOrSynthesized.ownerType)));
090        }
091    
092        @Nullable
093        private static SamAdapterInfo getNearestDeclarationOrSynthesized(
094                @NotNull SimpleFunctionDescriptor samAdapter,
095                @NotNull JetType ownerType
096        ) {
097            if (samAdapter.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
098                return new SamAdapterInfo(samAdapter, ownerType);
099            }
100    
101            for (CallableMemberDescriptor overridden : samAdapter.getOverriddenDescriptors()) {
102                ClassDescriptor containingClass = (ClassDescriptor) overridden.getContainingDeclaration();
103    
104                for (JetType immediateSupertype : TypeUtils.getImmediateSupertypes(ownerType)) {
105                    if (containingClass != immediateSupertype.getConstructor().getDeclarationDescriptor()) {
106                        continue;
107                    }
108    
109                    SamAdapterInfo found = getNearestDeclarationOrSynthesized((SimpleFunctionDescriptor) overridden, immediateSupertype);
110                    if (found != null) {
111                        return found;
112                    }
113                }
114            }
115    
116            return null;
117        }
118    
119        private static class SamAdapterInfo {
120            private final SimpleFunctionDescriptor samAdapter;
121            private final JetType ownerType;
122    
123            private SamAdapterInfo(@NotNull SimpleFunctionDescriptor samAdapter, @NotNull JetType ownerType) {
124                this.samAdapter = samAdapter;
125                this.ownerType = ownerType;
126            }
127        }
128    }