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 }