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