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