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