001    /*
002     * Copyright 2010-2016 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.annotations.Annotations;
023    import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
024    import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
025    import org.jetbrains.kotlin.load.java.descriptors.*;
026    import org.jetbrains.kotlin.load.java.lazy.types.LazyJavaTypeResolver;
027    import org.jetbrains.kotlin.name.Name;
028    import org.jetbrains.kotlin.resolve.DescriptorUtils;
029    import org.jetbrains.kotlin.resolve.FunctionTypeResolveUtilsKt;
030    import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
031    import org.jetbrains.kotlin.resolve.jvm.JavaResolverUtils;
032    import org.jetbrains.kotlin.types.*;
033    
034    import java.util.ArrayList;
035    import java.util.Collections;
036    import java.util.List;
037    import java.util.Map;
038    
039    import static org.jetbrains.kotlin.types.Variance.IN_VARIANCE;
040    
041    public class SingleAbstractMethodUtils {
042        private SingleAbstractMethodUtils() {
043        }
044    
045        @NotNull
046        public static List<CallableMemberDescriptor> getAbstractMembers(@NotNull KotlinType type) {
047            List<CallableMemberDescriptor> abstractMembers = new ArrayList<CallableMemberDescriptor>();
048            for (DeclarationDescriptor member : DescriptorUtils.getAllDescriptors(type.getMemberScope())) {
049                if (member instanceof CallableMemberDescriptor && ((CallableMemberDescriptor) member).getModality() == Modality.ABSTRACT) {
050                    abstractMembers.add((CallableMemberDescriptor) member);
051                }
052            }
053            return abstractMembers;
054        }
055    
056        @Nullable
057        public static KotlinType getFunctionTypeForSamType(@NotNull KotlinType samType) {
058            // e.g. samType == Comparator<String>?
059    
060            ClassifierDescriptor classifier = samType.getConstructor().getDeclarationDescriptor();
061            if (classifier instanceof JavaClassDescriptor) {
062                // Function2<T, T, Int>
063                KotlinType functionTypeDefault = ((JavaClassDescriptor) classifier).getFunctionTypeForSamInterface();
064    
065                if (functionTypeDefault != null) {
066                    KotlinType noProjectionsSamType = SingleAbstractMethodUtilsKt.nonProjectionParametrization(samType);
067                    if (noProjectionsSamType == null) return null;
068    
069                    // Function2<String, String, Int>?
070                    KotlinType type = TypeSubstitutor.create(noProjectionsSamType).substitute(functionTypeDefault, IN_VARIANCE);
071                    assert type != null : "Substitution based on type with no projections '" + noProjectionsSamType +
072                                          "' should not end with conflict";
073    
074                    if (FlexibleTypesKt.isNullabilityFlexible(samType)) {
075                        return LazyJavaTypeResolver.FlexibleJavaClassifierTypeFactory.INSTANCE.create(type, TypeUtils.makeNullable(type));
076                    }
077    
078                    return TypeUtils.makeNullableAsSpecified(type, samType.isMarkedNullable());
079                }
080            }
081            return null;
082        }
083    
084        @NotNull
085        public static KotlinType getFunctionTypeForAbstractMethod(@NotNull FunctionDescriptor function) {
086            KotlinType returnType = function.getReturnType();
087            assert returnType != null : "function is not initialized: " + function;
088            List<ValueParameterDescriptor> valueParameters = function.getValueParameters();
089            List<KotlinType> parameterTypes = new ArrayList<KotlinType>(valueParameters.size());
090            for (ValueParameterDescriptor parameter : valueParameters) {
091                parameterTypes.add(parameter.getType());
092            }
093            return FunctionTypeResolveUtilsKt.createFunctionType(
094                    DescriptorUtilsKt.getBuiltIns(function), Annotations.Companion.getEMPTY(), null, parameterTypes, returnType
095            );
096        }
097    
098        @Nullable
099        public static FunctionDescriptor getSingleAbstractMethodOrNull(@NotNull ClassDescriptor klass) {
100            if (klass.getKind() != ClassKind.INTERFACE) {
101                return null;
102            }
103    
104            List<CallableMemberDescriptor> abstractMembers = getAbstractMembers(klass.getDefaultType());
105            if (abstractMembers.size() == 1) {
106                CallableMemberDescriptor member = abstractMembers.get(0);
107                if (member instanceof SimpleFunctionDescriptor) {
108                    return member.getTypeParameters().isEmpty()
109                           ? (FunctionDescriptor) member
110                           : null;
111                }
112            }
113    
114            return null;
115        }
116    
117        @NotNull
118        public static SamConstructorDescriptor createSamConstructorFunction(
119                @NotNull DeclarationDescriptor owner,
120                @NotNull JavaClassDescriptor samInterface
121        ) {
122            assert getSingleAbstractMethodOrNull(samInterface) != null : samInterface;
123    
124            SamConstructorDescriptor result = new SamConstructorDescriptor(owner, samInterface);
125    
126            TypeParameters typeParameters = recreateAndInitializeTypeParameters(samInterface.getTypeConstructor().getParameters(), result);
127    
128            KotlinType parameterTypeUnsubstituted = getFunctionTypeForSamType(samInterface.getDefaultType());
129            assert parameterTypeUnsubstituted != null : "couldn't get function type for SAM type " + samInterface.getDefaultType();
130            KotlinType parameterType = typeParameters.substitutor.substitute(parameterTypeUnsubstituted, Variance.IN_VARIANCE);
131            assert parameterType != null : "couldn't substitute type: " + parameterTypeUnsubstituted +
132                                           ", substitutor = " + typeParameters.substitutor;
133            ValueParameterDescriptor parameter = new ValueParameterDescriptorImpl(
134                    result, null, 0, Annotations.Companion.getEMPTY(), Name.identifier("function"), parameterType,
135                    /* declaresDefaultValue = */ false,
136                    /* isCrossinline = */ false,
137                    /* isNoinline = */ false,
138                    null, SourceElement.NO_SOURCE);
139    
140            KotlinType returnType = typeParameters.substitutor.substitute(samInterface.getDefaultType(), Variance.OUT_VARIANCE);
141            assert returnType != null : "couldn't substitute type: " + samInterface.getDefaultType() +
142                                        ", substitutor = " + typeParameters.substitutor;
143    
144            result.initialize(
145                    null,
146                    null,
147                    typeParameters.descriptors,
148                    Collections.singletonList(parameter),
149                    returnType,
150                    Modality.FINAL,
151                    samInterface.getVisibility()
152            );
153    
154            return result;
155        }
156    
157        public static boolean isSamType(@NotNull KotlinType type) {
158            return getFunctionTypeForSamType(type) != null;
159        }
160    
161        public static boolean isSamAdapterNecessary(@NotNull FunctionDescriptor fun) {
162            for (ValueParameterDescriptor param : fun.getValueParameters()) {
163                if (isSamType(param.getType())) {
164                    return true;
165                }
166            }
167            return false;
168        }
169    
170        @NotNull
171        public static SamAdapterDescriptor<JavaMethodDescriptor> createSamAdapterFunction(@NotNull final JavaMethodDescriptor original) {
172            final SamAdapterFunctionDescriptor result = new SamAdapterFunctionDescriptor(original);
173            return initSamAdapter(original, result, new FunctionInitializer() {
174                @Override
175                public void initialize(
176                        @NotNull List<TypeParameterDescriptor> typeParameters,
177                        @NotNull List<ValueParameterDescriptor> valueParameters,
178                        @NotNull KotlinType returnType
179                ) {
180                    result.initialize(
181                            null,
182                            original.getDispatchReceiverParameter(),
183                            typeParameters,
184                            valueParameters,
185                            returnType,
186                            Modality.FINAL,
187                            original.getVisibility()
188                    );
189                }
190            });
191        }
192    
193        @NotNull
194        public static SamAdapterDescriptor<JavaConstructorDescriptor> createSamAdapterConstructor(@NotNull final JavaConstructorDescriptor original) {
195            final SamAdapterConstructorDescriptor result = new SamAdapterConstructorDescriptor(original);
196            return initSamAdapter(original, result, new FunctionInitializer() {
197                @Override
198                public void initialize(
199                        @NotNull List<TypeParameterDescriptor> typeParameters,
200                        @NotNull List<ValueParameterDescriptor> valueParameters,
201                        @NotNull KotlinType returnType
202                ) {
203                    result.initialize(valueParameters, original.getVisibility());
204                    result.setReturnType(returnType);
205                }
206            });
207        }
208    
209        @NotNull
210        private static <F extends FunctionDescriptor> SamAdapterDescriptor<F> initSamAdapter(
211                @NotNull F original,
212                @NotNull SamAdapterDescriptor<F> adapter,
213                @NotNull FunctionInitializer initializer
214        ) {
215            TypeParameters typeParameters = recreateAndInitializeTypeParameters(original.getTypeParameters(), adapter);
216    
217            KotlinType returnTypeUnsubstituted = original.getReturnType();
218            assert returnTypeUnsubstituted != null : "Creating SAM adapter for not initialized original: " + original;
219    
220            TypeSubstitutor substitutor = typeParameters.substitutor;
221            KotlinType returnType = substitutor.substitute(returnTypeUnsubstituted, Variance.INVARIANT);
222            assert returnType != null : "couldn't substitute type: " + returnTypeUnsubstituted +
223                                            ", substitutor = " + substitutor;
224    
225    
226            List<ValueParameterDescriptor> valueParameters = createValueParametersForSamAdapter(original, adapter, substitutor);
227    
228            initializer.initialize(typeParameters.descriptors, valueParameters, returnType);
229    
230            return adapter;
231        }
232    
233        public static List<ValueParameterDescriptor> createValueParametersForSamAdapter(
234                @NotNull FunctionDescriptor original,
235                @NotNull FunctionDescriptor samAdapter,
236                @NotNull TypeSubstitutor substitutor
237        ) {
238            List<ValueParameterDescriptor> originalValueParameters = original.getValueParameters();
239            List<ValueParameterDescriptor> valueParameters = new ArrayList<ValueParameterDescriptor>(originalValueParameters.size());
240            for (ValueParameterDescriptor originalParam : originalValueParameters) {
241                KotlinType originalType = originalParam.getType();
242                KotlinType functionType = getFunctionTypeForSamType(originalType);
243                KotlinType newTypeUnsubstituted = functionType != null ? functionType : originalType;
244                KotlinType newType = substitutor.substitute(newTypeUnsubstituted, Variance.IN_VARIANCE);
245                assert newType != null : "couldn't substitute type: " + newTypeUnsubstituted + ", substitutor = " + substitutor;
246    
247                ValueParameterDescriptor newParam = new ValueParameterDescriptorImpl(
248                        samAdapter, null, originalParam.getIndex(), originalParam.getAnnotations(),
249                        originalParam.getName(), newType,
250                        /* declaresDefaultValue = */ false,
251                        /* isCrossinline = */ false,
252                        /* isNoinline = */ false,
253                        null, SourceElement.NO_SOURCE
254                );
255                valueParameters.add(newParam);
256            }
257            return valueParameters;
258        }
259    
260        @NotNull
261        private static TypeParameters recreateAndInitializeTypeParameters(
262                @NotNull List<TypeParameterDescriptor> originalParameters,
263                @Nullable DeclarationDescriptor newOwner
264        ) {
265            if (newOwner instanceof SamAdapterConstructorDescriptor) {
266                return new TypeParameters(originalParameters, TypeSubstitutor.EMPTY);
267            }
268    
269            Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> traitToFunTypeParameters =
270                    JavaResolverUtils.recreateTypeParametersAndReturnMapping(originalParameters, newOwner);
271            TypeSubstitutor typeParametersSubstitutor = JavaResolverUtils.createSubstitutorForTypeParameters(traitToFunTypeParameters);
272            for (Map.Entry<TypeParameterDescriptor, TypeParameterDescriptorImpl> mapEntry : traitToFunTypeParameters.entrySet()) {
273                TypeParameterDescriptor traitTypeParameter = mapEntry.getKey();
274                TypeParameterDescriptorImpl funTypeParameter = mapEntry.getValue();
275    
276                for (KotlinType upperBound : traitTypeParameter.getUpperBounds()) {
277                    KotlinType upperBoundSubstituted = typeParametersSubstitutor.substitute(upperBound, Variance.INVARIANT);
278                    assert upperBoundSubstituted != null : "couldn't substitute type: " + upperBound + ", substitutor = " + typeParametersSubstitutor;
279                    funTypeParameter.addUpperBound(upperBoundSubstituted);
280                }
281    
282                funTypeParameter.setInitialized();
283            }
284    
285            List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(traitToFunTypeParameters.values());
286            return new TypeParameters(typeParameters, typeParametersSubstitutor);
287        }
288    
289        private static class TypeParameters {
290            public final List<TypeParameterDescriptor> descriptors;
291            public final TypeSubstitutor substitutor;
292    
293            private TypeParameters(List<TypeParameterDescriptor> descriptors, TypeSubstitutor substitutor) {
294                this.descriptors = descriptors;
295                this.substitutor = substitutor;
296            }
297        }
298    
299        private static abstract class FunctionInitializer {
300            public abstract void initialize(
301                    @NotNull List<TypeParameterDescriptor> typeParameters,
302                    @NotNull List<ValueParameterDescriptor> valueParameters,
303                    @NotNull KotlinType returnType
304            );
305        }
306    
307    
308    }