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