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