Don't allow fake override to inherit implementation with wrong return type

#KT-4763 Fixed
This commit is contained in:
Alexander Udalov
2014-03-28 23:09:52 +04:00
parent 05a04293ab
commit 9760f30c99
10 changed files with 128 additions and 18 deletions
@@ -379,40 +379,68 @@ public class OverrideResolver {
Set<CallableMemberDescriptor> relevantDirectlyOverridden =
getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations);
int implCount = countImplementations(relevantDirectlyOverridden);
if (implCount == 0) {
collectNotSynthesizedDescriptorsByModality(allFilteredOverriddenDeclarations, abstractNoImpl, Modality.ABSTRACT);
List<CallableMemberDescriptor> implementations = collectImplementations(relevantDirectlyOverridden);
if (implementations.size() == 1 && isReturnTypeOkForOverride(descriptor, implementations.get(0))) return;
List<CallableMemberDescriptor> abstractOverridden = new ArrayList<CallableMemberDescriptor>(allFilteredOverriddenDeclarations.size());
List<CallableMemberDescriptor> concreteOverridden = new ArrayList<CallableMemberDescriptor>(allFilteredOverriddenDeclarations.size());
filterNotSynthesizedDescriptorsByModality(allFilteredOverriddenDeclarations, abstractOverridden, concreteOverridden);
if (implementations.isEmpty()) {
abstractNoImpl.addAll(abstractOverridden);
}
else if (implCount > 1) {
collectNotSynthesizedDescriptorsByModality(allFilteredOverriddenDeclarations, manyImpl, Modality.OPEN, Modality.FINAL);
else if (implementations.size() > 1) {
manyImpl.addAll(concreteOverridden);
}
else {
abstractNoImpl.addAll(collectAbstractMethodsWithMoreSpecificReturnType(abstractOverridden, implementations.get(0)));
}
}
private static int countImplementations(@NotNull Set<CallableMemberDescriptor> relevantDirectlyOverridden) {
int implCount = 0;
@NotNull
private static List<CallableMemberDescriptor> collectImplementations(@NotNull Set<CallableMemberDescriptor> relevantDirectlyOverridden) {
List<CallableMemberDescriptor> result = new ArrayList<CallableMemberDescriptor>(relevantDirectlyOverridden.size());
for (CallableMemberDescriptor overriddenDescriptor : relevantDirectlyOverridden) {
if (overriddenDescriptor.getModality() != Modality.ABSTRACT) {
implCount++;
result.add(overriddenDescriptor);
}
}
return implCount;
return result;
}
private static void collectNotSynthesizedDescriptorsByModality(
private static void filterNotSynthesizedDescriptorsByModality(
@NotNull Set<CallableMemberDescriptor> allOverriddenDeclarations,
@NotNull Set<CallableMemberDescriptor> result,
Modality... modalities
@NotNull List<CallableMemberDescriptor> abstractOverridden,
@NotNull List<CallableMemberDescriptor> concreteOverridden
) {
Set<Modality> modalitySet = Sets.newHashSet(modalities);
for (CallableMemberDescriptor overridden : allOverriddenDeclarations) {
if (modalitySet.contains(overridden.getModality())) {
if (!CallResolverUtil.isOrOverridesSynthesized(overridden)) {
result.add(overridden);
if (!CallResolverUtil.isOrOverridesSynthesized(overridden)) {
if (overridden.getModality() == Modality.ABSTRACT) {
abstractOverridden.add(overridden);
}
else {
concreteOverridden.add(overridden);
}
}
}
}
@NotNull
private static List<CallableMemberDescriptor> collectAbstractMethodsWithMoreSpecificReturnType(
@NotNull List<CallableMemberDescriptor> abstractOverridden,
@NotNull CallableMemberDescriptor implementation
) {
List<CallableMemberDescriptor> result = new ArrayList<CallableMemberDescriptor>(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<CallableMemberDescriptor> getRelevantDirectlyOverridden(
@NotNull Map<CallableMemberDescriptor, Set<CallableMemberDescriptor>> overriddenByParent,
@@ -1,7 +1,7 @@
class B () {}
open class A(val b : B) {
fun a() = object: A(b) {}
fun a(): A = object: A(b) {}
}
fun box() : String {
@@ -1,5 +1,5 @@
trait A {
fun foo(): Object
fun foo(): Any
}
open class B {
@@ -0,0 +1,11 @@
trait A {
fun f(): String = "string"
}
open class B {
open fun f(): CharSequence = "charSequence"
}
class <!MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>C<!> : B(), A
val obj: A = <!MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>object<!> : B(), A {}
@@ -0,0 +1,11 @@
trait A {
fun f(): String
}
open class B {
open fun f(): CharSequence = "charSequence"
}
class <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>C<!> : B(), A
val d: A = <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object<!> : B(), A {}
@@ -0,0 +1,11 @@
trait P {
var f: Number
}
open class Q {
val x: Int = 42
}
class <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>R<!> : P, Q()
val s: Q = <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object<!> : Q(), P {}
@@ -5307,6 +5307,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest("compiler/testData/diagnostics/tests/override/FakeOverrideAbstractAndNonAbstractFun.kt");
}
@TestMetadata("FakeOverrideDifferentDeclarationSignatures.kt")
public void testFakeOverrideDifferentDeclarationSignatures() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.kt");
}
@TestMetadata("Generics.kt")
public void testGenerics() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/Generics.kt");
@@ -5327,6 +5332,16 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest("compiler/testData/diagnostics/tests/override/kt2052.kt");
}
@TestMetadata("kt4763.kt")
public void testKt4763() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/kt4763.kt");
}
@TestMetadata("kt4763property.kt")
public void testKt4763property() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/kt4763property.kt");
}
@TestMetadata("kt4785.kt")
public void testKt4785() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/kt4785.kt");
@@ -0,0 +1,27 @@
// !DIAGNOSTICS_NUMBER: 1
// !DIAGNOSTICS: ABSTRACT_MEMBER_NOT_IMPLEMENTED
// !MESSAGE_TYPE: TEXT
trait T1
trait T2 : T1
trait T3 : T2
trait T4 : T3
trait A {
fun f(): T1
}
trait B {
fun f(): T2 = null!!
}
trait C {
fun f(): T3
}
abstract class D {
abstract fun f(): T4
}
class E : A, B, C, D()
@@ -0,0 +1,2 @@
<!-- wrongReturnTypeInImplementation1 -->
Class 'E' must be declared abstract or implement abstract member internal abstract fun f(): T3 defined in C
@@ -146,4 +146,9 @@ public class DiagnosticMessageTestGenerated extends AbstractDiagnosticMessageTes
doTest("idea/testData/diagnosticMessage/upperBoundViolated.kt");
}
@TestMetadata("wrongReturnTypeInImplementation.kt")
public void testWrongReturnTypeInImplementation() throws Exception {
doTest("idea/testData/diagnosticMessage/wrongReturnTypeInImplementation.kt");
}
}