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