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.intellij.openapi.project.Project; 020 import com.intellij.psi.PsiNamedElement; 021 import com.intellij.util.containers.ComparatorUtil; 022 import com.intellij.util.containers.ContainerUtil; 023 import org.jetbrains.annotations.NotNull; 024 import org.jetbrains.annotations.Nullable; 025 import org.jetbrains.kotlin.descriptors.SourceElement; 026 import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; 027 import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor; 028 import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl; 029 import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl; 030 import org.jetbrains.kotlin.load.java.structure.JavaMember; 031 import org.jetbrains.kotlin.name.Name; 032 import org.jetbrains.kotlin.psi.*; 033 import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolverKt; 034 import org.jetbrains.kotlin.resolve.jvm.JavaResolverUtils; 035 import org.jetbrains.kotlin.types.KotlinType; 036 import org.jetbrains.kotlin.types.TypeSubstitutor; 037 import org.jetbrains.kotlin.types.TypeUtils; 038 import org.jetbrains.kotlin.types.Variance; 039 import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; 040 import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; 041 042 import java.util.ArrayList; 043 import java.util.List; 044 import java.util.Map; 045 import java.util.Set; 046 047 import static org.jetbrains.kotlin.load.java.components.TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT; 048 import static org.jetbrains.kotlin.load.java.components.TypeUsage.UPPER_BOUND; 049 import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getBuiltIns; 050 051 public class AlternativeMethodSignatureData extends ElementAlternativeSignatureData { 052 private final KtNamedFunction altFunDeclaration; 053 054 private List<ValueParameterDescriptor> altValueParameters; 055 private KotlinType altReturnType; 056 private List<TypeParameterDescriptor> altTypeParameters; 057 058 private Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> originalToAltTypeParameters; 059 060 public AlternativeMethodSignatureData( 061 @NotNull JavaMember methodOrConstructor, 062 @Nullable KotlinType receiverType, 063 @NotNull Project project, 064 @NotNull List<ValueParameterDescriptor> valueParameters, 065 @Nullable KotlinType originalReturnType, 066 @NotNull List<TypeParameterDescriptor> methodTypeParameters, 067 boolean hasSuperMethods 068 ) { 069 String signature = SignaturesUtil.getKotlinSignature(methodOrConstructor); 070 071 if (signature == null) { 072 setAnnotated(false); 073 altFunDeclaration = null; 074 return; 075 } 076 077 if (receiverType != null) { 078 throw new UnsupportedOperationException("Alternative annotations for extension functions are not supported yet"); 079 } 080 081 setAnnotated(true); 082 altFunDeclaration = KtPsiFactoryKt.KtPsiFactory(project).createFunction(signature); 083 084 originalToAltTypeParameters = JavaResolverUtils.recreateTypeParametersAndReturnMapping(methodTypeParameters, null); 085 086 try { 087 checkForSyntaxErrors(altFunDeclaration); 088 checkEqualFunctionNames(altFunDeclaration, methodOrConstructor); 089 090 computeTypeParameters(methodTypeParameters); 091 computeValueParameters(valueParameters); 092 093 if (originalReturnType != null) { 094 altReturnType = computeReturnType(originalReturnType, altFunDeclaration.getTypeReference(), originalToAltTypeParameters); 095 } 096 097 if (hasSuperMethods) { 098 checkParameterAndReturnTypesForOverridingMethods(valueParameters, methodTypeParameters, originalReturnType); 099 } 100 } 101 catch (AlternativeSignatureMismatchException e) { 102 setError(e.getMessage()); 103 } 104 } 105 106 public static List<ValueParameterDescriptor> updateNames( 107 List<ValueParameterDescriptor> originalValueParameters, 108 List<ValueParameterDescriptor> altValueParameters 109 ) { 110 List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>(originalValueParameters.size()); 111 for (int i = 0; i < originalValueParameters.size(); i++) { 112 ValueParameterDescriptor originalValueParameter = originalValueParameters.get(i); 113 ValueParameterDescriptor altValueParameter = altValueParameters.get(i); 114 result.add(originalValueParameter.copy(originalValueParameter.getContainingDeclaration(), altValueParameter.getName())); 115 } 116 return result; 117 } 118 119 private void checkParameterAndReturnTypesForOverridingMethods( 120 @NotNull List<ValueParameterDescriptor> valueParameters, 121 @NotNull List<TypeParameterDescriptor> methodTypeParameters, 122 @Nullable KotlinType returnType 123 ) { 124 if (JavaDescriptorResolverKt.getPLATFORM_TYPES()) return; 125 TypeSubstitutor substitutor = JavaResolverUtils.createSubstitutorForTypeParameters(originalToAltTypeParameters); 126 127 for (ValueParameterDescriptor parameter : valueParameters) { 128 int index = parameter.getIndex(); 129 ValueParameterDescriptor altParameter = altValueParameters.get(index); 130 131 KotlinType substituted = substitutor.substitute(parameter.getType(), Variance.INVARIANT); 132 assert substituted != null; 133 134 if (!TypeUtils.equalTypes(substituted, altParameter.getType())) { 135 throw new AlternativeSignatureMismatchException( 136 "Parameter type changed for method which overrides another: " + altParameter.getType() 137 + ", was: " + parameter.getType()); 138 } 139 } 140 141 // don't check receiver 142 143 for (TypeParameterDescriptor parameter : methodTypeParameters) { 144 int index = parameter.getIndex(); 145 146 KotlinType substituted = substitutor.substitute(parameter.getUpperBoundsAsType(), Variance.INVARIANT); 147 assert substituted != null; 148 149 if (!TypeUtils.equalTypes(substituted, altTypeParameters.get(index).getUpperBoundsAsType())) { 150 throw new AlternativeSignatureMismatchException( 151 "Type parameter's upper bound changed for method which overrides another: " 152 + altTypeParameters.get(index).getUpperBoundsAsType() + ", was: " + parameter.getUpperBoundsAsType()); 153 } 154 } 155 156 if (returnType != null) { 157 KotlinType substitutedReturnType = substitutor.substitute(returnType, Variance.INVARIANT); 158 assert substitutedReturnType != null; 159 160 if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(altReturnType, substitutedReturnType)) { 161 throw new AlternativeSignatureMismatchException( 162 "Return type is changed to not subtype for method which overrides another: " + altReturnType + ", was: " + returnType); 163 } 164 } 165 } 166 167 @NotNull 168 public List<ValueParameterDescriptor> getValueParameters() { 169 checkForErrors(); 170 return altValueParameters; 171 } 172 173 @Nullable 174 public KotlinType getReturnType() { 175 checkForErrors(); 176 return altReturnType; 177 } 178 179 @NotNull 180 public List<TypeParameterDescriptor> getTypeParameters() { 181 checkForErrors(); 182 return altTypeParameters; 183 } 184 185 private void computeValueParameters(@NotNull List<ValueParameterDescriptor> parameterDescriptors) { 186 if (parameterDescriptors.size() != altFunDeclaration.getValueParameters().size()) { 187 throw new AlternativeSignatureMismatchException("Method signature has %d value parameters, but alternative signature has %d", 188 parameterDescriptors.size(), altFunDeclaration.getValueParameters().size()); 189 } 190 191 List<ValueParameterDescriptor> altParamDescriptors = new ArrayList<ValueParameterDescriptor>(parameterDescriptors.size()); 192 for (int i = 0; i < parameterDescriptors.size(); i++) { 193 ValueParameterDescriptor originalParameterDescriptor = parameterDescriptors.get(i); 194 KtParameter annotationValueParameter = altFunDeclaration.getValueParameters().get(i); 195 196 //noinspection ConstantConditions 197 KtTypeElement alternativeTypeElement = annotationValueParameter.getTypeReference().getTypeElement(); 198 assert alternativeTypeElement != null; 199 200 KotlinType alternativeType; 201 KotlinType alternativeVarargElementType; 202 203 KotlinType originalParamVarargElementType = originalParameterDescriptor.getVarargElementType(); 204 if (originalParamVarargElementType == null) { 205 if (annotationValueParameter.isVarArg()) { 206 throw new AlternativeSignatureMismatchException("Parameter in method signature is not vararg, but in alternative signature it is vararg"); 207 } 208 209 alternativeType = TypeTransformingVisitor.computeType(alternativeTypeElement, originalParameterDescriptor.getType(), originalToAltTypeParameters, MEMBER_SIGNATURE_CONTRAVARIANT); 210 alternativeVarargElementType = null; 211 } 212 else { 213 if (!annotationValueParameter.isVarArg()) { 214 throw new AlternativeSignatureMismatchException("Parameter in method signature is vararg, but in alternative signature it is not"); 215 } 216 217 alternativeVarargElementType = TypeTransformingVisitor.computeType(alternativeTypeElement, originalParamVarargElementType, 218 originalToAltTypeParameters, MEMBER_SIGNATURE_CONTRAVARIANT); 219 alternativeType = getBuiltIns(originalParameterDescriptor).getArrayType(Variance.OUT_VARIANCE, alternativeVarargElementType); 220 } 221 222 Name altName = annotationValueParameter.getNameAsName(); 223 224 altParamDescriptors.add(new ValueParameterDescriptorImpl( 225 originalParameterDescriptor.getContainingDeclaration(), 226 null, 227 originalParameterDescriptor.getIndex(), 228 originalParameterDescriptor.getAnnotations(), 229 altName != null ? altName : originalParameterDescriptor.getName(), 230 alternativeType, 231 originalParameterDescriptor.declaresDefaultValue(), 232 originalParameterDescriptor.isCrossinline(), 233 originalParameterDescriptor.isNoinline(), 234 alternativeVarargElementType, 235 SourceElement.NO_SOURCE 236 )); 237 } 238 239 altValueParameters = altParamDescriptors; 240 } 241 242 private void computeTypeParameters(List<TypeParameterDescriptor> typeParameters) { 243 if (typeParameters.size() != altFunDeclaration.getTypeParameters().size()) { 244 throw new AlternativeSignatureMismatchException("Method signature has %d type parameters, but alternative signature has %d", 245 typeParameters.size(), altFunDeclaration.getTypeParameters().size()); 246 } 247 248 altTypeParameters = new ArrayList<TypeParameterDescriptor>(typeParameters.size()); 249 250 for (int i = 0; i < typeParameters.size(); i++) { 251 TypeParameterDescriptor originalTypeParamDescriptor = typeParameters.get(i); 252 253 TypeParameterDescriptorImpl altParamDescriptor = originalToAltTypeParameters.get(originalTypeParamDescriptor); 254 KtTypeParameter altTypeParameter = altFunDeclaration.getTypeParameters().get(i); 255 256 Set<KotlinType> originalUpperBounds = originalTypeParamDescriptor.getUpperBounds(); 257 List<KtTypeReference> altUpperBounds = getUpperBounds(altFunDeclaration, altTypeParameter); 258 if (altUpperBounds.size() != originalUpperBounds.size()) { 259 if (altUpperBounds.isEmpty() 260 && originalUpperBounds.size() == 1 261 && TypeUtilsKt.isDefaultBound(originalUpperBounds.iterator().next())) { 262 // Only default bound => no error 263 } 264 else { 265 throw new AlternativeSignatureMismatchException("Upper bound number mismatch for %s. Expected %d, but found %d", 266 originalTypeParamDescriptor.getName(), 267 originalUpperBounds.size(), 268 altUpperBounds.size()); 269 } 270 } 271 272 if (altUpperBounds.isEmpty()) { 273 altParamDescriptor.addDefaultUpperBound(); 274 } 275 else { 276 int upperBoundIndex = 0; 277 for (KotlinType upperBound : originalUpperBounds) { 278 279 KtTypeElement altTypeElement = altUpperBounds.get(upperBoundIndex).getTypeElement(); 280 assert altTypeElement != null; 281 282 altParamDescriptor.addUpperBound(TypeTransformingVisitor.computeType(altTypeElement, upperBound, 283 originalToAltTypeParameters, UPPER_BOUND)); 284 upperBoundIndex++; 285 } 286 } 287 288 altParamDescriptor.setInitialized(); 289 altTypeParameters.add(altParamDescriptor); 290 } 291 } 292 293 @NotNull 294 private static List<KtTypeReference> getUpperBounds(@NotNull KtFunction function, @NotNull KtTypeParameter jetTypeParameter) { 295 List<KtTypeReference> result = new ArrayList<KtTypeReference>(); 296 ContainerUtil.addIfNotNull(result, jetTypeParameter.getExtendsBound()); 297 298 Name name = jetTypeParameter.getNameAsName(); 299 if (name == null) return result; 300 301 for (KtTypeConstraint constraint : function.getTypeConstraints()) { 302 KtSimpleNameExpression parameterName = constraint.getSubjectTypeParameterName(); 303 assert parameterName != null : "No parameter name in constraint " + constraint.getText(); 304 if (name.equals(parameterName.getReferencedNameAsName())) { 305 result.add(constraint.getBoundTypeReference()); 306 } 307 } 308 309 return result; 310 } 311 312 private static void checkEqualFunctionNames(@NotNull PsiNamedElement namedElement, @NotNull JavaMember methodOrConstructor) { 313 if (!ComparatorUtil.equalsNullable(methodOrConstructor.getName().asString(), namedElement.getName())) { 314 throw new AlternativeSignatureMismatchException("Function names mismatch, original: %s, alternative: %s", 315 methodOrConstructor.getName().asString(), namedElement.getName()); 316 } 317 } 318 }