Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.resolve.OverrideResolver Maven / Gradle / Ivy
package org.jetbrains.kotlin.resolve;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.LinkedMultiMap;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.SmartHashSet;
import com.intellij.util.containers.hash.EqualityPolicy;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ReadOnly;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactoryWithPsiElement;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilKt;
import org.jetbrains.kotlin.resolve.dataClassUtils.DataClassUtilsKt;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.kotlin.utils.HashSetUtil;
import java.util.*;
import static kotlin.collections.CollectionsKt.sortedBy;
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.*;
import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractMembers;
import static org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE;
public class OverrideResolver {
@NotNull private final BindingTrace trace;
public OverrideResolver(@NotNull BindingTrace trace) {
this .trace = trace;
}
public void check(@NotNull TopDownAnalysisContext c) {
checkVisibility(c);
checkOverrides(c);
checkParameterOverridesForAllClasses(c);
}
public static void generateOverridesInAClass(
@NotNull ClassDescriptor classDescriptor,
@NotNull Collection membersFromCurrent,
@NotNull OverridingStrategy strategy
) {
List membersFromSupertypes = getCallableMembersFromSupertypes(classDescriptor);
MultiMap membersFromCurrentByName = groupDescriptorsByName(membersFromCurrent);
MultiMap membersFromSupertypesByName = groupDescriptorsByName(membersFromSupertypes);
Set memberNames = new LinkedHashSet();
memberNames.addAll(membersFromSupertypesByName.keySet());
memberNames.addAll(membersFromCurrentByName.keySet());
for (Name memberName : memberNames) {
Collection fromSupertypes = membersFromSupertypesByName.get(memberName);
Collection fromCurrent = membersFromCurrentByName.get(memberName);
OverridingUtil.generateOverridesInFunctionGroup(memberName, fromSupertypes, fromCurrent, classDescriptor, strategy);
}
}
public static void resolveUnknownVisibilities(
@NotNull Collection descriptors,
@NotNull BindingTrace trace
) {
for (CallableMemberDescriptor descriptor : descriptors) {
OverridingUtil.resolveUnknownVisibilityForMember(descriptor, createCannotInferVisibilityReporter(trace));
}
}
@NotNull
public static Function1 createCannotInferVisibilityReporter(@NotNull final BindingTrace trace) {
return new Function1() {
@Override
public Unit invoke(@NotNull CallableMemberDescriptor descriptor) {
DeclarationDescriptor reportOn;
if (descriptor.getKind() == FAKE_OVERRIDE || descriptor.getKind() == DELEGATION) {
reportOn = DescriptorUtils.getParentOfType(descriptor, ClassDescriptor.class );
}
else if (descriptor instanceof PropertyAccessorDescriptor && ((PropertyAccessorDescriptor) descriptor).isDefault()) {
reportOn = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
}
else {
reportOn = descriptor;
}
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(reportOn);
if (element instanceof KtDeclaration) {
trace.report(CANNOT_INFER_VISIBILITY.on((KtDeclaration) element, descriptor));
}
return Unit.INSTANCE;
}
};
}
private static enum Filtering {
RETAIN_OVERRIDING,
RETAIN_OVERRIDDEN
}
@NotNull
public static Set filterOutOverridden(@NotNull Set candidateSet) {
return filterOverrides(candidateSet, Function.ID, Filtering.RETAIN_OVERRIDING);
}
@NotNull
public static Set filterOutOverriding(@NotNull Set candidateSet) {
return filterOverrides(candidateSet, Function.ID, Filtering.RETAIN_OVERRIDDEN);
}
@NotNull
public static Set filterOutOverridden(
@NotNull Set candidateSet,
@NotNull Function transform
) {
return filterOverrides(candidateSet, transform, Filtering.RETAIN_OVERRIDING);
}
@NotNull
private static Set noDuplicates(
@NotNull Set candidateSet,
@NotNull final Function transform
) {
List fromSourcesGoesFirst = sortedBy(candidateSet, new Function1() {
@Override
public Integer invoke(D d) {
return DescriptorToSourceUtils.descriptorToDeclaration(transform.fun(d)) != null ? 0 : 1 ;
}
});
return HashSetUtil.linkedHashSet(
fromSourcesGoesFirst,
new EqualityPolicy() {
@Override
public int getHashCode(D d) {
return DescriptorUtils.getFqName(transform.fun(d).getContainingDeclaration()).hashCode();
}
@Override
public boolean isEqual(D d1, D d2) {
CallableDescriptor f = transform.fun(d1).getOriginal();
CallableDescriptor g = transform.fun(d2).getOriginal();
boolean ignoreReturnType = (DescriptorToSourceUtils.descriptorToDeclaration(f) == null ) !=
(DescriptorToSourceUtils.descriptorToDeclaration(g) == null );
return DescriptorEquivalenceForOverrides.INSTANCE.areCallableDescriptorsEquivalent(f, g, ignoreReturnType);
}
});
}
@NotNull
private static Set filterOverrides(
@NotNull Set candidateSet,
@NotNull Function transform,
@NotNull Filtering filtering
) {
if (candidateSet.size() <= 1 ) return candidateSet;
Set noDuplicates = noDuplicates(candidateSet, transform);
Set candidates = Sets.newLinkedHashSet();
outerLoop:
for (D meD : noDuplicates) {
CallableDescriptor me = transform.fun(meD);
for (D otherD : noDuplicates) {
CallableDescriptor other = transform.fun(otherD);
if (me == other) continue ;
if (filtering == Filtering.RETAIN_OVERRIDING) {
if (overrides(other, me)) {
continue outerLoop;
}
}
else if (filtering == Filtering.RETAIN_OVERRIDDEN) {
if (overrides(me, other)) {
continue outerLoop;
}
}
else {
throw new AssertionError("Unexpected Filtering object: " + filtering);
}
}
for (D otherD : candidates) {
CallableDescriptor other = transform.fun(otherD);
if (me.getOriginal() == other.getOriginal()
&& OverridingUtil.DEFAULT.isOverridableBy(other, me, null ).getResult() == OVERRIDABLE
&& OverridingUtil.DEFAULT.isOverridableBy(me, other, null ).getResult() == OVERRIDABLE) {
continue outerLoop;
}
}
candidates.add(meD);
}
assert !candidates.isEmpty() : "All candidates filtered out from " + candidateSet;
return candidates;
}
public static boolean overrides(@NotNull D f, @NotNull D g) {
if (!f.equals(g) && DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(f.getOriginal(), g.getOriginal())) return true ;
CallableDescriptor originalG = g.getOriginal();
for (D overriddenFunction : DescriptorUtils.getAllOverriddenDescriptors(f)) {
if (DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(originalG, overriddenFunction.getOriginal())) return true ;
}
return false ;
}
private static MultiMap groupDescriptorsByName(Collection properties) {
MultiMap r = new LinkedMultiMap();
for (T property : properties) {
r.putValue(property.getName(), property);
}
return r;
}
private static List getCallableMembersFromSupertypes(ClassDescriptor classDescriptor) {
Set r = Sets.newLinkedHashSet();
for (KotlinType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
r.addAll(getCallableMembersFromType(supertype));
}
return new ArrayList(r);
}
private static List getCallableMembersFromType(KotlinType type) {
List r = Lists.newArrayList();
for (DeclarationDescriptor decl : DescriptorUtils.getAllDescriptors(type.getMemberScope())) {
if (decl instanceof PropertyDescriptor || decl instanceof SimpleFunctionDescriptor) {
r.add((CallableMemberDescriptor) decl);
}
}
return r;
}
private void checkOverrides(@NotNull TopDownAnalysisContext c) {
for (Map.Entry entry : c.getDeclaredClasses().entrySet()) {
checkOverridesInAClass(entry.getValue(), entry.getKey());
}
}
private void checkOverridesInAClass(@NotNull ClassDescriptorWithResolutionScopes classDescriptor, @NotNull final KtClassOrObject klass) {
for (CallableMemberDescriptor member : classDescriptor.getDeclaredCallableMembers()) {
checkOverrideForMember(member);
}
CollectErrorInformationForInheritedMembersStrategy inheritedMemberErrors =
new CollectErrorInformationForInheritedMembersStrategy(klass, classDescriptor);
checkInheritedAndDelegatedSignatures(classDescriptor, inheritedMemberErrors, inheritedMemberErrors);
inheritedMemberErrors.doReportErrors();
}
@NotNull
public static Set getMissingImplementations(@NotNull ClassDescriptor classDescriptor) {
CollectMissingImplementationsStrategy collector = new CollectMissingImplementationsStrategy();
checkInheritedAndDelegatedSignatures(classDescriptor, collector, null );
return collector.shouldImplement;
}
private interface CheckInheritedSignaturesReportStrategy {
void abstractMemberNotImplemented(CallableMemberDescriptor descriptor);
void abstractBaseClassMemberNotImplemented(CallableMemberDescriptor descriptor);
void multipleImplementationsMemberNotImplemented(CallableMemberDescriptor descriptor);
void conflictingInterfaceMemberNotImplemented(CallableMemberDescriptor descriptor);
void returnTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2);
void propertyTypeMismatchOnInheritance(PropertyDescriptor descriptor1, PropertyDescriptor descriptor2);
}
private static class CollectMissingImplementationsStrategy implements CheckInheritedSignaturesReportStrategy {
private final Set shouldImplement = new LinkedHashSet();
@Override
public void abstractMemberNotImplemented(CallableMemberDescriptor descriptor) {
shouldImplement.add(descriptor);
}
@Override
public void abstractBaseClassMemberNotImplemented(CallableMemberDescriptor descriptor) {
}
@Override
public void multipleImplementationsMemberNotImplemented(CallableMemberDescriptor descriptor) {
shouldImplement.add(descriptor);
}
@Override
public void conflictingInterfaceMemberNotImplemented(CallableMemberDescriptor descriptor) {
}
@Override
public void returnTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) {
}
@Override
public void propertyTypeMismatchOnInheritance(PropertyDescriptor descriptor1, PropertyDescriptor descriptor2) {
}
}
private class CollectErrorInformationForInheritedMembersStrategy
implements CheckInheritedSignaturesReportStrategy , CheckOverrideReportStrategy {
private final KtClassOrObject klass;
private final ClassDescriptor classDescriptor;
private final Set abstractNoImpl = Sets.newLinkedHashSet();
private final Set multipleImplementations = Sets.newLinkedHashSet();
private final Set abstractInBaseClassNoImpl = Sets.newLinkedHashSet();
private final Set conflictingInterfaceMembers = Sets.newLinkedHashSet();
private final Set conflictingReturnTypes = Sets.newHashSet();
private final Set onceErrorsReported = new SmartHashSet();
public CollectErrorInformationForInheritedMembersStrategy(
@NotNull KtClassOrObject klass,
@NotNull ClassDescriptor classDescriptor
) {
this .klass = klass;
this .classDescriptor = classDescriptor;
}
@Override
public void abstractMemberNotImplemented(CallableMemberDescriptor descriptor) {
abstractNoImpl.add(descriptor);
}
@Override
public void abstractBaseClassMemberNotImplemented(CallableMemberDescriptor descriptor) {
abstractInBaseClassNoImpl.add(descriptor);
}
@Override
public void multipleImplementationsMemberNotImplemented(CallableMemberDescriptor descriptor) {
multipleImplementations.add(descriptor);
}
@Override
public void conflictingInterfaceMemberNotImplemented(CallableMemberDescriptor descriptor) {
conflictingInterfaceMembers.add(descriptor);
}
@Override
public void returnTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) {
conflictingReturnTypes.add(descriptor1);
conflictingReturnTypes.add(descriptor2);
reportInheritanceConflictIfRequired(RETURN_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2);
}
@Override
public void propertyTypeMismatchOnInheritance(PropertyDescriptor descriptor1, PropertyDescriptor descriptor2) {
conflictingReturnTypes.add(descriptor1);
conflictingReturnTypes.add(descriptor2);
if (descriptor1.isVar() || descriptor2.isVar()) {
reportInheritanceConflictIfRequired(VAR_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2);
}
else {
reportInheritanceConflictIfRequired(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2);
}
}
private void reportInheritanceConflictIfRequired(
@NotNull DiagnosticFactory2 diagnosticFactory,
@NotNull CallableMemberDescriptor descriptor1,
@NotNull CallableMemberDescriptor descriptor2
) {
if (!onceErrorsReported.contains(diagnosticFactory)) {
onceErrorsReported.add(diagnosticFactory);
trace.report(diagnosticFactory.on(klass, descriptor1, descriptor2));
}
}
@Override
public void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
reportDelegationProblemIfRequired(OVERRIDING_FINAL_MEMBER_BY_DELEGATION, overriding, overridden);
}
@Override
public void returnTypeMismatchOnOverride(
@NotNull CallableMemberDescriptor overriding,
@NotNull CallableMemberDescriptor overridden
) {
}
@Override
public void propertyTypeMismatchOnOverride(
@NotNull PropertyDescriptor overriding,
@NotNull PropertyDescriptor overridden
) {
}
@Override
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
reportDelegationProblemIfRequired(VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION, overriding, overridden);
}
private void reportDelegationProblemIfRequired(
@NotNull DiagnosticFactory2 diagnosticFactory,
@NotNull CallableMemberDescriptor delegate,
@NotNull CallableMemberDescriptor overridden
) {
assert delegate.getKind() == DELEGATION : "Delegate expected, got " + delegate + " of kind " + delegate.getKind();
if (!onceErrorsReported.contains(diagnosticFactory)) {
onceErrorsReported.add(diagnosticFactory);
trace.report(diagnosticFactory.on(klass, delegate, overridden));
}
}
@Override
public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden) {
assert overriding.getKind() == DELEGATION : "Delegate expected, got " + overriding + " of kind " + overriding.getKind();
assert overriding.getKind() != DELEGATION : "Delegated member can't override an invisible member; " + invisibleOverridden;
}
@Override
public void nothingToOverride(@NotNull CallableMemberDescriptor overriding) {
assert overriding.getKind() == DELEGATION : "Delegate expected, got " + overriding + " of kind " + overriding.getKind();
assert overriding.getKind() != DELEGATION : "Delegated member can't override nothing; " + overriding;
}
void doReportErrors() {
if (!classCanHaveAbstractMembers(classDescriptor)) {
if (!abstractInBaseClassNoImpl.isEmpty()) {
trace.report(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractInBaseClassNoImpl.iterator().next()));
}
else if (!abstractNoImpl.isEmpty()) {
trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractNoImpl.iterator().next()));
}
}
conflictingInterfaceMembers.removeAll(conflictingReturnTypes);
multipleImplementations.removeAll(conflictingReturnTypes);
if (!conflictingInterfaceMembers.isEmpty()) {
trace.report(MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.on(klass, klass, conflictingInterfaceMembers.iterator().next()));
}
else if (!multipleImplementations.isEmpty()) {
trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(klass, klass, multipleImplementations.iterator().next()));
}
}
}
private static void checkInheritedAndDelegatedSignatures(
@NotNull ClassDescriptor classDescriptor,
@NotNull CheckInheritedSignaturesReportStrategy inheritedReportStrategy,
@Nullable CheckOverrideReportStrategy overrideReportStrategyForDelegates
) {
for (DeclarationDescriptor member : DescriptorUtils.getAllDescriptors(classDescriptor.getDefaultType().getMemberScope())) {
if (member instanceof CallableMemberDescriptor) {
checkInheritedAndDelegatedSignatures((CallableMemberDescriptor) member, inheritedReportStrategy, overrideReportStrategyForDelegates);
}
}
}
private static void checkInheritedAndDelegatedSignatures(
@NotNull CallableMemberDescriptor descriptor,
@NotNull CheckInheritedSignaturesReportStrategy reportingStrategy,
@Nullable CheckOverrideReportStrategy overrideReportStrategyForDelegates
) {
CallableMemberDescriptor.Kind kind = descriptor.getKind();
if (kind != FAKE_OVERRIDE && kind != DELEGATION) return ;
if (descriptor.getVisibility() == Visibilities.INVISIBLE_FAKE) return ;
Collection directOverridden = descriptor.getOverriddenDescriptors();
assert !directOverridden.isEmpty() : kind + " " + descriptor.getName().asString() + " must override something" ;
Map> overriddenDeclarationsByDirectParent = collectOverriddenDeclarations(directOverridden);
List allOverriddenDeclarations = ContainerUtil.flatten(overriddenDeclarationsByDirectParent.values());
Set allFilteredOverriddenDeclarations = filterOutOverridden(
Sets.newLinkedHashSet(allOverriddenDeclarations));
Set relevantDirectlyOverridden =
getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations);
checkInheritedDescriptorsGroup(relevantDirectlyOverridden, descriptor, reportingStrategy);
if (kind == DELEGATION && overrideReportStrategyForDelegates != null ) {
checkOverridesForMember(descriptor, relevantDirectlyOverridden, overrideReportStrategyForDelegates);
}
if (kind != DELEGATION) {
checkMissingOverridesByJava8Restrictions(relevantDirectlyOverridden, reportingStrategy);
}
List implementations = collectImplementations(relevantDirectlyOverridden);
int numImplementations = implementations.size();
if (numImplementations == 1 && isReturnTypeOkForOverride(descriptor, implementations.get(0 ))) return ;
List abstractOverridden = new ArrayList(allFilteredOverriddenDeclarations.size());
List concreteOverridden = new ArrayList(allFilteredOverriddenDeclarations.size());
filterNotSynthesizedDescriptorsByModality(allFilteredOverriddenDeclarations, abstractOverridden, concreteOverridden);
if (numImplementations == 0 ) {
if (kind != DELEGATION) {
for (CallableMemberDescriptor member : abstractOverridden) {
reportingStrategy.abstractMemberNotImplemented(member);
}
}
}
else if (numImplementations > 1 ) {
for (CallableMemberDescriptor member : concreteOverridden) {
reportingStrategy.multipleImplementationsMemberNotImplemented(member);
}
}
else {
if (kind != DELEGATION) {
List membersWithMoreSpecificReturnType =
collectAbstractMethodsWithMoreSpecificReturnType(abstractOverridden, implementations.get(0 ));
for (CallableMemberDescriptor member : membersWithMoreSpecificReturnType) {
reportingStrategy.abstractMemberNotImplemented(member);
}
}
}
}
private static void checkMissingOverridesByJava8Restrictions(
@NotNull Set relevantDirectlyOverridden,
@NotNull CheckInheritedSignaturesReportStrategy reportingStrategy
) {
boolean overridesClassMember = false ;
boolean overridesNonAbstractInterfaceMember = false ;
CallableMemberDescriptor overridesAbstractInBaseClass = null ;
List overriddenInterfaceMembers = new SmartList();
for (CallableMemberDescriptor overridden : relevantDirectlyOverridden) {
DeclarationDescriptor containingDeclaration = overridden.getContainingDeclaration();
if (containingDeclaration instanceof ClassDescriptor) {
ClassDescriptor baseClassOrInterface = (ClassDescriptor) containingDeclaration;
if (baseClassOrInterface.getKind() == ClassKind.CLASS) {
overridesClassMember = true ;
if (overridden.getModality() == Modality.ABSTRACT) {
overridesAbstractInBaseClass = overridden;
}
}
else if (baseClassOrInterface.getKind() == ClassKind.INTERFACE) {
overriddenInterfaceMembers.add(overridden);
if (overridden.getModality() != Modality.ABSTRACT) {
overridesNonAbstractInterfaceMember = true ;
}
}
}
}
if (overridesAbstractInBaseClass != null ) {
reportingStrategy.abstractBaseClassMemberNotImplemented(overridesAbstractInBaseClass);
}
if (!overridesClassMember && overridesNonAbstractInterfaceMember && overriddenInterfaceMembers.size() > 1 ) {
for (CallableMemberDescriptor member : overriddenInterfaceMembers) {
reportingStrategy.conflictingInterfaceMemberNotImplemented(member);
}
}
}
@NotNull
private static List collectImplementations(@NotNull Set relevantDirectlyOverridden) {
List result = new ArrayList(relevantDirectlyOverridden.size());
for (CallableMemberDescriptor overriddenDescriptor : relevantDirectlyOverridden) {
if (overriddenDescriptor.getModality() != Modality.ABSTRACT) {
result.add(overriddenDescriptor);
}
}
return result;
}
private static void filterNotSynthesizedDescriptorsByModality(
@NotNull Set allOverriddenDeclarations,
@NotNull List abstractOverridden,
@NotNull List concreteOverridden
) {
for (CallableMemberDescriptor overridden : allOverriddenDeclarations) {
if (!CallResolverUtilKt.isOrOverridesSynthesized(overridden)) {
if (overridden.getModality() == Modality.ABSTRACT) {
abstractOverridden.add(overridden);
}
else {
concreteOverridden.add(overridden);
}
}
}
}
@NotNull
private static List collectAbstractMethodsWithMoreSpecificReturnType(
@NotNull List abstractOverridden,
@NotNull CallableMemberDescriptor implementation
) {
List result = new ArrayList(abstractOverridden.size());
for (CallableMemberDescriptor abstractMember : abstractOverridden) {
if (!isReturnTypeOkForOverride(abstractMember, implementation)) {
result.add(abstractMember);
}
}
assert !result.isEmpty() : "Implementation (" + implementation + ") doesn't have the most specific type, " +
"but none of the other overridden methods does either: " + abstractOverridden;
return result;
}
@NotNull
private static Set getRelevantDirectlyOverridden(
@NotNull Map> overriddenByParent,
@NotNull Set allFilteredOverriddenDeclarations
) {
for (Iterator>> iterator =
overriddenByParent.entrySet().iterator(); iterator.hasNext(); ) {
if (!isRelevant(iterator.next().getValue(), overriddenByParent.values(), allFilteredOverriddenDeclarations)) {
iterator.remove();
}
}
return overriddenByParent.keySet();
}
private static boolean isRelevant(
@NotNull Set declarationSet,
@NotNull Collection> allDeclarationSets,
@NotNull Set allFilteredOverriddenDeclarations
) {
for (Set otherSet : allDeclarationSets) {
if (otherSet == declarationSet) continue ;
if (otherSet.containsAll(declarationSet)) return false ;
if (Collections.disjoint(allFilteredOverriddenDeclarations, declarationSet)) return false ;
}
return true ;
}
@NotNull
private static Map> collectOverriddenDeclarations(
@NotNull Collection directOverriddenDescriptors
) {
Map> overriddenDeclarationsByDirectParent = Maps.newLinkedHashMap();
for (CallableMemberDescriptor descriptor : directOverriddenDescriptors) {
Set overriddenDeclarations = getOverriddenDeclarations(descriptor);
Set filteredOverrides = filterOutOverridden(overriddenDeclarations);
overriddenDeclarationsByDirectParent.put(descriptor, new LinkedHashSet(filteredOverrides));
}
return overriddenDeclarationsByDirectParent;
}
@NotNull
public static Set getOverriddenDeclarations(@NotNull CallableMemberDescriptor descriptor) {
Set result = new LinkedHashSet();
getOverriddenDeclarations(descriptor, result);
return result;
}
private static void getOverriddenDeclarations(
@NotNull CallableMemberDescriptor descriptor,
@NotNull Set result
) {
if (descriptor.getKind().isReal()) {
result.add(descriptor);
}
else {
if (descriptor.getOverriddenDescriptors().isEmpty()) {
throw new IllegalStateException("No overridden descriptors found for (fake override) " + descriptor);
}
for (CallableMemberDescriptor overridden : descriptor.getOverriddenDescriptors()) {
getOverriddenDeclarations(overridden, result);
}
}
}
private interface CheckOverrideReportStrategy {
void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden);
void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden);
void propertyTypeMismatchOnOverride(@NotNull PropertyDescriptor overriding, @NotNull PropertyDescriptor overridden);
void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden);
void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden);
void nothingToOverride(@NotNull CallableMemberDescriptor overriding);
}
private void checkOverrideForMember(@NotNull final CallableMemberDescriptor declared) {
if (declared.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED) {
if (DataClassUtilsKt.isComponentLike(declared.getName())) {
checkOverrideForComponentFunction(declared);
}
return ;
}
if (declared.getKind() != CallableMemberDescriptor.Kind.DECLARATION) {
return ;
}
final KtNamedDeclaration member = (KtNamedDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(declared);
if (member == null ) {
throw new IllegalStateException("declared descriptor is not resolved to declaration: " + declared);
}
KtModifierList modifierList = member.getModifierList();
boolean hasOverrideNode = modifierList != null && modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD);
Collection overriddenDescriptors = declared.getOverriddenDescriptors();
if (hasOverrideNode) {
checkOverridesForMemberMarkedOverride(declared, true , new CheckOverrideReportStrategy() {
private boolean finalOverriddenError = false ;
private boolean typeMismatchError = false ;
private boolean kindMismatchError = false ;
@Override
public void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
if (!finalOverriddenError) {
finalOverriddenError = true ;
trace.report(OVERRIDING_FINAL_MEMBER.on(member, overridden, overridden.getContainingDeclaration()));
}
}
@Override
public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
if (!typeMismatchError) {
typeMismatchError = true ;
trace.report(RETURN_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden));
}
}
@Override
public void propertyTypeMismatchOnOverride(@NotNull PropertyDescriptor overriding, @NotNull PropertyDescriptor overridden) {
if (!typeMismatchError) {
typeMismatchError = true ;
if (overridden.isVar()) {
trace.report(VAR_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden));
}
else {
trace.report(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden));
}
}
}
@Override
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
if (!kindMismatchError) {
kindMismatchError = true ;
trace.report(VAR_OVERRIDDEN_BY_VAL.on(member, (PropertyDescriptor) declared, (PropertyDescriptor) overridden));
}
}
@Override
public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden) {
trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, invisibleOverridden));
}
@Override
public void nothingToOverride(@NotNull CallableMemberDescriptor overriding) {
trace.report(NOTHING_TO_OVERRIDE.on(member, declared));
}
});
}
else if (!overriddenDescriptors.isEmpty()) {
CallableMemberDescriptor overridden = overriddenDescriptors.iterator().next();
trace.report(VIRTUAL_MEMBER_HIDDEN.on(member, declared, overridden, overridden.getContainingDeclaration()));
}
}
private static void checkInheritedDescriptorsGroup(
@NotNull Collection inheritedDescriptors,
@NotNull CallableMemberDescriptor mostSpecific,
@NotNull CheckInheritedSignaturesReportStrategy reportingStrategy
) {
if (inheritedDescriptors.size() > 1 ) {
PropertyDescriptor mostSpecificProperty = mostSpecific instanceof PropertyDescriptor ? (PropertyDescriptor) mostSpecific : null ;
for (CallableMemberDescriptor inheritedDescriptor : inheritedDescriptors) {
if (mostSpecificProperty != null ) {
assert inheritedDescriptor instanceof PropertyDescriptor
: inheritedDescriptor + " inherited from " + mostSpecificProperty + " is not a property" ;
PropertyDescriptor inheritedPropertyDescriptor = (PropertyDescriptor) inheritedDescriptor;
if (!isPropertyTypeOkForOverride(inheritedPropertyDescriptor, mostSpecificProperty)) {
reportingStrategy.propertyTypeMismatchOnInheritance(mostSpecificProperty, inheritedPropertyDescriptor);
}
}
else if (!isReturnTypeOkForOverride(inheritedDescriptor, mostSpecific)) {
reportingStrategy.returnTypeMismatchOnInheritance(mostSpecific, inheritedDescriptor);
}
}
}
}
private static void checkOverridesForMemberMarkedOverride(
@NotNull CallableMemberDescriptor declared,
boolean checkIfOverridesNothing,
@NotNull CheckOverrideReportStrategy reportError
) {
Collection overriddenDescriptors = declared.getOverriddenDescriptors();
checkOverridesForMember(declared, overriddenDescriptors, reportError);
if (checkIfOverridesNothing && overriddenDescriptors.isEmpty()) {
DeclarationDescriptor containingDeclaration = declared.getContainingDeclaration();
assert containingDeclaration instanceof ClassDescriptor : "Overrides may only be resolved in a class, but " + declared + " comes from " + containingDeclaration;
ClassDescriptor declaringClass = (ClassDescriptor) containingDeclaration;
CallableMemberDescriptor invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass);
if (invisibleOverriddenDescriptor != null ) {
reportError.cannotOverrideInvisibleMember(declared, invisibleOverriddenDescriptor);
}
else {
reportError.nothingToOverride(declared);
}
}
}
private static void checkOverridesForMember(
@NotNull CallableMemberDescriptor memberDescriptor,
@NotNull Collection overriddenDescriptors,
@NotNull CheckOverrideReportStrategy reportError
) {
PropertyDescriptor propertyMemberDescriptor =
memberDescriptor instanceof PropertyDescriptor ? (PropertyDescriptor) memberDescriptor : null ;
for (CallableMemberDescriptor overridden : overriddenDescriptors) {
if (overridden == null ) continue ;
if (!ModalityKt.isOverridable(overridden)) {
reportError.overridingFinalMember(memberDescriptor, overridden);
}
if (propertyMemberDescriptor != null ) {
assert overridden instanceof PropertyDescriptor : overridden + " is overridden by property " + propertyMemberDescriptor;
PropertyDescriptor overriddenProperty = (PropertyDescriptor) overridden;
if (!isPropertyTypeOkForOverride(overriddenProperty, propertyMemberDescriptor)) {
reportError.propertyTypeMismatchOnOverride(propertyMemberDescriptor, overriddenProperty);
}
}
else if (!isReturnTypeOkForOverride(overridden, memberDescriptor)) {
reportError.returnTypeMismatchOnOverride(memberDescriptor, overridden);
}
if (checkPropertyKind(overridden, true ) && checkPropertyKind(memberDescriptor, false )) {
reportError.varOverriddenByVal(memberDescriptor, overridden);
}
}
}
public static boolean isReturnTypeOkForOverride(
@NotNull CallableDescriptor superDescriptor,
@NotNull CallableDescriptor subDescriptor
) {
TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor);
if (typeSubstitutor == null ) return false ;
KotlinType superReturnType = superDescriptor.getReturnType();
assert superReturnType != null ;
KotlinType subReturnType = subDescriptor.getReturnType();
assert subReturnType != null ;
KotlinType substitutedSuperReturnType = typeSubstitutor.substitute(superReturnType, Variance.OUT_VARIANCE);
assert substitutedSuperReturnType != null ;
return KotlinTypeChecker.DEFAULT.isSubtypeOf(subReturnType, substitutedSuperReturnType);
}
@Nullable
private static TypeSubstitutor prepareTypeSubstitutor(
@NotNull CallableDescriptor superDescriptor,
@NotNull CallableDescriptor subDescriptor
) {
List superTypeParameters = superDescriptor.getTypeParameters();
List subTypeParameters = subDescriptor.getTypeParameters();
if (subTypeParameters.size() != superTypeParameters.size()) return null ;
ArrayList arguments = new ArrayList(subTypeParameters.size());
for (int i = 0 ; i < superTypeParameters.size(); i++) {
arguments.add(new TypeProjectionImpl(subTypeParameters.get(i).getDefaultType()));
}
return new IndexedParametersSubstitution(superTypeParameters, arguments).buildSubstitutor();
}
public static boolean isPropertyTypeOkForOverride(
@NotNull PropertyDescriptor superDescriptor,
@NotNull PropertyDescriptor subDescriptor
) {
TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor);
if (typeSubstitutor == null ) return false ;
KotlinType substitutedSuperReturnType = typeSubstitutor.substitute(superDescriptor.getType(), Variance.OUT_VARIANCE);
assert substitutedSuperReturnType != null ;
if (superDescriptor.isVar()) {
return KotlinTypeChecker.DEFAULT.equalTypes(subDescriptor.getType(), substitutedSuperReturnType);
}
else {
return KotlinTypeChecker.DEFAULT.isSubtypeOf(subDescriptor.getType(), substitutedSuperReturnType);
}
}
private void checkOverrideForComponentFunction(@NotNull final CallableMemberDescriptor componentFunction) {
final PsiElement dataModifier = findDataModifierForDataClass(componentFunction.getContainingDeclaration());
checkOverridesForMemberMarkedOverride(componentFunction, false , new CheckOverrideReportStrategy() {
private boolean overrideConflict = false ;
@Override
public void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
if (!overrideConflict) {
overrideConflict = true ;
trace.report(DATA_CLASS_OVERRIDE_CONFLICT.on(dataModifier, componentFunction, overridden.getContainingDeclaration()));
}
}
@Override
public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
if (!overrideConflict) {
overrideConflict = true ;
trace.report(DATA_CLASS_OVERRIDE_CONFLICT.on(dataModifier, componentFunction, overridden.getContainingDeclaration()));
}
}
@Override
public void propertyTypeMismatchOnOverride(@NotNull PropertyDescriptor overriding, @NotNull PropertyDescriptor overridden) {
throw new IllegalStateException("Component functions are not properties" );
}
@Override
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
throw new IllegalStateException("Component functions are not properties" );
}
@Override
public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden) {
throw new IllegalStateException("CANNOT_OVERRIDE_INVISIBLE_MEMBER should be reported on the corresponding property" );
}
@Override
public void nothingToOverride(@NotNull CallableMemberDescriptor overriding) {
throw new IllegalStateException("Component functions are OK to override nothing" );
}
});
}
@NotNull
private static PsiElement findDataModifierForDataClass(@NotNull DeclarationDescriptor dataClass) {
KtClass classDeclaration = (KtClass) DescriptorToSourceUtils.getSourceFromDescriptor(dataClass);
if (classDeclaration != null && classDeclaration.getModifierList() != null ) {
PsiElement modifier = classDeclaration.getModifierList().getModifier(KtTokens.DATA_KEYWORD);
if (modifier != null ) {
return modifier;
}
}
throw new IllegalStateException("No data modifier is found for data class " + dataClass);
}
@Nullable
private static CallableMemberDescriptor findInvisibleOverriddenDescriptor(
@NotNull CallableMemberDescriptor declared,
@NotNull ClassDescriptor declaringClass
) {
for (KotlinType supertype : declaringClass.getTypeConstructor().getSupertypes()) {
Set all = Sets.newLinkedHashSet();
all.addAll(supertype.getMemberScope().getContributedFunctions(declared.getName(), NoLookupLocation.WHEN_CHECK_OVERRIDES));
all.addAll((Collection) supertype.getMemberScope().getContributedVariables(declared.getName(), NoLookupLocation.WHEN_CHECK_OVERRIDES));
for (CallableMemberDescriptor fromSuper : all) {
if (OverridingUtil.DEFAULT.isOverridableBy(fromSuper, declared, null ).getResult() == OVERRIDABLE) {
if (Visibilities.isVisibleIgnoringReceiver(fromSuper, declared)) {
throw new IllegalStateException("Descriptor " + fromSuper + " is overridable by " + declared +
" and visible but does not appear in its getOverriddenDescriptors()" );
}
return fromSuper;
}
}
}
return null ;
}
private void checkParameterOverridesForAllClasses(@NotNull TopDownAnalysisContext c) {
for (ClassDescriptorWithResolutionScopes classDescriptor : c.getDeclaredClasses().values()) {
for (DeclarationDescriptor member : DescriptorUtils.getAllDescriptors(classDescriptor.getDefaultType().getMemberScope())) {
if (member instanceof CallableMemberDescriptor) {
checkOverridesForParameters((CallableMemberDescriptor) member);
}
}
}
}
private void checkOverridesForParameters(@NotNull CallableMemberDescriptor declared) {
boolean isDeclaration = declared.getKind() == CallableMemberDescriptor.Kind.DECLARATION;
if (isDeclaration) {
KtModifierListOwner declaration = (KtModifierListOwner) DescriptorToSourceUtils.descriptorToDeclaration(declared);
if (declaration != null && !declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
return ;
}
}
for (ValueParameterDescriptor parameterFromSubclass : declared.getValueParameters()) {
int defaultsInSuper = 0 ;
for (ValueParameterDescriptor parameterFromSuperclass : parameterFromSubclass.getOverriddenDescriptors()) {
if (parameterFromSuperclass.declaresDefaultValue()) {
defaultsInSuper++;
}
}
boolean multipleDefaultsInSuper = defaultsInSuper > 1 ;
if (isDeclaration) {
checkNameAndDefaultForDeclaredParameter(parameterFromSubclass, multipleDefaultsInSuper);
}
else {
checkNameAndDefaultForFakeOverrideParameter(declared, parameterFromSubclass, multipleDefaultsInSuper);
}
}
}
private void checkNameAndDefaultForDeclaredParameter(@NotNull ValueParameterDescriptor descriptor, boolean multipleDefaultsInSuper) {
KtParameter parameter = (KtParameter) DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
assert parameter != null : "Declaration not found for parameter: " + descriptor;
if (descriptor.declaresDefaultValue()) {
trace.report(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE.on(parameter));
}
if (multipleDefaultsInSuper) {
trace.report(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES.on(parameter, descriptor));
}
for (ValueParameterDescriptor parameterFromSuperclass : descriptor.getOverriddenDescriptors()) {
if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) {
trace.report(PARAMETER_NAME_CHANGED_ON_OVERRIDE.on(
parameter,
(ClassDescriptor) parameterFromSuperclass.getContainingDeclaration().getContainingDeclaration(),
parameterFromSuperclass)
);
}
}
}
private void checkNameAndDefaultForFakeOverrideParameter(
@NotNull CallableMemberDescriptor containingFunction,
@NotNull ValueParameterDescriptor descriptor,
boolean multipleDefaultsInSuper
) {
DeclarationDescriptor containingClass = containingFunction.getContainingDeclaration();
KtClassOrObject classElement = (KtClassOrObject) DescriptorToSourceUtils.descriptorToDeclaration(containingClass);
assert classElement != null : "Declaration not found for class: " + containingClass;
if (multipleDefaultsInSuper) {
trace.report(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE.on(classElement, descriptor));
}
for (ValueParameterDescriptor parameterFromSuperclass : descriptor.getOverriddenDescriptors()) {
if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) {
trace.report(DIFFERENT_NAMES_FOR_THE_SAME_PARAMETER_IN_SUPERTYPES.on(
classElement,
containingFunction.getOverriddenDescriptors(),
parameterFromSuperclass.getIndex() + 1 )
);
}
}
}
public static boolean shouldReportParameterNameOverrideWarning(
@NotNull ValueParameterDescriptor parameterFromSubclass,
@NotNull ValueParameterDescriptor parameterFromSuperclass
) {
return parameterFromSubclass.getContainingDeclaration().hasStableParameterNames() &&
parameterFromSuperclass.getContainingDeclaration().hasStableParameterNames() &&
!parameterFromSuperclass.getName().equals(parameterFromSubclass.getName());
}
private static boolean checkPropertyKind(@NotNull CallableMemberDescriptor descriptor, boolean isVar) {
return descriptor instanceof PropertyDescriptor && ((PropertyDescriptor) descriptor).isVar() == isVar;
}
private void checkVisibility(@NotNull TopDownAnalysisContext c) {
for (Map.Entry entry : c.getMembers().entrySet()) {
checkVisibilityForMember(entry.getKey(), entry.getValue());
if (entry.getKey() instanceof KtProperty && entry.getValue() instanceof PropertyDescriptor) {
KtPropertyAccessor setter = ((KtProperty) entry.getKey()).getSetter();
PropertySetterDescriptor setterDescriptor = ((PropertyDescriptor) entry.getValue()).getSetter();
if (setter != null && setterDescriptor != null ) {
checkVisibilityForMember(setter, setterDescriptor);
}
}
}
}
private void checkVisibilityForMember(@NotNull KtDeclaration declaration, @NotNull CallableMemberDescriptor memberDescriptor) {
Visibility visibility = memberDescriptor.getVisibility();
for (CallableMemberDescriptor descriptor : memberDescriptor.getOverriddenDescriptors()) {
Integer compare = Visibilities.compare(visibility, descriptor.getVisibility());
if (compare == null ) {
trace.report(CANNOT_CHANGE_ACCESS_PRIVILEGE.on(declaration, descriptor.getVisibility(), descriptor, descriptor.getContainingDeclaration()));
return ;
}
else if (compare < 0 ) {
trace.report(CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(declaration, descriptor.getVisibility(), descriptor, descriptor.getContainingDeclaration()));
return ;
}
}
}
@NotNull
public static Collection getDirectlyOverriddenDeclarations(@NotNull D descriptor) {
Set result = new LinkedHashSet();
for (D overriddenDescriptor : (Collection) descriptor.getOverriddenDescriptors()) {
CallableMemberDescriptor.Kind kind = overriddenDescriptor.getKind();
if (kind == DECLARATION) {
result.add(overriddenDescriptor);
}
else if (kind == FAKE_OVERRIDE || kind == DELEGATION) {
result.addAll(getDirectlyOverriddenDeclarations(overriddenDescriptor));
}
else if (kind == SYNTHESIZED) {
}
else {
throw new AssertionError("Unexpected callable kind " + kind);
}
}
return filterOutOverridden(result);
}
@NotNull
@ReadOnly
public static Set getDeepestSuperDeclarations(@NotNull D functionDescriptor) {
Set overriddenDeclarations = DescriptorUtils.getAllOverriddenDeclarations(functionDescriptor);
if (overriddenDeclarations.isEmpty()) {
return Collections.singleton(functionDescriptor);
}
return filterOutOverriding(overriddenDeclarations);
}
}