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.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 (a instanceof SimpleFunctionDescriptor) {
342 assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass();
343
344 return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType);
345 }
346 if (a instanceof PropertyDescriptor) {
347 assert b instanceof PropertyDescriptor : "b is " + b.getClass();
348
349 PropertyDescriptor pa = (PropertyDescriptor) a;
350 PropertyDescriptor pb = (PropertyDescriptor) b;
351 if (pa.isVar() && pb.isVar()) {
352 return DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters()).equalTypes(aReturnType, bReturnType);
353 }
354 else {
355 // both vals or var vs val: val can't be more specific then var
356 return !(!pa.isVar() && pb.isVar()) && isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType);
357 }
358 }
359 throw new IllegalArgumentException("Unexpected callable: " + a.getClass());
360 }
361
362 private static boolean isMoreSpecificThenAllOf(@NotNull CallableDescriptor candidate, @NotNull Collection<CallableDescriptor> descriptors) {
363 // NB subtyping relation in Kotlin is not transitive in presence of flexible types:
364 // String? <: String! <: String, but not String? <: String
365 for (CallableDescriptor descriptor : descriptors) {
366 if (!isMoreSpecific(candidate, descriptor)) {
367 return false;
368 }
369 }
370 return true;
371 }
372
373 private static boolean isReturnTypeMoreSpecific(
374 @NotNull CallableDescriptor a,
375 @NotNull KotlinType aReturnType,
376 @NotNull CallableDescriptor b,
377 @NotNull KotlinType bReturnType
378 ) {
379 KotlinTypeChecker typeChecker = DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters());
380 return typeChecker.isSubtypeOf(aReturnType, bReturnType);
381 }
382
383 @NotNull
384 public static <H> H selectMostSpecificMember(
385 @NotNull Collection<H> overridables,
386 @NotNull Function1<H, CallableDescriptor> descriptorByHandle
387 ) {
388 assert !overridables.isEmpty() : "Should have at least one overridable descriptor";
389
390 if (overridables.size() == 1) {
391 return CollectionsKt.first(overridables);
392 }
393
394 Collection<H> candidates = new ArrayList<H>(2);
395 List<CallableDescriptor> callableMemberDescriptors = CollectionsKt.map(overridables, descriptorByHandle);
396
397 H transitivelyMostSpecific = CollectionsKt.first(overridables);
398 CallableDescriptor transitivelyMostSpecificDescriptor = descriptorByHandle.invoke(transitivelyMostSpecific);
399
400 for (H overridable : overridables) {
401 CallableDescriptor descriptor = descriptorByHandle.invoke(overridable);
402 if (isMoreSpecificThenAllOf(descriptor, callableMemberDescriptors)) {
403 candidates.add(overridable);
404 }
405 if (isMoreSpecific(descriptor, transitivelyMostSpecificDescriptor)
406 && !isMoreSpecific(transitivelyMostSpecificDescriptor, descriptor)) {
407 transitivelyMostSpecific = overridable;
408 }
409 }
410
411 if (candidates.isEmpty()) {
412 return transitivelyMostSpecific;
413 }
414 else if (candidates.size() == 1) {
415 return CollectionsKt.first(candidates);
416 }
417
418 H firstNonFlexible = null;
419 for (H candidate : candidates) {
420 if (!FlexibleTypesKt.isFlexible(descriptorByHandle.invoke(candidate).getReturnType())) {
421 firstNonFlexible = candidate;
422 break;
423 }
424 }
425 if (firstNonFlexible != null) {
426 return firstNonFlexible;
427 }
428
429 return CollectionsKt.first(candidates);
430 }
431
432 private static void createAndBindFakeOverride(
433 @NotNull Collection<CallableMemberDescriptor> overridables,
434 @NotNull ClassDescriptor current,
435 @NotNull DescriptorSink sink
436 ) {
437 Collection<CallableMemberDescriptor> visibleOverridables = filterVisibleFakeOverrides(current, overridables);
438 boolean allInvisible = visibleOverridables.isEmpty();
439 Collection<CallableMemberDescriptor> effectiveOverridden = allInvisible ? overridables : visibleOverridables;
440
441 // FIXME doesn't work as expected for flexible types: should create a refined signature.
442 // Current algorithm produces bad results in presence of annotated Java signatures such as:
443 // J: foo(s: String!): String -- @NotNull String foo(String s);
444 // K: foo(s: String): String?
445 // --> 'foo(s: String!): String' as an inherited signature with most specific return type.
446 // This is bad because it can be overridden by 'foo(s: String?): String', which is not override-equivalent with K::foo above.
447 // Should be 'foo(s: String): String'.
448 Modality modality = getMinimalModality(effectiveOverridden);
449 Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED;
450 CallableMemberDescriptor mostSpecific =
451 selectMostSpecificMember(effectiveOverridden,
452 new Function1<CallableMemberDescriptor, CallableDescriptor>() {
453 @Override
454 public CallableMemberDescriptor invoke(CallableMemberDescriptor descriptor) {
455 return descriptor;
456 }
457 });
458 CallableMemberDescriptor fakeOverride =
459 mostSpecific.copy(current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
460 for (CallableMemberDescriptor descriptor : effectiveOverridden) {
461 fakeOverride.addOverriddenDescriptor(descriptor);
462 }
463 sink.addFakeOverride(fakeOverride);
464 }
465
466 @NotNull
467 private static Modality getMinimalModality(@NotNull Collection<CallableMemberDescriptor> descriptors) {
468 Modality modality = Modality.ABSTRACT;
469 for (CallableMemberDescriptor descriptor : descriptors) {
470 if (descriptor.getModality().compareTo(modality) < 0) {
471 modality = descriptor.getModality();
472 }
473 }
474 return modality;
475 }
476
477 @NotNull
478 private static Collection<CallableMemberDescriptor> filterVisibleFakeOverrides(
479 @NotNull final ClassDescriptor current,
480 @NotNull Collection<CallableMemberDescriptor> toFilter
481 ) {
482 return CollectionsKt.filter(toFilter, new Function1<CallableMemberDescriptor, Boolean>() {
483 @Override
484 public Boolean invoke(CallableMemberDescriptor descriptor) {
485 //nested class could capture private member, so check for private visibility added
486 return !Visibilities.isPrivate(descriptor.getVisibility()) &&
487 Visibilities.isVisibleWithIrrelevantReceiver(descriptor, current);
488 }
489 });
490 }
491
492 /**
493 * @param <H> is something that handles CallableDescriptor inside
494 * @return
495 */
496 @NotNull
497 public static <H> Collection<H> extractMembersOverridableInBothWays(
498 @NotNull H overrider,
499 @NotNull @Mutable Collection<H> extractFrom,
500 @NotNull Function1<H, CallableDescriptor> descriptorByHandle,
501 @NotNull Function1<H, Unit> onConflict
502 ) {
503 Collection<H> overridable = new ArrayList<H>();
504 overridable.add(overrider);
505 CallableDescriptor overriderDescriptor = descriptorByHandle.invoke(overrider);
506 for (Iterator<H> iterator = extractFrom.iterator(); iterator.hasNext(); ) {
507 H candidate = iterator.next();
508 CallableDescriptor candidateDescriptor = descriptorByHandle.invoke(candidate);
509 if (overrider == candidate) {
510 iterator.remove();
511 continue;
512 }
513
514 OverrideCompatibilityInfo.Result finalResult = getBothWaysOverridability(overriderDescriptor, candidateDescriptor);
515
516 if (finalResult == OVERRIDABLE) {
517 overridable.add(candidate);
518 iterator.remove();
519 }
520 else if (finalResult == CONFLICT) {
521 onConflict.invoke(candidate);
522 iterator.remove();
523 }
524 }
525 return overridable;
526 }
527
528 @Nullable
529 public static OverrideCompatibilityInfo.Result getBothWaysOverridability(
530 CallableDescriptor overriderDescriptor,
531 CallableDescriptor candidateDescriptor
532 ) {
533 OverrideCompatibilityInfo.Result result1 = DEFAULT.isOverridableBy(candidateDescriptor, overriderDescriptor, null).getResult();
534 OverrideCompatibilityInfo.Result result2 = DEFAULT.isOverridableBy(overriderDescriptor, candidateDescriptor, null).getResult();
535
536 return result1 == OVERRIDABLE && result2 == OVERRIDABLE
537 ? OVERRIDABLE
538 : ((result1 == CONFLICT || result2 == CONFLICT) ? CONFLICT : INCOMPATIBLE);
539 }
540
541 @NotNull
542 private static Collection<CallableMemberDescriptor> extractMembersOverridableInBothWays(
543 @NotNull final CallableMemberDescriptor overrider,
544 @NotNull Queue<CallableMemberDescriptor> extractFrom,
545 @NotNull final DescriptorSink sink
546 ) {
547 return extractMembersOverridableInBothWays(overrider, extractFrom,
548 // ID
549 new Function1<CallableMemberDescriptor, CallableDescriptor>() {
550 @Override
551 public CallableDescriptor invoke(CallableMemberDescriptor descriptor) {
552 return descriptor;
553 }
554 },
555 new Function1<CallableMemberDescriptor, Unit>() {
556 @Override
557 public Unit invoke(CallableMemberDescriptor descriptor) {
558 sink.conflict(overrider, descriptor);
559 return Unit.INSTANCE;
560 }
561 });
562 }
563
564
565 public static void resolveUnknownVisibilityForMember(
566 @NotNull CallableMemberDescriptor memberDescriptor,
567 @Nullable Function1<CallableMemberDescriptor, Unit> cannotInferVisibility
568 ) {
569 for (CallableMemberDescriptor descriptor : memberDescriptor.getOverriddenDescriptors()) {
570 if (descriptor.getVisibility() == Visibilities.INHERITED) {
571 resolveUnknownVisibilityForMember(descriptor, cannotInferVisibility);
572 }
573 }
574
575 if (memberDescriptor.getVisibility() != Visibilities.INHERITED) {
576 return;
577 }
578
579 Visibility maxVisibility = computeVisibilityToInherit(memberDescriptor);
580 Visibility visibilityToInherit;
581 if (maxVisibility == null) {
582 if (cannotInferVisibility != null) {
583 cannotInferVisibility.invoke(memberDescriptor);
584 }
585 visibilityToInherit = Visibilities.PUBLIC;
586 }
587 else {
588 visibilityToInherit = maxVisibility;
589 }
590
591 if (memberDescriptor instanceof PropertyDescriptorImpl) {
592 ((PropertyDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
593 for (PropertyAccessorDescriptor accessor : ((PropertyDescriptor) memberDescriptor).getAccessors()) {
594 // If we couldn't infer visibility for property, the diagnostic is already reported, no need to report it again on accessors
595 resolveUnknownVisibilityForMember(accessor, maxVisibility == null ? null : cannotInferVisibility);
596 }
597 }
598 else if (memberDescriptor instanceof FunctionDescriptorImpl) {
599 ((FunctionDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
600 }
601 else {
602 assert memberDescriptor instanceof PropertyAccessorDescriptorImpl;
603 ((PropertyAccessorDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
604 }
605 }
606
607 @Nullable
608 private static Visibility computeVisibilityToInherit(@NotNull CallableMemberDescriptor memberDescriptor) {
609 Collection<? extends CallableMemberDescriptor> overriddenDescriptors = memberDescriptor.getOverriddenDescriptors();
610 Visibility maxVisibility = findMaxVisibility(overriddenDescriptors);
611 if (maxVisibility == null) {
612 return null;
613 }
614 if (memberDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
615 for (CallableMemberDescriptor overridden : overriddenDescriptors) {
616 // An implementation (a non-abstract overridden member) of a fake override should have the maximum possible visibility
617 if (overridden.getModality() != Modality.ABSTRACT && !overridden.getVisibility().equals(maxVisibility)) {
618 return null;
619 }
620 }
621 return maxVisibility;
622 }
623 return maxVisibility.normalize();
624 }
625
626 @Nullable
627 public static Visibility findMaxVisibility(@NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
628 if (descriptors.isEmpty()) {
629 return Visibilities.DEFAULT_VISIBILITY;
630 }
631 Visibility maxVisibility = null;
632 for (CallableMemberDescriptor descriptor : descriptors) {
633 Visibility visibility = descriptor.getVisibility();
634 assert visibility != Visibilities.INHERITED : "Visibility should have been computed for " + descriptor;
635 if (maxVisibility == null) {
636 maxVisibility = visibility;
637 continue;
638 }
639 Integer compareResult = Visibilities.compare(visibility, maxVisibility);
640 if (compareResult == null) {
641 maxVisibility = null;
642 }
643 else if (compareResult > 0) {
644 maxVisibility = visibility;
645 }
646 }
647 if (maxVisibility == null) {
648 return null;
649 }
650 for (CallableMemberDescriptor descriptor : descriptors) {
651 Integer compareResult = Visibilities.compare(maxVisibility, descriptor.getVisibility());
652 if (compareResult == null || compareResult < 0) {
653 return null;
654 }
655 }
656 return maxVisibility;
657 }
658
659 public interface DescriptorSink {
660 void addFakeOverride(@NotNull CallableMemberDescriptor fakeOverride);
661
662 void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent);
663 }
664
665 public static class OverrideCompatibilityInfo {
666 public enum Result {
667 OVERRIDABLE,
668 INCOMPATIBLE,
669 CONFLICT,
670 }
671
672 private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(OVERRIDABLE, "SUCCESS");
673
674 @NotNull
675 public static OverrideCompatibilityInfo success() {
676 return SUCCESS;
677 }
678
679 @NotNull
680 public static OverrideCompatibilityInfo incompatible(@NotNull String debugMessage) {
681 return new OverrideCompatibilityInfo(INCOMPATIBLE, debugMessage);
682 }
683
684 @NotNull
685 public static OverrideCompatibilityInfo conflict(@NotNull String debugMessage) {
686 return new OverrideCompatibilityInfo(CONFLICT, debugMessage);
687 }
688
689 private final Result overridable;
690 private final String debugMessage;
691
692 public OverrideCompatibilityInfo(@NotNull Result success, @NotNull String debugMessage) {
693 this.overridable = success;
694 this.debugMessage = debugMessage;
695 }
696
697 @NotNull
698 public Result getResult() {
699 return overridable;
700 }
701
702 @NotNull
703 public String getDebugMessage() {
704 return debugMessage;
705 }
706 }
707 }