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;
018
019 import kotlin.Unit;
020 import kotlin.collections.CollectionsKt;
021 import kotlin.jvm.functions.Function1;
022 import org.jetbrains.annotations.Mutable;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.kotlin.descriptors.*;
026 import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl;
027 import org.jetbrains.kotlin.descriptors.impl.PropertyAccessorDescriptorImpl;
028 import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl;
029 import org.jetbrains.kotlin.name.Name;
030 import org.jetbrains.kotlin.types.FlexibleTypesKt;
031 import org.jetbrains.kotlin.types.KotlinType;
032 import org.jetbrains.kotlin.types.TypeConstructor;
033 import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
034 import org.jetbrains.kotlin.utils.SmartSet;
035
036 import java.util.*;
037
038 import static org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.*;
039
040 public class OverridingUtil {
041
042 private static final List<ExternalOverridabilityCondition> EXTERNAL_CONDITIONS =
043 CollectionsKt.toList(ServiceLoader.load(
044 ExternalOverridabilityCondition.class,
045 ExternalOverridabilityCondition.class.getClassLoader()
046 ));
047
048 public static final OverridingUtil DEFAULT = new OverridingUtil(new KotlinTypeChecker.TypeConstructorEquality() {
049 @Override
050 public boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
051 return a.equals(b);
052 }
053 });
054
055 @NotNull
056 public static OverridingUtil createWithEqualityAxioms(@NotNull KotlinTypeChecker.TypeConstructorEquality equalityAxioms) {
057 return new OverridingUtil(equalityAxioms);
058 }
059
060 private final KotlinTypeChecker.TypeConstructorEquality equalityAxioms;
061
062 private OverridingUtil(KotlinTypeChecker.TypeConstructorEquality axioms) {
063 equalityAxioms = axioms;
064 }
065
066 @NotNull
067 public OverrideCompatibilityInfo isOverridableBy(
068 @NotNull CallableDescriptor superDescriptor,
069 @NotNull CallableDescriptor subDescriptor,
070 @Nullable ClassDescriptor subClassDescriptor
071 ) {
072 return isOverridableBy(superDescriptor, subDescriptor, subClassDescriptor, false);
073 }
074
075 @NotNull
076 public OverrideCompatibilityInfo isOverridableByIncludingReturnType(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
077 return isOverridableBy(superDescriptor, subDescriptor, null, true);
078 }
079
080 @NotNull
081 private OverrideCompatibilityInfo isOverridableBy(
082 @NotNull CallableDescriptor superDescriptor,
083 @NotNull CallableDescriptor subDescriptor,
084 @Nullable ClassDescriptor subClassDescriptor,
085 boolean checkReturnType
086 ) {
087 OverrideCompatibilityInfo basicResult = isOverridableByWithoutExternalConditions(superDescriptor, subDescriptor, checkReturnType);
088 boolean wasSuccess = basicResult.getResult() == OVERRIDABLE;
089
090 for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
091 // Do not run CONFLICTS_ONLY while there was no success
092 if (externalCondition.getContract() == ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY) continue;
093 if (wasSuccess && externalCondition.getContract() == ExternalOverridabilityCondition.Contract.SUCCESS_ONLY) continue;
094
095 ExternalOverridabilityCondition.Result result =
096 externalCondition.isOverridable(superDescriptor, subDescriptor, subClassDescriptor);
097
098 switch (result) {
099 case OVERRIDABLE:
100 wasSuccess = true;
101 break;
102 case CONFLICT:
103 return OverrideCompatibilityInfo.conflict("External condition failed");
104 case INCOMPATIBLE:
105 return OverrideCompatibilityInfo.incompatible("External condition");
106 case UNKNOWN:
107 // do nothing
108 // go to the next external condition or default override check
109 }
110 }
111
112 if (!wasSuccess) {
113 return basicResult;
114 }
115
116 // Search for conflicts from external conditions
117 for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
118 // Run all conditions that was not run before (i.e. CONFLICTS_ONLY)
119 if (externalCondition.getContract() != ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY) continue;
120
121 ExternalOverridabilityCondition.Result result =
122 externalCondition.isOverridable(superDescriptor, subDescriptor, subClassDescriptor);
123 switch (result) {
124 case CONFLICT:
125 return OverrideCompatibilityInfo.conflict("External condition failed");
126 case INCOMPATIBLE:
127 return OverrideCompatibilityInfo.incompatible("External condition");
128 case OVERRIDABLE:
129 throw new IllegalStateException(
130 "Contract violation in " + externalCondition.getClass().getName() + " condition. It's not supposed to end with success");
131 case UNKNOWN:
132 // do nothing
133 // go to the next external condition or default override check
134 }
135 }
136
137 return OverrideCompatibilityInfo.success();
138 }
139
140 @NotNull
141 public OverrideCompatibilityInfo isOverridableByWithoutExternalConditions(
142 @NotNull CallableDescriptor superDescriptor,
143 @NotNull CallableDescriptor subDescriptor,
144 boolean checkReturnType
145 ) {
146 OverrideCompatibilityInfo basicOverridability = getBasicOverridabilityProblem(superDescriptor, subDescriptor);
147 if (basicOverridability != null) return basicOverridability;
148
149 List<KotlinType> superValueParameters = compiledValueParameters(superDescriptor);
150 List<KotlinType> subValueParameters = compiledValueParameters(subDescriptor);
151
152 List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
153 List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
154
155 if (superTypeParameters.size() != subTypeParameters.size()) {
156 for (int i = 0; i < superValueParameters.size(); ++i) {
157 // TODO: compare erasure
158 if (!KotlinTypeChecker.DEFAULT.equalTypes(superValueParameters.get(i), subValueParameters.get(i))) {
159 return OverrideCompatibilityInfo.incompatible("Type parameter number mismatch");
160 }
161 }
162 return OverrideCompatibilityInfo.conflict("Type parameter number mismatch");
163 }
164
165 KotlinTypeChecker typeChecker = createTypeChecker(superTypeParameters, subTypeParameters);
166
167 for (int i = 0; i < superTypeParameters.size(); i++) {
168 if (!areTypeParametersEquivalent(superTypeParameters.get(i), subTypeParameters.get(i), typeChecker)) {
169 return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch");
170 }
171 }
172
173 for (int i = 0; i < superValueParameters.size(); i++) {
174 if (!areTypesEquivalent(superValueParameters.get(i), subValueParameters.get(i), typeChecker)) {
175 return OverrideCompatibilityInfo.incompatible("Value parameter type mismatch");
176 }
177 }
178
179 if (checkReturnType) {
180 KotlinType superReturnType = superDescriptor.getReturnType();
181 KotlinType subReturnType = subDescriptor.getReturnType();
182
183 if (superReturnType != null && subReturnType != null) {
184 boolean bothErrors = subReturnType.isError() && superReturnType.isError();
185 if (!bothErrors && !typeChecker.isSubtypeOf(subReturnType, superReturnType)) {
186 return OverrideCompatibilityInfo.conflict("Return type mismatch");
187 }
188 }
189 }
190
191 return OverrideCompatibilityInfo.success();
192 }
193
194 @Nullable
195 public static OverrideCompatibilityInfo getBasicOverridabilityProblem(
196 @NotNull CallableDescriptor superDescriptor,
197 @NotNull CallableDescriptor subDescriptor
198 ) {
199 if (superDescriptor instanceof FunctionDescriptor && !(subDescriptor instanceof FunctionDescriptor) ||
200 superDescriptor instanceof PropertyDescriptor && !(subDescriptor instanceof PropertyDescriptor)) {
201 return OverrideCompatibilityInfo.incompatible("Member kind mismatch");
202 }
203
204 if (!(superDescriptor instanceof FunctionDescriptor) && !(superDescriptor instanceof PropertyDescriptor)) {
205 throw new IllegalArgumentException("This type of CallableDescriptor cannot be checked for overridability: " + superDescriptor);
206 }
207
208 // TODO: check outside of this method
209 if (!superDescriptor.getName().equals(subDescriptor.getName())) {
210 return OverrideCompatibilityInfo.incompatible("Name mismatch");
211 }
212
213 OverrideCompatibilityInfo receiverAndParameterResult = checkReceiverAndParameterCount(superDescriptor, subDescriptor);
214 if (receiverAndParameterResult != null) {
215 return receiverAndParameterResult;
216 }
217
218 return null;
219 }
220
221 @NotNull
222 private KotlinTypeChecker createTypeChecker(
223 @NotNull List<TypeParameterDescriptor> firstParameters,
224 @NotNull List<TypeParameterDescriptor> secondParameters
225 ) {
226 assert firstParameters.size() == secondParameters.size() :
227 "Should be the same number of type parameters: " + firstParameters + " vs " + secondParameters;
228 if (firstParameters.isEmpty()) return KotlinTypeChecker.withAxioms(equalityAxioms);
229
230 final Map<TypeConstructor, TypeConstructor> matchingTypeConstructors = new HashMap<TypeConstructor, TypeConstructor>();
231 for (int i = 0; i < firstParameters.size(); i++) {
232 matchingTypeConstructors.put(firstParameters.get(i).getTypeConstructor(), secondParameters.get(i).getTypeConstructor());
233 }
234
235 return KotlinTypeChecker.withAxioms(new KotlinTypeChecker.TypeConstructorEquality() {
236 @Override
237 public boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
238 if (equalityAxioms.equals(a, b)) return true;
239 TypeConstructor img1 = matchingTypeConstructors.get(a);
240 TypeConstructor img2 = matchingTypeConstructors.get(b);
241 return (img1 != null && img1.equals(b)) || (img2 != null && img2.equals(a));
242 }
243 });
244 }
245
246 @Nullable
247 static OverrideCompatibilityInfo checkReceiverAndParameterCount(
248 CallableDescriptor superDescriptor,
249 CallableDescriptor subDescriptor
250 ) {
251 if ((superDescriptor.getExtensionReceiverParameter() == null) != (subDescriptor.getExtensionReceiverParameter() == null)) {
252 return OverrideCompatibilityInfo.incompatible("Receiver presence mismatch");
253 }
254
255 if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
256 return OverrideCompatibilityInfo.incompatible("Value parameter number mismatch");
257 }
258
259 return null;
260 }
261
262 private static boolean areTypesEquivalent(
263 @NotNull KotlinType typeInSuper,
264 @NotNull KotlinType typeInSub,
265 @NotNull KotlinTypeChecker typeChecker
266 ) {
267 boolean bothErrors = typeInSuper.isError() && typeInSub.isError();
268 return bothErrors || typeChecker.equalTypes(typeInSuper, typeInSub);
269 }
270
271 // See JLS 8, 8.4.4 Generic Methods
272 // TODO: use TypeSubstitutor instead
273 private static boolean areTypeParametersEquivalent(
274 @NotNull TypeParameterDescriptor superTypeParameter,
275 @NotNull TypeParameterDescriptor subTypeParameter,
276 @NotNull KotlinTypeChecker typeChecker
277 ) {
278 List<KotlinType> superBounds = superTypeParameter.getUpperBounds();
279 List<KotlinType> subBounds = new ArrayList<KotlinType>(subTypeParameter.getUpperBounds());
280 if (superBounds.size() != subBounds.size()) return false;
281
282 outer:
283 for (KotlinType superBound : superBounds) {
284 ListIterator<KotlinType> it = subBounds.listIterator();
285 while (it.hasNext()) {
286 KotlinType subBound = it.next();
287 if (areTypesEquivalent(superBound, subBound, typeChecker)) {
288 it.remove();
289 continue outer;
290 }
291 }
292 return false;
293 }
294
295 return true;
296 }
297
298 static List<KotlinType> compiledValueParameters(CallableDescriptor callableDescriptor) {
299 ReceiverParameterDescriptor receiverParameter = callableDescriptor.getExtensionReceiverParameter();
300 List<KotlinType> parameters = new ArrayList<KotlinType>();
301 if (receiverParameter != null) {
302 parameters.add(receiverParameter.getType());
303 }
304 for (ValueParameterDescriptor valueParameterDescriptor : callableDescriptor.getValueParameters()) {
305 parameters.add(valueParameterDescriptor.getType());
306 }
307 return parameters;
308 }
309
310 public static void generateOverridesInFunctionGroup(
311 @SuppressWarnings("UnusedParameters")
312 @NotNull Name name, //DO NOT DELETE THIS PARAMETER: needed to make sure all descriptors have the same name
313 @NotNull Collection<? extends CallableMemberDescriptor> membersFromSupertypes,
314 @NotNull Collection<? extends CallableMemberDescriptor> membersFromCurrent,
315 @NotNull ClassDescriptor current,
316 @NotNull OverridingStrategy strategy
317 ) {
318 Collection<CallableMemberDescriptor> notOverridden = new LinkedHashSet<CallableMemberDescriptor>(membersFromSupertypes);
319
320 for (CallableMemberDescriptor fromCurrent : membersFromCurrent) {
321 Collection<CallableMemberDescriptor> bound =
322 extractAndBindOverridesForMember(fromCurrent, membersFromSupertypes, current, strategy);
323 notOverridden.removeAll(bound);
324 }
325
326 createAndBindFakeOverrides(current, notOverridden, strategy);
327 }
328
329 private static Collection<CallableMemberDescriptor> extractAndBindOverridesForMember(
330 @NotNull CallableMemberDescriptor fromCurrent,
331 @NotNull Collection<? extends CallableMemberDescriptor> descriptorsFromSuper,
332 @NotNull ClassDescriptor current,
333 @NotNull OverridingStrategy strategy
334 ) {
335 Collection<CallableMemberDescriptor> bound = new ArrayList<CallableMemberDescriptor>(descriptorsFromSuper.size());
336 Collection<CallableMemberDescriptor> overridden = SmartSet.create();
337 for (CallableMemberDescriptor fromSupertype : descriptorsFromSuper) {
338 OverrideCompatibilityInfo.Result result = DEFAULT.isOverridableBy(fromSupertype, fromCurrent, current).getResult();
339
340 boolean isVisible = Visibilities.isVisibleWithIrrelevantReceiver(fromSupertype, current);
341 switch (result) {
342 case OVERRIDABLE:
343 if (isVisible) {
344 overridden.add(fromSupertype);
345 }
346 bound.add(fromSupertype);
347 break;
348 case CONFLICT:
349 if (isVisible) {
350 strategy.conflict(fromSupertype, fromCurrent);
351 }
352 bound.add(fromSupertype);
353 break;
354 case INCOMPATIBLE:
355 break;
356 }
357 }
358
359 strategy.setOverriddenDescriptors(fromCurrent, overridden);
360
361 return bound;
362 }
363
364 private static boolean allHasSameContainingDeclaration(@NotNull Collection<CallableMemberDescriptor> notOverridden) {
365 if (notOverridden.size() < 2) return true;
366
367 final DeclarationDescriptor containingDeclaration = notOverridden.iterator().next().getContainingDeclaration();
368 return CollectionsKt.all(notOverridden, new Function1<CallableMemberDescriptor, Boolean>() {
369 @Override
370 public Boolean invoke(CallableMemberDescriptor descriptor) {
371 return descriptor.getContainingDeclaration() == containingDeclaration;
372 }
373 });
374 }
375
376 private static void createAndBindFakeOverrides(
377 @NotNull ClassDescriptor current,
378 @NotNull Collection<CallableMemberDescriptor> notOverridden,
379 @NotNull OverridingStrategy strategy
380 ) {
381 // Optimization: If all notOverridden descriptors have the same containing declaration,
382 // then we can just create fake overrides for them, because they should be matched correctly in their containing declaration
383 if (allHasSameContainingDeclaration(notOverridden)) {
384 for (CallableMemberDescriptor descriptor : notOverridden) {
385 createAndBindFakeOverride(Collections.singleton(descriptor), current, strategy);
386 }
387 return;
388 }
389
390 Queue<CallableMemberDescriptor> fromSuperQueue = new LinkedList<CallableMemberDescriptor>(notOverridden);
391 while (!fromSuperQueue.isEmpty()) {
392 CallableMemberDescriptor notOverriddenFromSuper = VisibilityUtilKt.findMemberWithMaxVisibility(fromSuperQueue);
393 Collection<CallableMemberDescriptor> overridables =
394 extractMembersOverridableInBothWays(notOverriddenFromSuper, fromSuperQueue, strategy);
395 createAndBindFakeOverride(overridables, current, strategy);
396 }
397 }
398
399 public static boolean isMoreSpecific(@NotNull CallableDescriptor a, @NotNull CallableDescriptor b) {
400 KotlinType aReturnType = a.getReturnType();
401 KotlinType bReturnType = b.getReturnType();
402
403 assert aReturnType != null : "Return type of " + a + " is null";
404 assert bReturnType != null : "Return type of " + b + " is null";
405
406 if (!isVisibilityMoreSpecific(a, b)) return false;
407
408 if (a instanceof SimpleFunctionDescriptor) {
409 assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass();
410
411 return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType);
412 }
413 if (a instanceof PropertyDescriptor) {
414 assert b instanceof PropertyDescriptor : "b is " + b.getClass();
415
416 PropertyDescriptor pa = (PropertyDescriptor) a;
417 PropertyDescriptor pb = (PropertyDescriptor) b;
418
419 if (!isAccessorMoreSpecific(pa.getSetter(), pb.getSetter())) return false;
420
421 if (pa.isVar() && pb.isVar()) {
422 return DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters()).equalTypes(aReturnType, bReturnType);
423 }
424 else {
425 // both vals or var vs val: val can't be more specific then var
426 return !(!pa.isVar() && pb.isVar()) && isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType);
427 }
428 }
429 throw new IllegalArgumentException("Unexpected callable: " + a.getClass());
430 }
431
432 private static boolean isVisibilityMoreSpecific(
433 @NotNull DeclarationDescriptorWithVisibility a,
434 @NotNull DeclarationDescriptorWithVisibility b
435 ) {
436 Integer result = Visibilities.compare(a.getVisibility(), b.getVisibility());
437 return result == null || result >= 0;
438 }
439
440 private static boolean isAccessorMoreSpecific(@Nullable PropertyAccessorDescriptor a, @Nullable PropertyAccessorDescriptor b) {
441 if (a == null || b == null) return true;
442 return isVisibilityMoreSpecific(a, b);
443 }
444
445 private static boolean isMoreSpecificThenAllOf(@NotNull CallableDescriptor candidate, @NotNull Collection<CallableDescriptor> descriptors) {
446 // NB subtyping relation in Kotlin is not transitive in presence of flexible types:
447 // String? <: String! <: String, but not String? <: String
448 for (CallableDescriptor descriptor : descriptors) {
449 if (!isMoreSpecific(candidate, descriptor)) {
450 return false;
451 }
452 }
453 return true;
454 }
455
456 private static boolean isReturnTypeMoreSpecific(
457 @NotNull CallableDescriptor a,
458 @NotNull KotlinType aReturnType,
459 @NotNull CallableDescriptor b,
460 @NotNull KotlinType bReturnType
461 ) {
462 KotlinTypeChecker typeChecker = DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters());
463 return typeChecker.isSubtypeOf(aReturnType, bReturnType);
464 }
465
466 @NotNull
467 public static <H> H selectMostSpecificMember(
468 @NotNull Collection<H> overridables,
469 @NotNull Function1<H, CallableDescriptor> descriptorByHandle
470 ) {
471 assert !overridables.isEmpty() : "Should have at least one overridable descriptor";
472
473 if (overridables.size() == 1) {
474 return CollectionsKt.first(overridables);
475 }
476
477 Collection<H> candidates = new ArrayList<H>(2);
478 List<CallableDescriptor> callableMemberDescriptors = CollectionsKt.map(overridables, descriptorByHandle);
479
480 H transitivelyMostSpecific = CollectionsKt.first(overridables);
481 CallableDescriptor transitivelyMostSpecificDescriptor = descriptorByHandle.invoke(transitivelyMostSpecific);
482
483 for (H overridable : overridables) {
484 CallableDescriptor descriptor = descriptorByHandle.invoke(overridable);
485 if (isMoreSpecificThenAllOf(descriptor, callableMemberDescriptors)) {
486 candidates.add(overridable);
487 }
488 if (isMoreSpecific(descriptor, transitivelyMostSpecificDescriptor)
489 && !isMoreSpecific(transitivelyMostSpecificDescriptor, descriptor)) {
490 transitivelyMostSpecific = overridable;
491 }
492 }
493
494 if (candidates.isEmpty()) {
495 return transitivelyMostSpecific;
496 }
497 else if (candidates.size() == 1) {
498 return CollectionsKt.first(candidates);
499 }
500
501 H firstNonFlexible = null;
502 for (H candidate : candidates) {
503 if (!FlexibleTypesKt.isFlexible(descriptorByHandle.invoke(candidate).getReturnType())) {
504 firstNonFlexible = candidate;
505 break;
506 }
507 }
508 if (firstNonFlexible != null) {
509 return firstNonFlexible;
510 }
511
512 return CollectionsKt.first(candidates);
513 }
514
515 private static void createAndBindFakeOverride(
516 @NotNull Collection<CallableMemberDescriptor> overridables,
517 @NotNull ClassDescriptor current,
518 @NotNull OverridingStrategy strategy
519 ) {
520 Collection<CallableMemberDescriptor> visibleOverridables = filterVisibleFakeOverrides(current, overridables);
521 boolean allInvisible = visibleOverridables.isEmpty();
522 Collection<CallableMemberDescriptor> effectiveOverridden = allInvisible ? overridables : visibleOverridables;
523
524 // FIXME doesn't work as expected for flexible types: should create a refined signature.
525 // Current algorithm produces bad results in presence of annotated Java signatures such as:
526 // J: foo(s: String!): String -- @NotNull String foo(String s);
527 // K: foo(s: String): String?
528 // --> 'foo(s: String!): String' as an inherited signature with most specific return type.
529 // This is bad because it can be overridden by 'foo(s: String?): String', which is not override-equivalent with K::foo above.
530 // Should be 'foo(s: String): String'.
531 Modality modality = getMinimalModality(effectiveOverridden);
532 Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED;
533 CallableMemberDescriptor mostSpecific =
534 selectMostSpecificMember(effectiveOverridden,
535 new Function1<CallableMemberDescriptor, CallableDescriptor>() {
536 @Override
537 public CallableMemberDescriptor invoke(CallableMemberDescriptor descriptor) {
538 return descriptor;
539 }
540 });
541 CallableMemberDescriptor fakeOverride =
542 mostSpecific.copy(current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
543 strategy.setOverriddenDescriptors(fakeOverride, effectiveOverridden);
544 assert !fakeOverride.getOverriddenDescriptors().isEmpty()
545 : "Overridden descriptors should be set for " + CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
546 strategy.addFakeOverride(fakeOverride);
547 }
548
549 @NotNull
550 private static Modality getMinimalModality(@NotNull Collection<CallableMemberDescriptor> descriptors) {
551 Modality modality = Modality.ABSTRACT;
552 for (CallableMemberDescriptor descriptor : descriptors) {
553 if (descriptor.getModality().compareTo(modality) < 0) {
554 modality = descriptor.getModality();
555 }
556 }
557 return modality;
558 }
559
560 @NotNull
561 private static Collection<CallableMemberDescriptor> filterVisibleFakeOverrides(
562 @NotNull final ClassDescriptor current,
563 @NotNull Collection<CallableMemberDescriptor> toFilter
564 ) {
565 return CollectionsKt.filter(toFilter, new Function1<CallableMemberDescriptor, Boolean>() {
566 @Override
567 public Boolean invoke(CallableMemberDescriptor descriptor) {
568 //nested class could capture private member, so check for private visibility added
569 return !Visibilities.isPrivate(descriptor.getVisibility()) &&
570 Visibilities.isVisibleWithIrrelevantReceiver(descriptor, current);
571 }
572 });
573 }
574
575 /**
576 * @param <H> is something that handles CallableDescriptor inside
577 * @return
578 */
579 @NotNull
580 public static <H> Collection<H> extractMembersOverridableInBothWays(
581 @NotNull H overrider,
582 @NotNull @Mutable Collection<H> extractFrom,
583 @NotNull Function1<H, CallableDescriptor> descriptorByHandle,
584 @NotNull Function1<H, Unit> onConflict
585 ) {
586 Collection<H> overridable = new ArrayList<H>();
587 overridable.add(overrider);
588 CallableDescriptor overriderDescriptor = descriptorByHandle.invoke(overrider);
589 for (Iterator<H> iterator = extractFrom.iterator(); iterator.hasNext(); ) {
590 H candidate = iterator.next();
591 CallableDescriptor candidateDescriptor = descriptorByHandle.invoke(candidate);
592 if (overrider == candidate) {
593 iterator.remove();
594 continue;
595 }
596
597 OverrideCompatibilityInfo.Result finalResult = getBothWaysOverridability(overriderDescriptor, candidateDescriptor);
598
599 if (finalResult == OVERRIDABLE) {
600 overridable.add(candidate);
601 iterator.remove();
602 }
603 else if (finalResult == CONFLICT) {
604 onConflict.invoke(candidate);
605 iterator.remove();
606 }
607 }
608 return overridable;
609 }
610
611 @Nullable
612 public static OverrideCompatibilityInfo.Result getBothWaysOverridability(
613 CallableDescriptor overriderDescriptor,
614 CallableDescriptor candidateDescriptor
615 ) {
616 OverrideCompatibilityInfo.Result result1 = DEFAULT.isOverridableBy(candidateDescriptor, overriderDescriptor, null).getResult();
617 OverrideCompatibilityInfo.Result result2 = DEFAULT.isOverridableBy(overriderDescriptor, candidateDescriptor, null).getResult();
618
619 return result1 == OVERRIDABLE && result2 == OVERRIDABLE
620 ? OVERRIDABLE
621 : ((result1 == CONFLICT || result2 == CONFLICT) ? CONFLICT : INCOMPATIBLE);
622 }
623
624 @NotNull
625 private static Collection<CallableMemberDescriptor> extractMembersOverridableInBothWays(
626 @NotNull final CallableMemberDescriptor overrider,
627 @NotNull Queue<CallableMemberDescriptor> extractFrom,
628 @NotNull final OverridingStrategy strategy
629 ) {
630 return extractMembersOverridableInBothWays(overrider, extractFrom,
631 // ID
632 new Function1<CallableMemberDescriptor, CallableDescriptor>() {
633 @Override
634 public CallableDescriptor invoke(CallableMemberDescriptor descriptor) {
635 return descriptor;
636 }
637 },
638 new Function1<CallableMemberDescriptor, Unit>() {
639 @Override
640 public Unit invoke(CallableMemberDescriptor descriptor) {
641 strategy.conflict(overrider, descriptor);
642 return Unit.INSTANCE;
643 }
644 });
645 }
646
647
648 public static void resolveUnknownVisibilityForMember(
649 @NotNull CallableMemberDescriptor memberDescriptor,
650 @Nullable Function1<CallableMemberDescriptor, Unit> cannotInferVisibility
651 ) {
652 for (CallableMemberDescriptor descriptor : memberDescriptor.getOverriddenDescriptors()) {
653 if (descriptor.getVisibility() == Visibilities.INHERITED) {
654 resolveUnknownVisibilityForMember(descriptor, cannotInferVisibility);
655 }
656 }
657
658 if (memberDescriptor.getVisibility() != Visibilities.INHERITED) {
659 return;
660 }
661
662 Visibility maxVisibility = computeVisibilityToInherit(memberDescriptor);
663 Visibility visibilityToInherit;
664 if (maxVisibility == null) {
665 if (cannotInferVisibility != null) {
666 cannotInferVisibility.invoke(memberDescriptor);
667 }
668 visibilityToInherit = Visibilities.PUBLIC;
669 }
670 else {
671 visibilityToInherit = maxVisibility;
672 }
673
674 if (memberDescriptor instanceof PropertyDescriptorImpl) {
675 ((PropertyDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
676 for (PropertyAccessorDescriptor accessor : ((PropertyDescriptor) memberDescriptor).getAccessors()) {
677 // If we couldn't infer visibility for property, the diagnostic is already reported, no need to report it again on accessors
678 resolveUnknownVisibilityForMember(accessor, maxVisibility == null ? null : cannotInferVisibility);
679 }
680 }
681 else if (memberDescriptor instanceof FunctionDescriptorImpl) {
682 ((FunctionDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
683 }
684 else {
685 assert memberDescriptor instanceof PropertyAccessorDescriptorImpl;
686 ((PropertyAccessorDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
687 }
688 }
689
690 @Nullable
691 private static Visibility computeVisibilityToInherit(@NotNull CallableMemberDescriptor memberDescriptor) {
692 Collection<? extends CallableMemberDescriptor> overriddenDescriptors = memberDescriptor.getOverriddenDescriptors();
693 Visibility maxVisibility = findMaxVisibility(overriddenDescriptors);
694 if (maxVisibility == null) {
695 return null;
696 }
697 if (memberDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
698 for (CallableMemberDescriptor overridden : overriddenDescriptors) {
699 // An implementation (a non-abstract overridden member) of a fake override should have the maximum possible visibility
700 if (overridden.getModality() != Modality.ABSTRACT && !overridden.getVisibility().equals(maxVisibility)) {
701 return null;
702 }
703 }
704 return maxVisibility;
705 }
706 return maxVisibility.normalize();
707 }
708
709 @Nullable
710 public static Visibility findMaxVisibility(@NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
711 if (descriptors.isEmpty()) {
712 return Visibilities.DEFAULT_VISIBILITY;
713 }
714 Visibility maxVisibility = null;
715 for (CallableMemberDescriptor descriptor : descriptors) {
716 Visibility visibility = descriptor.getVisibility();
717 assert visibility != Visibilities.INHERITED : "Visibility should have been computed for " + descriptor;
718 if (maxVisibility == null) {
719 maxVisibility = visibility;
720 continue;
721 }
722 Integer compareResult = Visibilities.compare(visibility, maxVisibility);
723 if (compareResult == null) {
724 maxVisibility = null;
725 }
726 else if (compareResult > 0) {
727 maxVisibility = visibility;
728 }
729 }
730 if (maxVisibility == null) {
731 return null;
732 }
733 for (CallableMemberDescriptor descriptor : descriptors) {
734 Integer compareResult = Visibilities.compare(maxVisibility, descriptor.getVisibility());
735 if (compareResult == null || compareResult < 0) {
736 return null;
737 }
738 }
739 return maxVisibility;
740 }
741
742 public static class OverrideCompatibilityInfo {
743 public enum Result {
744 OVERRIDABLE,
745 INCOMPATIBLE,
746 CONFLICT,
747 }
748
749 private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(OVERRIDABLE, "SUCCESS");
750
751 @NotNull
752 public static OverrideCompatibilityInfo success() {
753 return SUCCESS;
754 }
755
756 @NotNull
757 public static OverrideCompatibilityInfo incompatible(@NotNull String debugMessage) {
758 return new OverrideCompatibilityInfo(INCOMPATIBLE, debugMessage);
759 }
760
761 @NotNull
762 public static OverrideCompatibilityInfo conflict(@NotNull String debugMessage) {
763 return new OverrideCompatibilityInfo(CONFLICT, debugMessage);
764 }
765
766 private final Result overridable;
767 private final String debugMessage;
768
769 public OverrideCompatibilityInfo(@NotNull Result success, @NotNull String debugMessage) {
770 this.overridable = success;
771 this.debugMessage = debugMessage;
772 }
773
774 @NotNull
775 public Result getResult() {
776 return overridable;
777 }
778
779 @NotNull
780 public String getDebugMessage() {
781 return debugMessage;
782 }
783 }
784 }