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