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 com.intellij.util.containers.ContainerUtil;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.jet.lang.descriptors.SourceElement;
026 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
027 import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
028 import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
029 import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
030 import org.jetbrains.jet.lang.psi.*;
031 import org.jetbrains.jet.lang.resolve.java.JavaPackage;
032 import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils;
033 import org.jetbrains.jet.lang.resolve.java.resolver.ExternalAnnotationResolver;
034 import org.jetbrains.jet.lang.resolve.java.structure.JavaMember;
035 import org.jetbrains.jet.lang.resolve.name.Name;
036 import org.jetbrains.jet.lang.types.JetType;
037 import org.jetbrains.jet.lang.types.TypeSubstitutor;
038 import org.jetbrains.jet.lang.types.TypeUtils;
039 import org.jetbrains.jet.lang.types.Variance;
040 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
041 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
042
043 import java.util.*;
044
045 import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
046 import static org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT;
047 import static org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage.UPPER_BOUND;
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 = DescriptorResolverUtils.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.getReturnTypeRef(), 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 (JavaPackage.getPLATFORM_TYPES()) return;
124 TypeSubstitutor substitutor = DescriptorResolverUtils.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(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 }