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