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.
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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.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.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.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.kotlin.utils.HashSetUtil;
import java.util.*;
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 OverridingUtil.DescriptorSink sink
) {
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, sink);
}
}
public static void resolveUnknownVisibilities(
@NotNull Collection extends CallableMemberDescriptor> 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;
}
//noinspection ConstantConditions
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) {
//noinspection unchecked
return filterOverrides(candidateSet, Function.ID, Filtering.RETAIN_OVERRIDING);
}
@NotNull
public static Set filterOutOverriding(@NotNull Set candidateSet) {
//noinspection unchecked
return filterOverrides(candidateSet, Function.ID, Filtering.RETAIN_OVERRIDDEN);
}
@NotNull
public static Set filterOutOverridden(
@NotNull Set candidateSet,
@NotNull Function super D, ? extends CallableDescriptor> transform
) {
return filterOverrides(candidateSet, transform, Filtering.RETAIN_OVERRIDING);
}
@NotNull
private static Set filterOverrides(
@NotNull Set candidateSet,
@NotNull final Function super D, ? extends CallableDescriptor> transform,
@NotNull Filtering filtering
) {
if (candidateSet.size() <= 1) return candidateSet;
// In a multi-module project different "copies" of the same class may be present in different libraries,
// that's why we use structural equivalence for members (DescriptorEquivalenceForOverrides).
// Here we filter out structurally equivalent descriptors before processing overrides, because such descriptors
// "override" each other (overrides(f, g) = overrides(g, f) = true) and the code below removes them all from the
// candidates, unless we first compute noDuplicates
Set noDuplicates = HashSetUtil.linkedHashSet(
candidateSet,
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);
CallableDescriptor g = transform.fun(d2);
return DescriptorEquivalenceForOverrides.INSTANCE$.areEquivalent(f.getOriginal(), g.getOriginal());
}
});
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).getResult() == OVERRIDABLE
&& OverridingUtil.DEFAULT.isOverridableBy(me, other).getResult() == OVERRIDABLE) {
continue outerLoop;
}
}
candidates.add(meD);
}
assert !candidates.isEmpty() : "All candidates filtered out from " + candidateSet;
return candidates;
}
// check whether f overrides g
public static boolean overrides(@NotNull D f, @NotNull D g) {
// This first check cover the case of duplicate classes in different modules:
// when B is defined in modules m1 and m2, and C (indirectly) inherits from both versions,
// we'll be getting sets of members that do not override each other, but are structurally equivalent.
// As other code relies on no equal descriptors passed here, we guard against f == g, but this may not be necessary
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 : type.getMemberScope().getAllDescriptors()) {
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 KtClassOrObject klass) {
// Check overrides for internal consistency
for (CallableMemberDescriptor member : classDescriptor.getDeclaredCallableMembers()) {
checkOverrideForMember(member);
}
// Check if everything that must be overridden, actually is
// More than one implementation or no implementations at all
Set abstractNoImpl = Sets.newLinkedHashSet();
Set manyImpl = Sets.newLinkedHashSet();
Set abstractInBaseClassNoImpl = Sets.newLinkedHashSet();
Set conflictingInterfaceOverrides = Sets.newLinkedHashSet();
collectMissingImplementations(classDescriptor,
abstractNoImpl, manyImpl,
abstractInBaseClassNoImpl, conflictingInterfaceOverrides);
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()));
}
}
if (!conflictingInterfaceOverrides.isEmpty()) {
trace.report(MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.on(klass, klass, conflictingInterfaceOverrides.iterator().next()));
}
else if (!manyImpl.isEmpty()) {
trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(klass, klass, manyImpl.iterator().next()));
}
}
@NotNull
public static Set getMissingImplementations(@NotNull ClassDescriptor classDescriptor) {
Set shouldImplement = new LinkedHashSet();
Set dontCare = new HashSet();
collectMissingImplementations(classDescriptor, shouldImplement, shouldImplement, dontCare, dontCare);
return shouldImplement;
}
private static void collectMissingImplementations(
@NotNull ClassDescriptor classDescriptor,
@NotNull Set abstractNoImpl,
@NotNull Set manyImpl,
@NotNull Set abstractInBaseClassNoImpl,
@NotNull Set conflictingInterfaceOverrides
) {
for (DeclarationDescriptor member : classDescriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
if (member instanceof CallableMemberDescriptor) {
collectMissingImplementations((CallableMemberDescriptor) member,
abstractNoImpl, manyImpl,
abstractInBaseClassNoImpl, conflictingInterfaceOverrides);
}
}
}
private static void collectMissingImplementations(
@NotNull CallableMemberDescriptor descriptor,
@NotNull Set abstractNoImpl,
@NotNull Set manyImpl,
@NotNull Set abstractInBaseClassNoImpl,
@NotNull Set conflictingInterfaceOverrides
) {
if (descriptor.getKind().isReal()) return;
if (descriptor.getVisibility() == Visibilities.INVISIBLE_FAKE) return;
Collection extends CallableMemberDescriptor> directOverridden = descriptor.getOverriddenDescriptors();
if (directOverridden.size() == 0) {
throw new IllegalStateException("A 'fake override' " + descriptor.getName().asString() + " must override something");
}
// collects map from the directly overridden descriptor to the set of declarations:
// -- if directly overridden is not fake, the set consists of one element: this directly overridden
// -- if it's fake, overridden declarations (non-fake) of this descriptor are collected
Map> overriddenDeclarationsByDirectParent = collectOverriddenDeclarations(directOverridden);
List allOverriddenDeclarations = ContainerUtil.flatten(overriddenDeclarationsByDirectParent.values());
Set allFilteredOverriddenDeclarations = filterOutOverridden(
Sets.newLinkedHashSet(allOverriddenDeclarations));
Set relevantDirectlyOverridden =
getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations);
collectJava8MissingOverrides(relevantDirectlyOverridden, abstractInBaseClassNoImpl, conflictingInterfaceOverrides);
List implementations = collectImplementations(relevantDirectlyOverridden);
if (implementations.size() == 1 && isReturnTypeOkForOverride(descriptor, implementations.get(0))) return;
List abstractOverridden = new ArrayList(allFilteredOverriddenDeclarations.size());
List concreteOverridden = new ArrayList(allFilteredOverriddenDeclarations.size());
filterNotSynthesizedDescriptorsByModality(allFilteredOverriddenDeclarations, abstractOverridden, concreteOverridden);
if (implementations.isEmpty()) {
abstractNoImpl.addAll(abstractOverridden);
}
else if (implementations.size() > 1) {
manyImpl.addAll(concreteOverridden);
}
else {
abstractNoImpl.addAll(collectAbstractMethodsWithMoreSpecificReturnType(abstractOverridden, implementations.get(0)));
}
}
private static void collectJava8MissingOverrides(
Set relevantDirectlyOverridden,
@NotNull Set abstractInBaseClassNoImpl,
@NotNull Set conflictingInterfaceOverrides
) {
// Java 8:
// -- class should implement an abstract member of a super-class,
// even if relevant default implementation is provided in one of the super-interfaces;
// -- inheriting multiple override equivalent methods from an interface is a conflict
// regardless of 'default' vs 'abstract'.
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) {
abstractInBaseClassNoImpl.add(overridesAbstractInBaseClass);
}
if (!overridesClassMember && overridesNonAbstractInterfaceMember && overriddenInterfaceMembers.size() > 1) {
conflictingInterfaceOverrides.addAll(overriddenInterfaceMembers);
}
}
@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
) {
/* Let the following class hierarchy is declared:
trait A { fun foo() = 1 }
trait B : A
trait C : A
trait D : A { override fun foo() = 2 }
trait E : B, C, D {}
Traits B and C have fake descriptors for function foo.
The map 'overriddenByParent' is:
{ 'foo in B' (fake) -> { 'foo in A' }, 'foo in C' (fake) -> { 'foo in A' }, 'foo in D' -> { 'foo in D'} }
This is a map from directly overridden descriptors (functions 'foo' in B, C, D in this example) to the set of declarations (non-fake),
that are overridden by this descriptor.
The goal is to leave only relevant directly overridden descriptors to count implementations of our fake function on them.
In the example above there is no error (trait E inherits only one implementation of 'foo' (from D), because this implementation is more precise).
So only 'foo in D' is relevant.
Directly overridden descriptor is not relevant if it doesn't add any more appropriate non-fake declarations of the concerned function.
More precisely directly overridden descriptor is not relevant if:
- it's declaration set is a subset of declaration set for other directly overridden descriptor
('foo in B' is not relevant because it's declaration set is a subset of 'foo in C' function's declaration set)
- each member of it's declaration set is overridden by a member of other declaration set
('foo in C' is not relevant, because 'foo in A' is overridden by 'foo in D', so 'foo in A' is not appropriate non-fake declaration for 'foo')
For the last condition allFilteredOverriddenDeclarations helps (for the example above it's { 'foo in A' } only): each declaration set
is compared with allFilteredOverriddenDeclarations, if they have no intersection, this means declaration set has only functions that
are overridden by some other function and corresponding directly overridden descriptor is not relevant.
*/
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 extends CallableMemberDescriptor> 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;
}
/**
* @return overridden real descriptors (not fake overrides). Note that all usages of this method should be followed by calling
* {@link #filterOutOverridden(java.util.Set)} or {@link #filterOutOverriding(java.util.Set)}, because some of the declarations
* can override the other
* TODO: merge this method with filterOutOverridden
*/
@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 overridden);
void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden);
void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden);
void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden);
void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden);
void nothingToOverride();
}
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 extends CallableMemberDescriptor> 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 overridden) {
if (!finalOverriddenError) {
finalOverriddenError = true;
trace.report(OVERRIDING_FINAL_MEMBER.on(member, overridden, overridden.getContainingDeclaration()));
}
}
@Override
public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) {
if (!typeMismatchError) {
typeMismatchError = true;
trace.report(RETURN_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden));
}
}
@Override
public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) {
if (!typeMismatchError) {
typeMismatchError = true;
trace.report(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden));
}
}
@Override
public void varOverriddenByVal(@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 invisibleOverridden) {
trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, invisibleOverridden));
}
@Override
public void nothingToOverride() {
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 checkOverridesForMemberMarkedOverride(
@NotNull CallableMemberDescriptor declared,
boolean checkIfOverridesNothing,
@NotNull CheckOverrideReportStrategy reportError
) {
Collection extends CallableMemberDescriptor> overriddenDescriptors = declared.getOverriddenDescriptors();
for (CallableMemberDescriptor overridden : overriddenDescriptors) {
if (overridden == null) continue;
if (!overridden.getModality().isOverridable()) {
reportError.overridingFinalMember(overridden);
}
if (declared instanceof PropertyDescriptor &&
!isPropertyTypeOkForOverride((PropertyDescriptor) overridden, (PropertyDescriptor) declared)) {
reportError.propertyTypeMismatchOnOverride(overridden);
}
else if (!isReturnTypeOkForOverride(overridden, declared)) {
reportError.returnTypeMismatchOnOverride(overridden);
}
if (checkPropertyKind(overridden, true) && checkPropertyKind(declared, false)) {
reportError.varOverriddenByVal(overridden);
}
}
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(invisibleOverriddenDescriptor);
}
else {
reportError.nothingToOverride();
}
}
}
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;
if (!superDescriptor.isVar()) return true;
KotlinType substitutedSuperReturnType = typeSubstitutor.substitute(superDescriptor.getType(), Variance.OUT_VARIANCE);
assert substitutedSuperReturnType != null;
return KotlinTypeChecker.DEFAULT.equalTypes(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 overridden) {
if (!overrideConflict) {
overrideConflict = true;
trace.report(DATA_CLASS_OVERRIDE_CONFLICT.on(dataModifier, componentFunction, overridden.getContainingDeclaration()));
}
}
@Override
public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) {
if (!overrideConflict) {
overrideConflict = true;
trace.report(DATA_CLASS_OVERRIDE_CONFLICT.on(dataModifier, componentFunction, overridden.getContainingDeclaration()));
}
}
@Override
public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) {
throw new IllegalStateException("Component functions are not properties");
}
@Override
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) {
throw new IllegalStateException("Component functions are not properties");
}
@Override
public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden) {
throw new IllegalStateException("CANNOT_OVERRIDE_INVISIBLE_MEMBER should be reported on the corresponding property");
}
@Override
public void nothingToOverride() {
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().getFunctions(declared.getName(), NoLookupLocation.UNSORTED));
//noinspection unchecked
all.addAll((Collection) supertype.getMemberScope().getProperties(declared.getName(), NoLookupLocation.UNSORTED));
for (CallableMemberDescriptor fromSuper : all) {
if (OverridingUtil.DEFAULT.isOverridableBy(fromSuper, declared).getResult() == OVERRIDABLE) {
if (Visibilities.isVisible(ReceiverValue.IRRELEVANT_RECEIVER, 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 : classDescriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
if (member instanceof CallableMemberDescriptor) {
checkOverridesForParameters((CallableMemberDescriptor) member);
}
}
}
}
private void checkOverridesForParameters(@NotNull CallableMemberDescriptor declared) {
boolean isDeclaration = declared.getKind() == CallableMemberDescriptor.Kind.DECLARATION;
if (isDeclaration) {
// No check if the function is not marked as 'override'
KtModifierListOwner declaration = (KtModifierListOwner) DescriptorToSourceUtils.descriptorToDeclaration(declared);
if (declaration != null && !declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
return;
}
}
// Let p1 be a parameter of the overriding function
// Let p2 be a parameter of the function being overridden
// Then
// a) p1 is not allowed to have a default value declared
// b) p1 must have the same name as p2
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)) {
//noinspection ConstantConditions
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());
}
}
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();
//noinspection unchecked
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) {
//do nothing
}
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);
}
}