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 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 }