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