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    }