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.resolve;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
022    import org.jetbrains.kotlin.descriptors.*;
023    import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl;
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.resolve.scopes.JetScope;
028    import org.jetbrains.kotlin.resolve.scopes.RedeclarationHandler;
029    import org.jetbrains.kotlin.resolve.scopes.WritableScope;
030    import org.jetbrains.kotlin.resolve.scopes.WritableScopeImpl;
031    import org.jetbrains.kotlin.types.*;
032    
033    import java.util.*;
034    
035    public class FunctionDescriptorUtil {
036        private static final TypeSubstitutor MAKE_TYPE_PARAMETERS_FRESH = TypeSubstitutor.create(new TypeSubstitution() {
037    
038            @Override
039            public TypeProjection get(TypeConstructor key) {
040                return null;
041            }
042    
043            @Override
044            public String toString() {
045                return "FunctionDescriptorUtil.MAKE_TYPE_PARAMETERS_FRESH";
046            }
047        });
048    
049        private FunctionDescriptorUtil() {
050        }
051    
052        public static Map<TypeConstructor, TypeProjection> createSubstitutionContext(
053                @NotNull FunctionDescriptor functionDescriptor,
054                @NotNull List<JetType> typeArguments
055        ) {
056            if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap();
057    
058            Map<TypeConstructor, TypeProjection> result = new HashMap<TypeConstructor, TypeProjection>();
059    
060            List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
061            assert typeArguments.size() >= typeParameters.size() :
062                    "Insufficient number of type arguments.\nType arguments: " + typeArguments + "\nType parameters: " + typeParameters;
063            for (int i = 0; i < typeParameters.size(); i++) {
064                TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
065                JetType typeArgument = typeArguments.get(i);
066                result.put(typeParameterDescriptor.getTypeConstructor(), new TypeProjectionImpl(typeArgument));
067            }
068            return result;
069        }
070    
071        @NotNull
072        public static JetScope getFunctionInnerScope(@NotNull JetScope outerScope, @NotNull FunctionDescriptor descriptor, @NotNull BindingTrace trace) {
073            TraceBasedRedeclarationHandler redeclarationHandler = new TraceBasedRedeclarationHandler(trace);
074            return getFunctionInnerScope(outerScope, descriptor, redeclarationHandler);
075        }
076    
077        @NotNull
078        public static JetScope getFunctionInnerScope(
079                @NotNull JetScope outerScope,
080                @NotNull FunctionDescriptor descriptor,
081                @NotNull RedeclarationHandler redeclarationHandler
082        ) {
083            WritableScope parameterScope = new WritableScopeImpl(outerScope, descriptor, redeclarationHandler, "Function inner scope");
084            ReceiverParameterDescriptor receiver = descriptor.getExtensionReceiverParameter();
085            if (receiver != null) {
086                parameterScope.setImplicitReceiver(receiver);
087            }
088            for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) {
089                parameterScope.addTypeParameterDescriptor(typeParameter);
090            }
091            for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) {
092                parameterScope.addVariableDescriptor(valueParameterDescriptor);
093            }
094            parameterScope.addLabeledDeclaration(descriptor);
095            parameterScope.changeLockLevel(WritableScope.LockLevel.READING);
096            return parameterScope;
097        }
098    
099        public static void initializeFromFunctionType(
100                @NotNull FunctionDescriptorImpl functionDescriptor,
101                @NotNull JetType functionType,
102                @Nullable ReceiverParameterDescriptor dispatchReceiverParameter,
103                @NotNull Modality modality,
104                @NotNull Visibility visibility
105        ) {
106    
107            assert KotlinBuiltIns.isFunctionOrExtensionFunctionType(functionType);
108            functionDescriptor.initialize(KotlinBuiltIns.getReceiverType(functionType),
109                                          dispatchReceiverParameter,
110                                          Collections.<TypeParameterDescriptorImpl>emptyList(),
111                                          KotlinBuiltIns.getValueParameters(functionDescriptor, functionType),
112                                          KotlinBuiltIns.getReturnTypeFromFunctionType(functionType),
113                                          modality,
114                                          visibility);
115        }
116    
117        public static <D extends CallableDescriptor> D alphaConvertTypeParameters(D candidate) {
118            return (D) candidate.substitute(MAKE_TYPE_PARAMETERS_FRESH);
119        }
120    
121        /**
122         * Returns function's copy with new parameter list. Note that parameters may belong to other methods or have incorrect "index" property
123         * -- it will be fixed by this function.
124         */
125        @NotNull
126        public static FunctionDescriptor replaceFunctionParameters(
127                @NotNull FunctionDescriptor function,
128                @NotNull List<ValueParameterDescriptor> newParameters
129        ) {
130            FunctionDescriptorImpl descriptor = SimpleFunctionDescriptorImpl.create(
131                    function.getContainingDeclaration(),
132                    function.getAnnotations(),
133                    function.getName(),
134                    function.getKind(),
135                    SourceElement.NO_SOURCE
136            );
137            List<ValueParameterDescriptor> parameters = new ArrayList<ValueParameterDescriptor>(newParameters.size());
138            int idx = 0;
139            for (ValueParameterDescriptor parameter : newParameters) {
140                JetType returnType = parameter.getReturnType();
141                assert returnType != null;
142    
143                parameters.add(
144                        new ValueParameterDescriptorImpl(
145                                descriptor,
146                                null,
147                                idx,
148                                parameter.getAnnotations(),
149                                parameter.getName(),
150                                returnType,
151                                parameter.declaresDefaultValue(),
152                                parameter.getVarargElementType(),
153                                SourceElement.NO_SOURCE
154                        )
155                );
156                idx++;
157            }
158            ReceiverParameterDescriptor receiver = function.getExtensionReceiverParameter();
159            descriptor.initialize(
160                    receiver == null ? null : receiver.getType(),
161                    function.getDispatchReceiverParameter(),
162                    function.getTypeParameters(),
163                    parameters,
164                    function.getReturnType(),
165                    function.getModality(),
166                    function.getVisibility());
167            return descriptor;
168        }
169    }