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.jvm.kotlinSignature;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.util.Function;
021 import com.intellij.util.containers.ContainerUtil;
022 import kotlin.CollectionsKt;
023 import kotlin.jvm.functions.Function1;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.annotations.Nullable;
026 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
027 import org.jetbrains.kotlin.descriptors.*;
028 import org.jetbrains.kotlin.descriptors.annotations.Annotations;
029 import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
030 import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
031 import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor;
032 import org.jetbrains.kotlin.load.java.structure.JavaMethod;
033 import org.jetbrains.kotlin.name.FqNameUnsafe;
034 import org.jetbrains.kotlin.name.Name;
035 import org.jetbrains.kotlin.resolve.DescriptorUtils;
036 import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
037 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
038 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.KotlinToJvmSignatureMapper;
039 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.KotlinToJvmSignatureMapperKt;
040 import org.jetbrains.kotlin.types.KotlinType;
041 import org.jetbrains.kotlin.types.TypeUtils;
042
043 import java.util.*;
044
045 import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName;
046
047 public class SignaturesPropagationData {
048
049 private static final KotlinToJvmSignatureMapper SIGNATURE_MAPPER = ServiceLoader.load(
050 KotlinToJvmSignatureMapper.class,
051 KotlinToJvmSignatureMapper.class.getClassLoader()
052 ).iterator().next();
053
054 private final ValueParameters modifiedValueParameters;
055 private final List<String> signatureErrors = new ArrayList<String>(0);
056 private final List<FunctionDescriptor> superFunctions;
057
058 public SignaturesPropagationData(
059 @NotNull ClassDescriptor containingClass,
060 @NotNull KotlinType autoReturnType, // type built by JavaTypeTransformer from Java signature and @NotNull annotations
061 @Nullable KotlinType receiverType,
062 @NotNull List<ValueParameterDescriptor> autoValueParameters, // descriptors built by parameters resolver
063 @NotNull List<TypeParameterDescriptor> autoTypeParameters, // descriptors built by signature resolver
064 @NotNull JavaMethod method
065 ) {
066 assert receiverType == null : "Parameters before propagation have receiver type," +
067 " but propagation should be disabled for functions compiled from Kotlin in class: " +
068 DescriptorUtils.getFqName(containingClass);
069
070 JavaMethodDescriptor autoMethodDescriptor =
071 createAutoMethodDescriptor(containingClass, method, autoReturnType, autoValueParameters, autoTypeParameters);
072
073 superFunctions = getSuperFunctionsForMethod(method, autoMethodDescriptor, containingClass);
074 modifiedValueParameters = modifyValueParametersAccordingToSuperMethods(autoValueParameters);
075 }
076
077 @NotNull
078 private static JavaMethodDescriptor createAutoMethodDescriptor(
079 @NotNull ClassDescriptor containingClass,
080 @NotNull JavaMethod method, KotlinType autoReturnType,
081 @NotNull List<ValueParameterDescriptor> autoValueParameters,
082 @NotNull List<TypeParameterDescriptor> autoTypeParameters
083 ) {
084 JavaMethodDescriptor autoMethodDescriptor = JavaMethodDescriptor.createJavaMethod(
085 containingClass,
086 Annotations.Companion.getEMPTY(),
087 method.getName(),
088 //TODO: what to do?
089 SourceElement.NO_SOURCE
090 );
091 autoMethodDescriptor.initialize(
092 /* receiverParameterType = */ null,
093 containingClass.getThisAsReceiverParameter(),
094 autoTypeParameters,
095 autoValueParameters,
096 autoReturnType,
097 Modality.OPEN,
098 Visibilities.PUBLIC
099 );
100 return autoMethodDescriptor;
101 }
102
103 public KotlinType getModifiedReceiverType() {
104 return modifiedValueParameters.receiverType;
105 }
106
107 public List<ValueParameterDescriptor> getModifiedValueParameters() {
108 return modifiedValueParameters.descriptors;
109 }
110
111 public boolean getModifiedHasStableParameterNames() {
112 return modifiedValueParameters.hasStableParameterNames;
113 }
114
115 public List<String> getSignatureErrors() {
116 return signatureErrors;
117 }
118
119 void reportError(String error) {
120 signatureErrors.add(error);
121 }
122
123 private ValueParameters modifyValueParametersAccordingToSuperMethods(@NotNull List<ValueParameterDescriptor> parameters) {
124 KotlinType resultReceiverType = null;
125 List<ValueParameterDescriptor> resultParameters = new ArrayList<ValueParameterDescriptor>(parameters.size());
126
127 boolean shouldBeExtension = checkIfShouldBeExtension();
128
129 for (final ValueParameterDescriptor originalParam : parameters) {
130 final int originalIndex = originalParam.getIndex();
131 List<TypeAndName> typesFromSuperMethods = ContainerUtil.map(superFunctions,
132 new Function<FunctionDescriptor, TypeAndName>() {
133 @Override
134 public TypeAndName fun(FunctionDescriptor superFunction) {
135 ReceiverParameterDescriptor receiver = superFunction.getExtensionReceiverParameter();
136 int index = receiver != null ? originalIndex - 1 : originalIndex;
137 if (index == -1) {
138 assert receiver != null : "can't happen: index is -1, while function is not extension";
139 return new TypeAndName(receiver.getType(), originalParam.getName());
140 }
141 ValueParameterDescriptor parameter = superFunction.getValueParameters().get(index);
142 return new TypeAndName(parameter.getType(), parameter.getName());
143 }
144 });
145
146 VarargCheckResult varargCheckResult = checkVarargInSuperFunctions(originalParam);
147
148 KotlinType altType = varargCheckResult.parameterType;
149
150 if (shouldBeExtension && originalIndex == 0) {
151 resultReceiverType = altType;
152 }
153 else {
154 Name stableName = null;
155 for (int i = 0; i < superFunctions.size(); i++) {
156 if (superFunctions.get(i).hasStableParameterNames()) {
157 // When there's more than one stable name in super functions, we pick the first one. This behaviour is similar to
158 // the compiler front-end, except that it reports a warning in such cases
159 // TODO: report a warning somewhere if there's more than one stable name in super functions
160 stableName = typesFromSuperMethods.get(i).name;
161 break;
162 }
163 }
164
165 resultParameters.add(new ValueParameterDescriptorImpl(
166 originalParam.getContainingDeclaration(),
167 null,
168 shouldBeExtension ? originalIndex - 1 : originalIndex,
169 originalParam.getAnnotations(),
170 stableName != null ? stableName : originalParam.getName(),
171 altType,
172 originalParam.declaresDefaultValue(),
173 originalParam.isCrossinline(),
174 originalParam.isNoinline(),
175 varargCheckResult.isVararg ? DescriptorUtilsKt.getBuiltIns(originalParam).getArrayElementType(altType) : null,
176 SourceElement.NO_SOURCE
177 ));
178 }
179 }
180
181 boolean hasStableParameterNames = CollectionsKt.any(superFunctions, new Function1<FunctionDescriptor, Boolean>() {
182 @Override
183 public Boolean invoke(FunctionDescriptor descriptor) {
184 return descriptor.hasStableParameterNames();
185 }
186 });
187
188 return new ValueParameters(resultReceiverType, resultParameters, hasStableParameterNames);
189 }
190
191 private static List<FunctionDescriptor> getSuperFunctionsForMethod(
192 @NotNull JavaMethod method,
193 @NotNull JavaMethodDescriptor autoMethodDescriptor,
194 @NotNull ClassDescriptor containingClass
195 ) {
196 List<FunctionDescriptor> superFunctions = Lists.newArrayList();
197
198 // TODO: Add propagation for other kotlin descriptors (KT-3621)
199 Name name = method.getName();
200 JvmMethodSignature autoSignature = SIGNATURE_MAPPER.mapToJvmMethodSignature(autoMethodDescriptor);
201 for (KotlinType supertype : containingClass.getTypeConstructor().getSupertypes()) {
202 Collection<FunctionDescriptor> superFunctionCandidates = supertype.getMemberScope().getContributedFunctions(name, NoLookupLocation.WHEN_GET_SUPER_MEMBERS);
203 for (FunctionDescriptor candidate : superFunctionCandidates) {
204 JvmMethodSignature candidateSignature = SIGNATURE_MAPPER.mapToJvmMethodSignature(candidate);
205 if (KotlinToJvmSignatureMapperKt.erasedSignaturesEqualIgnoringReturnTypes(autoSignature, candidateSignature)) {
206 superFunctions.add(candidate);
207 }
208 }
209 }
210
211 // sorting for diagnostic stability
212 Collections.sort(superFunctions, new Comparator<FunctionDescriptor>() {
213 @Override
214 public int compare(@NotNull FunctionDescriptor fun1, @NotNull FunctionDescriptor fun2) {
215 FqNameUnsafe fqName1 = getFqName(fun1.getContainingDeclaration());
216 FqNameUnsafe fqName2 = getFqName(fun2.getContainingDeclaration());
217 return fqName1.asString().compareTo(fqName2.asString());
218 }
219 });
220 return superFunctions;
221 }
222
223 private boolean checkIfShouldBeExtension() {
224 boolean someSupersExtension = false;
225 boolean someSupersNotExtension = false;
226
227 for (FunctionDescriptor superFunction : superFunctions) {
228 if (superFunction.getExtensionReceiverParameter() != null) {
229 someSupersExtension = true;
230 }
231 else {
232 someSupersNotExtension = true;
233 }
234 }
235
236 if (someSupersExtension) {
237 if (someSupersNotExtension) {
238 reportError("Incompatible super methods: some are extension functions, some are not");
239 }
240 else {
241 return true;
242 }
243 }
244 return false;
245 }
246
247 @NotNull
248 private VarargCheckResult checkVarargInSuperFunctions(@NotNull ValueParameterDescriptor originalParam) {
249 boolean someSupersVararg = false;
250 boolean someSupersNotVararg = false;
251 for (FunctionDescriptor superFunction : superFunctions) {
252 int originalIndex = originalParam.getIndex();
253 int index = superFunction.getExtensionReceiverParameter() != null ? originalIndex - 1 : originalIndex;
254 if (index != -1 && superFunction.getValueParameters().get(index).getVarargElementType() != null) {
255 someSupersVararg = true;
256 }
257 else {
258 someSupersNotVararg = true;
259 }
260 }
261
262 KotlinType originalVarargElementType = originalParam.getVarargElementType();
263 KotlinType originalType = originalParam.getType();
264
265 if (someSupersVararg && someSupersNotVararg) {
266 reportError("Incompatible super methods: some have vararg parameter, some have not");
267 return new VarargCheckResult(originalType, originalVarargElementType != null);
268 }
269
270 if (someSupersVararg && originalVarargElementType == null) {
271 // convert to vararg
272
273 assert isArrayType(originalType);
274 return new VarargCheckResult(TypeUtils.makeNotNullable(originalType), true);
275 }
276 else if (someSupersNotVararg && originalVarargElementType != null) {
277 // convert to non-vararg
278
279 assert isArrayType(originalType);
280 return new VarargCheckResult(TypeUtils.makeNullable(originalType), false);
281 }
282 return new VarargCheckResult(originalType, originalVarargElementType != null);
283 }
284
285 private static boolean isArrayType(@NotNull KotlinType type) {
286 return KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type);
287 }
288
289 private static class VarargCheckResult {
290 public final KotlinType parameterType;
291 public final boolean isVararg;
292
293 public VarargCheckResult(KotlinType parameterType, boolean isVararg) {
294 this.parameterType = parameterType;
295 this.isVararg = isVararg;
296 }
297 }
298
299 private static class TypeAndName {
300 public final KotlinType type;
301 public final Name name;
302
303 public TypeAndName(KotlinType type, Name name) {
304 this.type = type;
305 this.name = name;
306 }
307 }
308
309 private static class ValueParameters {
310 private final KotlinType receiverType;
311 private final List<ValueParameterDescriptor> descriptors;
312 private final boolean hasStableParameterNames;
313
314 public ValueParameters(
315 @Nullable KotlinType receiverType,
316 @NotNull List<ValueParameterDescriptor> descriptors,
317 boolean hasStableParameterNames
318 ) {
319 this.receiverType = receiverType;
320 this.descriptors = descriptors;
321 this.hasStableParameterNames = hasStableParameterNames;
322 }
323 }
324 }