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