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