FIR: use Java 8 rules in not implemented checker

This commit is contained in:
Mikhail Glukhikh
2021-04-06 09:47:02 +03:00
parent 5de8401494
commit 84ccf7bbb1
19 changed files with 171 additions and 53 deletions
@@ -2789,6 +2789,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
}
@TestMetadata("symbolsAndDescriptors.kt")
public void testSymbolsAndDescriptors() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
}
@TestMetadata("transform.kt")
public void testTransform() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/transform.kt");
@@ -0,0 +1,46 @@
FILE: symbolsAndDescriptors.kt
public final class IrClassSymbolImpl : R|IrBindableSymbolBase<kotlin/String>|, R|IrClassSymbol| {
public constructor(descriptor: R|kotlin/String?| = Null(null)): R|IrClassSymbolImpl| {
super<R|IrBindableSymbolBase<kotlin/String>|>(R|<local>/descriptor|)
}
}
public abstract interface IrClassSymbol : R|IrClassifierSymbol|, R|IrBindableSymbol<kotlin/String>| {
}
public abstract interface IrClassifierSymbol : R|IrSymbol|, R|TypeConstructorMarker| {
public abstract override val descriptor: R|kotlin/CharSequence|
public get(): R|kotlin/CharSequence|
}
public abstract interface IrSymbol : R|kotlin/Any| {
public abstract val descriptor: R|kotlin/Any|
public get(): R|kotlin/Any|
}
public abstract interface TypeConstructorMarker : R|kotlin/Any| {
}
public abstract interface IrBindableSymbol<out D : R|kotlin/Any|> : R|IrSymbol| {
public abstract override val descriptor: R|D|
public get(): R|D|
}
public abstract class IrBindableSymbolBase<out D : R|kotlin/Any|> : R|IrBindableSymbol<D>|, R|IrSymbolBase<D>| {
public constructor<out D : R|kotlin/Any|>(descriptor: R|D?|): R|IrBindableSymbolBase<D>| {
super<R|IrSymbolBase<D>|>(R|<local>/descriptor|)
}
}
public abstract class IrSymbolBase<out D : R|kotlin/Any|> : R|IrSymbol| {
public constructor<out D : R|kotlin/Any|>(_descriptor: R|D?|): R|IrSymbolBase<D>| {
super<R|kotlin/Any|>()
}
private final val _descriptor: R|D?| = R|<local>/_descriptor|
private get(): R|D?|
public open override val descriptor: R|D|
public get(): R|D| {
^ this@R|/IrSymbolBase|.R|/IrSymbolBase._descriptor|!!
}
}
@@ -0,0 +1,33 @@
class IrClassSymbolImpl(descriptor: String? = null) :
IrBindableSymbolBase<String>(descriptor),
IrClassSymbol
interface IrClassSymbol : IrClassifierSymbol, IrBindableSymbol<String>
interface IrClassifierSymbol : IrSymbol, TypeConstructorMarker {
override val descriptor: CharSequence
}
interface IrSymbol {
val descriptor: Any
}
interface TypeConstructorMarker
interface IrBindableSymbol<out D : Any> : IrSymbol {
override val descriptor: D
}
abstract class IrBindableSymbolBase<out D : Any>(descriptor: D?) :
IrBindableSymbol<D>, IrSymbolBase<D>(descriptor)
abstract class IrSymbolBase<out D : Any>(
private val _descriptor: D?
) : IrSymbol {
override val descriptor: D
get() = _descriptor!!
}
@@ -3159,6 +3159,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
}
@Test
@TestMetadata("symbolsAndDescriptors.kt")
public void testSymbolsAndDescriptors() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
}
@Test
@TestMetadata("transform.kt")
public void testTransform() throws Exception {
@@ -3159,6 +3159,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
}
@Test
@TestMetadata("symbolsAndDescriptors.kt")
public void testSymbolsAndDescriptors() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
}
@Test
@TestMetadata("transform.kt")
public void testTransform() throws Exception {
@@ -63,11 +63,58 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
return false
}
fun FirIntersectionCallableSymbol.subjectToManyNotImplemented(): Boolean {
var nonAbstractCountInClass = 0
var nonAbstractCountInInterface = 0
var abstractCountInInterface = 0
for (intersectionSymbol in intersections) {
val intersection = intersectionSymbol.fir as FirCallableMemberDeclaration
val containingClass = intersection.getContainingClass(context) as? FirRegularClass
val hasInterfaceContainer = containingClass?.classKind == ClassKind.INTERFACE
if (intersection.modality != Modality.ABSTRACT) {
if (hasInterfaceContainer) {
nonAbstractCountInInterface++
} else {
nonAbstractCountInClass++
}
} else if (hasInterfaceContainer) {
abstractCountInInterface++
}
if (nonAbstractCountInClass + nonAbstractCountInInterface > 1) {
return true
}
if (nonAbstractCountInInterface > 0 && abstractCountInInterface > 0) {
return true
}
}
return false
}
fun FirIntersectionCallableSymbol.shouldBeImplemented(): Boolean {
// In Java 8, non-abstract intersection overrides having abstract symbol from base class
// still should be implemented in current class (even when they have default interface implementation)
if (intersections.none {
val fir = (it.fir as FirCallableMemberDeclaration).unwrapFakeOverrides()
fir.isAbstract && (fir.getContainingClass(context) as? FirRegularClass)?.classKind == ClassKind.CLASS
}
) return false
// Exception from the rule above: interface implementation via delegation
if (intersections.any {
val fir = (it.fir as FirCallableMemberDeclaration)
fir.origin == FirDeclarationOrigin.Delegated && !fir.isAbstract
}
) return false
return true
}
fun FirCallableMemberDeclaration<*>.shouldBeImplemented(): Boolean {
if (!isAbstract) return false
val containingClass = getContainingClass(context)
if (containingClass === declaration && origin == FirDeclarationOrigin.Source) return false
if (containingClass is FirRegularClass && containingClass.isExpect) return false
if (!isAbstract) {
val symbol = symbol as? FirIntersectionCallableSymbol ?: return false
return symbol.shouldBeImplemented()
}
if (containingClass === declaration && origin == FirDeclarationOrigin.Source) return false
return true
}
@@ -75,9 +122,8 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
classScope.processFunctionsByName(name) { namedFunctionSymbol ->
val simpleFunction = namedFunctionSymbol.fir
if (namedFunctionSymbol is FirIntersectionOverrideFunctionSymbol) {
if (namedFunctionSymbol.intersections.count {
(it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT
} > 1 && simpleFunction.getContainingClass(context) === declaration
if (simpleFunction.getContainingClass(context) === declaration &&
namedFunctionSymbol.subjectToManyNotImplemented()
) {
notImplementedIntersectionSymbols += namedFunctionSymbol
return@processFunctionsByName
@@ -99,9 +145,8 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
classScope.processPropertiesByName(name) { propertySymbol ->
val property = propertySymbol.fir as? FirProperty ?: return@processPropertiesByName
if (propertySymbol is FirIntersectionOverridePropertySymbol) {
if (propertySymbol.intersections.count {
(it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT
} > 1 && property.getContainingClass(context) === declaration
if (property.getContainingClass(context) === declaration &&
propertySymbol.subjectToManyNotImplemented()
) {
notImplementedIntersectionSymbols += propertySymbol
return@processPropertiesByName
@@ -1,3 +1,6 @@
// IGNORE_BACKEND_FIR: JVM_IR
// Note: this test will fail in Kotlin 1.6 (see AbstractClassMemberNotImplementedWithIntermediateAbstractClass feature)
interface A {
fun foo(): Any
}
@@ -1,3 +1,6 @@
// IGNORE_BACKEND_FIR: JVM_IR
// Note: this test will fail in Kotlin 1.6 (see AbstractClassMemberNotImplementedWithIntermediateAbstractClass feature)
// FILE: 1.kt
class Test: Impl(), CProvider
@@ -8,11 +8,11 @@ interface IRight {
fun foo() {}
}
class CDerived : ALeft(), IRight
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class CDerived<!> : ALeft(), IRight
abstract class CAbstract : ALeft(), IRight
class CDerivedFromAbstract : CAbstract()
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class CDerivedFromAbstract<!> : CAbstract()
interface ILeft {
fun foo()
@@ -21,10 +21,10 @@ interface ILeft {
abstract class AILeft : ILeft
// Should be ERROR
class AILeftImpl : AILeft(), IRight
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class AILeftImpl<!> : AILeft(), IRight
// Should be ERROR
class RightLeft : ILeft, IRight
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class RightLeft<!> : ILeft, IRight
interface IBase {
fun foo()
@@ -8,11 +8,11 @@ interface IRight {
fun foo() {}
}
class CDerived : ALeft(), IRight
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class CDerived<!> : ALeft(), IRight
abstract class CAbstract : ALeft(), IRight
class CDerivedFromAbstract : CAbstract()
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class CDerivedFromAbstract<!> : CAbstract()
interface ILeft {
fun foo()
@@ -21,10 +21,10 @@ interface ILeft {
abstract class AILeft : ILeft
// Should be ERROR
class AILeftImpl : AILeft(), IRight
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class AILeftImpl<!> : AILeft(), IRight
// Should be ERROR
class RightLeft : ILeft, IRight
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class RightLeft<!> : ILeft, IRight
interface IBase {
fun foo()
@@ -8,6 +8,6 @@ interface IRight {
interface IDerived : ILeft, IRight
class CDerived : ILeft, IRight
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class CDerived<!> : ILeft, IRight
abstract class ADerived : ILeft, IRight
@@ -8,11 +8,11 @@ interface B {
open class D: B
open class C: D(), A
open <!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class C<!>: D(), A
// ------------
class Test: Impl(), CProvider
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class Test<!>: Impl(), CProvider
open class CC
@@ -1,18 +0,0 @@
interface A {
fun foo() {}
}
interface B : A {
abstract override fun foo()
}
interface C : A {
abstract override fun foo()
}
interface D : A {
override fun foo() = super.foo()
}
// Fake override Z#foo should be open
class Z : B, C, D
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
interface A {
fun foo() {}
}
@@ -1,13 +0,0 @@
// FILE: JavaInterface.java
interface JavaInterface {
void foo(int javaName);
}
// FILE: kotlin.kt
interface KotlinTrait {
public fun foo(someOtherName: Int) {}
}
class BothTraitsSubclass : JavaInterface, KotlinTrait
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: JavaInterface.java
interface JavaInterface {
@@ -25,7 +25,7 @@ class D : B, A {
}
}
class E: B, A {
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class E<!>: B, A {
fun foo() {
super<B>.test()
}
@@ -24,7 +24,7 @@ class D : B, A {
}
}
class E: B, A {
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class E<!>: B, A {
fun foo() {
super<A>.test()
}
@@ -4,7 +4,7 @@
// FULL_JDK
// TESTCASE NUMBER: 1
class Case1() : BaseCase1(), InterfaceCase1 {}
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class Case1<!>() : BaseCase1(), InterfaceCase1 {}
abstract class BaseCase1() {
abstract fun foo(): String