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 043 import java.util.*; 044 045 import static org.jetbrains.kotlin.load.java.components.TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT; 046 import static org.jetbrains.kotlin.load.java.components.TypeUsage.UPPER_BOUND; 047 import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory; 048 049 public class AlternativeMethodSignatureData extends ElementAlternativeSignatureData { 050 private final JetNamedFunction altFunDeclaration; 051 052 private List<ValueParameterDescriptor> altValueParameters; 053 private JetType altReturnType; 054 private List<TypeParameterDescriptor> altTypeParameters; 055 056 private Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> originalToAltTypeParameters; 057 058 public AlternativeMethodSignatureData( 059 @NotNull ExternalAnnotationResolver externalAnnotationResolver, 060 @NotNull JavaMember methodOrConstructor, 061 @Nullable JetType receiverType, 062 @NotNull Project project, 063 @NotNull List<ValueParameterDescriptor> valueParameters, 064 @Nullable JetType originalReturnType, 065 @NotNull List<TypeParameterDescriptor> methodTypeParameters, 066 boolean hasSuperMethods 067 ) { 068 String signature = SignaturesUtil.getKotlinSignature(externalAnnotationResolver, methodOrConstructor); 069 070 if (signature == null) { 071 setAnnotated(false); 072 altFunDeclaration = null; 073 return; 074 } 075 076 if (receiverType != null) { 077 throw new UnsupportedOperationException("Alternative annotations for extension functions are not supported yet"); 078 } 079 080 setAnnotated(true); 081 altFunDeclaration = JetPsiFactory(project).createFunction(signature); 082 083 originalToAltTypeParameters = JavaResolverUtils.recreateTypeParametersAndReturnMapping(methodTypeParameters, null); 084 085 try { 086 checkForSyntaxErrors(altFunDeclaration); 087 checkEqualFunctionNames(altFunDeclaration, methodOrConstructor); 088 089 computeTypeParameters(methodTypeParameters); 090 computeValueParameters(valueParameters); 091 092 if (originalReturnType != null) { 093 altReturnType = computeReturnType(originalReturnType, altFunDeclaration.getTypeReference(), originalToAltTypeParameters); 094 } 095 096 if (hasSuperMethods) { 097 checkParameterAndReturnTypesForOverridingMethods(valueParameters, methodTypeParameters, originalReturnType); 098 } 099 } 100 catch (AlternativeSignatureMismatchException e) { 101 setError(e.getMessage()); 102 } 103 } 104 105 public static List<ValueParameterDescriptor> updateNames( 106 List<ValueParameterDescriptor> originalValueParameters, 107 List<ValueParameterDescriptor> altValueParameters 108 ) { 109 List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>(originalValueParameters.size()); 110 for (int i = 0; i < originalValueParameters.size(); i++) { 111 ValueParameterDescriptor originalValueParameter = originalValueParameters.get(i); 112 ValueParameterDescriptor altValueParameter = altValueParameters.get(i); 113 result.add(originalValueParameter.copy(originalValueParameter.getContainingDeclaration(), altValueParameter.getName())); 114 } 115 return result; 116 } 117 118 private void checkParameterAndReturnTypesForOverridingMethods( 119 @NotNull List<ValueParameterDescriptor> valueParameters, 120 @NotNull List<TypeParameterDescriptor> methodTypeParameters, 121 @Nullable JetType returnType 122 ) { 123 if (JvmPackage.getPLATFORM_TYPES()) return; 124 TypeSubstitutor substitutor = JavaResolverUtils.createSubstitutorForTypeParameters(originalToAltTypeParameters); 125 126 for (ValueParameterDescriptor parameter : valueParameters) { 127 int index = parameter.getIndex(); 128 ValueParameterDescriptor altParameter = altValueParameters.get(index); 129 130 JetType substituted = substitutor.substitute(parameter.getType(), Variance.INVARIANT); 131 assert substituted != null; 132 133 if (!TypeUtils.equalTypes(substituted, altParameter.getType())) { 134 throw new AlternativeSignatureMismatchException( 135 "Parameter type changed for method which overrides another: " + altParameter.getType() 136 + ", was: " + parameter.getType()); 137 } 138 } 139 140 // don't check receiver 141 142 for (TypeParameterDescriptor parameter : methodTypeParameters) { 143 int index = parameter.getIndex(); 144 145 JetType substituted = substitutor.substitute(parameter.getUpperBoundsAsType(), Variance.INVARIANT); 146 assert substituted != null; 147 148 if (!TypeUtils.equalTypes(substituted, altTypeParameters.get(index).getUpperBoundsAsType())) { 149 throw new AlternativeSignatureMismatchException( 150 "Type parameter's upper bound changed for method which overrides another: " 151 + altTypeParameters.get(index).getUpperBoundsAsType() + ", was: " + parameter.getUpperBoundsAsType()); 152 } 153 } 154 155 if (returnType != null) { 156 JetType substitutedReturnType = substitutor.substitute(returnType, Variance.INVARIANT); 157 assert substitutedReturnType != null; 158 159 if (!JetTypeChecker.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 JetType 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>(); 191 for (int i = 0, size = parameterDescriptors.size(); i < size; i++) { 192 ValueParameterDescriptor originalParameterDescriptor = parameterDescriptors.get(i); 193 JetParameter annotationValueParameter = altFunDeclaration.getValueParameters().get(i); 194 195 //noinspection ConstantConditions 196 JetTypeElement alternativeTypeElement = annotationValueParameter.getTypeReference().getTypeElement(); 197 assert alternativeTypeElement != null; 198 199 JetType alternativeType; 200 JetType alternativeVarargElementType; 201 202 JetType 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 = KotlinBuiltIns.getInstance().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 alternativeVarargElementType, 232 SourceElement.NO_SOURCE 233 )); 234 } 235 236 altValueParameters = altParamDescriptors; 237 } 238 239 private void computeTypeParameters(List<TypeParameterDescriptor> typeParameters) { 240 if (typeParameters.size() != altFunDeclaration.getTypeParameters().size()) { 241 throw new AlternativeSignatureMismatchException("Method signature has %d type parameters, but alternative signature has %d", 242 typeParameters.size(), altFunDeclaration.getTypeParameters().size()); 243 } 244 245 altTypeParameters = new ArrayList<TypeParameterDescriptor>(); 246 247 for (int i = 0, size = typeParameters.size(); i < size; i++) { 248 TypeParameterDescriptor originalTypeParamDescriptor = typeParameters.get(i); 249 250 TypeParameterDescriptorImpl altParamDescriptor = originalToAltTypeParameters.get(originalTypeParamDescriptor); 251 JetTypeParameter altTypeParameter = altFunDeclaration.getTypeParameters().get(i); 252 253 Set<JetType> originalUpperBounds = originalTypeParamDescriptor.getUpperBounds(); 254 List<JetTypeReference> altUpperBounds = getUpperBounds(altFunDeclaration, altTypeParameter); 255 if (altUpperBounds.size() != originalUpperBounds.size()) { 256 if (altUpperBounds.isEmpty() 257 && originalUpperBounds.equals(Collections.singleton(KotlinBuiltIns.getInstance().getDefaultBound()))) { 258 // Only default bound => no error 259 } 260 else { 261 throw new AlternativeSignatureMismatchException("Upper bound number mismatch for %s. Expected %d, but found %d", 262 originalTypeParamDescriptor.getName(), 263 originalUpperBounds.size(), 264 altUpperBounds.size()); 265 } 266 } 267 268 if (altUpperBounds.isEmpty()) { 269 altParamDescriptor.addDefaultUpperBound(); 270 } 271 else { 272 int upperBoundIndex = 0; 273 for (JetType upperBound : originalUpperBounds) { 274 275 JetTypeElement altTypeElement = altUpperBounds.get(upperBoundIndex).getTypeElement(); 276 assert altTypeElement != null; 277 278 altParamDescriptor.addUpperBound(TypeTransformingVisitor.computeType(altTypeElement, upperBound, 279 originalToAltTypeParameters, UPPER_BOUND)); 280 upperBoundIndex++; 281 } 282 } 283 284 altParamDescriptor.setInitialized(); 285 altTypeParameters.add(altParamDescriptor); 286 } 287 } 288 289 @NotNull 290 private static List<JetTypeReference> getUpperBounds(@NotNull JetFunction function, @NotNull JetTypeParameter jetTypeParameter) { 291 List<JetTypeReference> result = new ArrayList<JetTypeReference>(); 292 ContainerUtil.addIfNotNull(result, jetTypeParameter.getExtendsBound()); 293 294 Name name = jetTypeParameter.getNameAsName(); 295 if (name == null) return result; 296 297 for (JetTypeConstraint constraint : function.getTypeConstraints()) { 298 JetSimpleNameExpression parameterName = constraint.getSubjectTypeParameterName(); 299 assert parameterName != null : "No parameter name in constraint " + constraint.getText(); 300 if (name.equals(parameterName.getReferencedNameAsName())) { 301 result.add(constraint.getBoundTypeReference()); 302 } 303 } 304 305 return result; 306 } 307 308 private static void checkEqualFunctionNames(@NotNull PsiNamedElement namedElement, @NotNull JavaMember methodOrConstructor) { 309 if (!ComparatorUtil.equalsNullable(methodOrConstructor.getName().asString(), namedElement.getName())) { 310 throw new AlternativeSignatureMismatchException("Function names mismatch, original: %s, alternative: %s", 311 methodOrConstructor.getName().asString(), namedElement.getName()); 312 } 313 } 314 }