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