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
017 package org.jetbrains.jet.lang.resolve.java.kotlinSignature;
018
019 import com.intellij.openapi.project.Project;
020 import com.intellij.psi.PsiNamedElement;
021 import com.intellij.util.containers.ComparatorUtil;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
025 import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
026 import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
027 import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
028 import org.jetbrains.jet.lang.psi.*;
029 import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
030 import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
031 import org.jetbrains.jet.lang.resolve.name.Name;
032 import org.jetbrains.jet.lang.types.JetType;
033 import org.jetbrains.jet.lang.types.TypeSubstitutor;
034 import org.jetbrains.jet.lang.types.TypeUtils;
035 import org.jetbrains.jet.lang.types.Variance;
036 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
037 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
038
039 import java.util.ArrayList;
040 import java.util.List;
041 import java.util.Map;
042
043 import static org.jetbrains.jet.lang.resolve.java.TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT;
044 import static org.jetbrains.jet.lang.resolve.java.TypeUsage.UPPER_BOUND;
045
046 public 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 }