FirNotImplementedOverrideChecker: check also anonymous objects / enums
This commit is contained in:
+2
-2
@@ -26,11 +26,11 @@ enum class EnumClass {
|
||||
override val bar: String = "a"
|
||||
},
|
||||
|
||||
E2 {
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>E2<!> {
|
||||
|
||||
},
|
||||
|
||||
E3();
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>E3<!>();
|
||||
|
||||
abstract fun foo(): Int
|
||||
abstract val bar: String
|
||||
|
||||
+9
-10
@@ -28,16 +28,13 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
|
||||
override fun check(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
// TODO: kt4763Property: reporting on `object` literal causes invalid error in test...FirDiagnosticHandler
|
||||
if (declaration !is FirRegularClass) return
|
||||
|
||||
val source = declaration.source ?: return
|
||||
if (source.kind is FirFakeSourceElementKind) return
|
||||
val sourceKind = source.kind
|
||||
if (sourceKind is FirFakeSourceElementKind && sourceKind != FirFakeSourceElementKind.EnumInitializer) return
|
||||
val modality = declaration.modality()
|
||||
if (modality == Modality.ABSTRACT || modality == Modality.SEALED) return
|
||||
if (declaration.isExpect) return
|
||||
if (declaration is FirRegularClass && declaration.isExpect) return
|
||||
val classKind = declaration.classKind
|
||||
// TODO: we should check enum entries (probably as anonymous objects, see above)
|
||||
if (classKind == ClassKind.ANNOTATION_CLASS || classKind == ClassKind.ENUM_CLASS) return
|
||||
|
||||
val classScope = declaration.unsubstitutedScope(
|
||||
@@ -70,7 +67,9 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
classScope.processFunctionsByName(name) { namedFunctionSymbol ->
|
||||
val simpleFunction = namedFunctionSymbol.fir
|
||||
if (!simpleFunction.shouldBeImplemented()) return@processFunctionsByName
|
||||
if (declaration.isData && simpleFunction.matchesDataClassSyntheticMemberSignatures) return@processFunctionsByName
|
||||
if (declaration is FirRegularClass && declaration.isData && simpleFunction.matchesDataClassSyntheticMemberSignatures) {
|
||||
return@processFunctionsByName
|
||||
}
|
||||
|
||||
// TODO: suspend function overridden by a Java class in the middle is not properly regarded as an override
|
||||
if (simpleFunction.isSuspend) return@processFunctionsByName
|
||||
@@ -94,7 +93,7 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
|
||||
if (notImplementedSymbols.isNotEmpty()) {
|
||||
val notImplemented = notImplementedSymbols.first().fir
|
||||
if (notImplemented.isFromInterface(context)) {
|
||||
if (notImplemented.isFromInterfaceOrEnum(context)) {
|
||||
reporter.reportOn(source, FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)
|
||||
} else {
|
||||
reporter.reportOn(source, FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)
|
||||
@@ -110,8 +109,8 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirCallableDeclaration<*>.isFromInterface(context: CheckerContext): Boolean =
|
||||
(getContainingClass(context) as? FirRegularClass)?.isInterface == true
|
||||
private fun FirCallableDeclaration<*>.isFromInterfaceOrEnum(context: CheckerContext): Boolean =
|
||||
(getContainingClass(context) as? FirRegularClass)?.let { it.isInterface || it.isEnumClass } == true
|
||||
|
||||
private val FirSimpleFunction.matchesDataClassSyntheticMemberSignatures: Boolean
|
||||
get() = (this.name == OperatorNameConventions.EQUALS && matchesEqualsSignature) ||
|
||||
|
||||
+4
-3
@@ -532,7 +532,8 @@ class DeclarationsConverter(
|
||||
fun convertObjectLiteral(objectLiteral: LighterASTNode): FirElement {
|
||||
return withChildClassName(ANONYMOUS_OBJECT_NAME) {
|
||||
buildAnonymousObject {
|
||||
source = objectLiteral.toFirSourceElement()
|
||||
val objectDeclaration = objectLiteral.getChildNodesByType(OBJECT_DECLARATION).first()
|
||||
source = objectDeclaration.toFirSourceElement()
|
||||
origin = FirDeclarationOrigin.Source
|
||||
session = baseSession
|
||||
classKind = ClassKind.OBJECT
|
||||
@@ -551,7 +552,7 @@ class DeclarationsConverter(
|
||||
var delegatedConstructorSource: FirLightSourceElement? = null
|
||||
var delegateFields: List<FirField>? = null
|
||||
|
||||
objectLiteral.getChildNodesByType(OBJECT_DECLARATION).first().forEachChildren {
|
||||
objectDeclaration.forEachChildren {
|
||||
when (it.tokenType) {
|
||||
MODIFIER_LIST -> modifiers = convertModifierList(it)
|
||||
PRIMARY_CONSTRUCTOR -> primaryConstructor = it
|
||||
@@ -636,7 +637,7 @@ class DeclarationsConverter(
|
||||
annotations += modifiers.annotations
|
||||
initializer = withChildClassName(enumEntryName) {
|
||||
buildAnonymousObject {
|
||||
source = this@buildEnumEntry.source
|
||||
source = enumEntry.toFirSourceElement(FirFakeSourceElementKind.EnumInitializer)
|
||||
session = baseSession
|
||||
origin = FirDeclarationOrigin.Source
|
||||
classKind = ClassKind.ENUM_ENTRY
|
||||
|
||||
@@ -894,7 +894,7 @@ open class RawFirBuilder(
|
||||
val objectDeclaration = expression.objectDeclaration
|
||||
return withChildClassName(ANONYMOUS_OBJECT_NAME) {
|
||||
buildAnonymousObject {
|
||||
source = expression.toFirSourceElement()
|
||||
source = objectDeclaration.toFirSourceElement()
|
||||
session = baseSession
|
||||
origin = FirDeclarationOrigin.Source
|
||||
classKind = ClassKind.OBJECT
|
||||
|
||||
+1
@@ -258,6 +258,7 @@ class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
|
||||
it is KtAnnotatedExpression ||
|
||||
it is KtWhenConditionWithExpression ||
|
||||
it is KtFinallySection ||
|
||||
it is KtObjectLiteralExpression ||
|
||||
// TODO: KT-24089 (support of dynamic)
|
||||
it is KtDynamicType ||
|
||||
// NB: KtAnnotation is processed via its KtAnnotationEntries
|
||||
|
||||
@@ -7,7 +7,7 @@ public interface SomeTrait {
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
val x = object : SomeTrait {
|
||||
val x = <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object<!> : SomeTrait {
|
||||
}
|
||||
x.foo()
|
||||
}
|
||||
@@ -17,5 +17,5 @@ fun foo() {
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class C<!> : SomeTrait {}
|
||||
|
||||
fun foo2() {
|
||||
val r = object : Runnable {} //no error
|
||||
val r = <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object<!> : Runnable {} //no error
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
enum class EnumClass {
|
||||
E1 {
|
||||
override fun foo() = 1
|
||||
override val bar: String = "a"
|
||||
},
|
||||
|
||||
E2 {
|
||||
|
||||
};
|
||||
|
||||
abstract fun foo(): Int
|
||||
abstract val bar: String
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
enum class EnumClass {
|
||||
E1 {
|
||||
override fun foo() = 1
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
interface P {
|
||||
var f: Number
|
||||
}
|
||||
|
||||
open class Q {
|
||||
val x: Int = 42
|
||||
}
|
||||
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class R<!> : P, Q()
|
||||
|
||||
val s: Q = object : Q(), P {}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
interface P {
|
||||
var f: Number
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
interface Base {
|
||||
fun foo()
|
||||
}
|
||||
val String.test: Base = <!EXTENSION_PROPERTY_WITH_BACKING_FIELD!>object: Base<!> {
|
||||
val String.test: Base = <!EXTENSION_PROPERTY_WITH_BACKING_FIELD!>object<!>: Base {
|
||||
override fun foo() {
|
||||
<!UNRESOLVED_LABEL!>this@test<!>
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ abstract class KFunctionKt9005WorkAround<out R: Any?>(private val _functionInsta
|
||||
|
||||
private val _parameters: List<kotlin.reflect.KParameter> = run {
|
||||
_functionInstance.javaClass.methods.first().<!UNRESOLVED_REFERENCE!>parameters<!>.<!AMBIGUITY!>map<!> {
|
||||
object : kotlin.reflect.KParameter {
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object<!> : kotlin.reflect.KParameter {
|
||||
override val index: Int = 0
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ class Case2Outer {
|
||||
|
||||
// TESTCASE NUMBER: 3
|
||||
fun case3() {
|
||||
object : CaseOuter.CaseBase() {}.outerFoo()
|
||||
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>object<!> : CaseOuter.CaseBase() {}.outerFoo()
|
||||
}
|
||||
|
||||
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class B<!>() : CaseOuter.CaseBase() {}
|
||||
|
||||
+2
-2
@@ -44,7 +44,7 @@ fun case1() {
|
||||
* NOTE: property is not implemented
|
||||
*/
|
||||
fun case2() {
|
||||
val impl = object : Base() {
|
||||
val impl = <!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>object<!> : Base() {
|
||||
override var b: Any
|
||||
get() = TODO()
|
||||
set(value) {}
|
||||
@@ -71,7 +71,7 @@ fun case2() {
|
||||
*/
|
||||
|
||||
fun case3() {
|
||||
val impl = object : Base() {
|
||||
val impl = <!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>object<!> : Base() {
|
||||
override var b: Any
|
||||
get() = TODO()
|
||||
set(value) {}
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ class Case2() {
|
||||
abstract inner class Impl(override val a: CharSequence) : MainClass.Base3(a) {}
|
||||
|
||||
fun boo() {
|
||||
val impl = object : Impl("a") {
|
||||
val impl = <!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>object<!> : Impl("a") {
|
||||
override fun foo(): CharSequence = "foo"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -65,7 +65,7 @@ fun case3() {
|
||||
val v = Case3()
|
||||
v.boo(true)
|
||||
|
||||
val o = object : BaseKotlin() {}
|
||||
val o = <!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>object<!> : BaseKotlin() {}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -78,6 +78,6 @@ abstract class AbstractClassCase4 : BaseKotlin() {}
|
||||
fun case4() {
|
||||
val v = Case4()
|
||||
v.boo(true)
|
||||
val o = object : AbstractClassCase4() {}
|
||||
val o = <!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>object<!> : AbstractClassCase4() {}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -59,7 +59,7 @@ import libModule.*
|
||||
// TESTCASE NUMBER: 2
|
||||
class KotlinClassWithAbstractJavaClass() {
|
||||
fun foo() {
|
||||
val baseJava1 = object : BaseJava1() {}
|
||||
val baseKotlin = object : BaseKotlin1() {}
|
||||
val baseJava1 = <!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>object<!> : BaseJava1() {}
|
||||
val baseKotlin = <!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>object<!> : BaseKotlin1() {}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -882,48 +882,48 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
}
|
||||
add(FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED) { firDiagnostic ->
|
||||
AbstractMemberNotImplementedImpl(
|
||||
firSymbolBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED) { firDiagnostic ->
|
||||
AbstractClassMemberNotImplementedImpl(
|
||||
firSymbolBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER) { firDiagnostic ->
|
||||
InvisibleAbstractMemberFromSuperImpl(
|
||||
firSymbolBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING) { firDiagnostic ->
|
||||
InvisibleAbstractMemberFromSuperWarningImpl(
|
||||
firSymbolBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED) { firDiagnostic ->
|
||||
ManyImplMemberNotImplementedImpl(
|
||||
firSymbolBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED) { firDiagnostic ->
|
||||
ManyInterfacesMemberNotImplementedImpl(
|
||||
firSymbolBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
// Test for KT-8187
|
||||
interface A {
|
||||
fun get(x: Int)
|
||||
|
||||
Reference in New Issue
Block a user