FIR: introduce INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER
This commit is contained in:
+1
-1
@@ -22,7 +22,7 @@ abstract class K {
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> val i2: Int
|
||||
}
|
||||
|
||||
private open class L : K()
|
||||
private open <!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class L<!> : K()
|
||||
private abstract class M : K()
|
||||
|
||||
class X {
|
||||
|
||||
+8
@@ -299,6 +299,14 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
parameter<FirClass<*>>("classOrObject")
|
||||
parameter<FirCallableDeclaration<*>>("missingDeclaration")
|
||||
}
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by error<FirSourceElement, KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
|
||||
parameter<FirClass<*>>("classOrObject")
|
||||
parameter<FirCallableDeclaration<*>>("invisibleDeclaration")
|
||||
}
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING by warning<FirSourceElement, KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
|
||||
parameter<FirClass<*>>("classOrObject")
|
||||
parameter<FirCallableDeclaration<*>>("invisibleDeclaration")
|
||||
}
|
||||
val MANY_IMPL_MEMBER_NOT_IMPLEMENTED by error<FirSourceElement, KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
|
||||
parameter<FirClass<*>>("classOrObject")
|
||||
parameter<FirCallableDeclaration<*>>("missingDeclaration")
|
||||
|
||||
@@ -210,6 +210,8 @@ object FirErrors {
|
||||
val OVERRIDING_FINAL_MEMBER by error2<FirSourceElement, KtNamedDeclaration, FirCallableDeclaration<*>, Name>(SourceElementPositioningStrategies.OVERRIDE_MODIFIER)
|
||||
val ABSTRACT_MEMBER_NOT_IMPLEMENTED by error2<FirSourceElement, KtClassOrObject, FirClass<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED by error2<FirSourceElement, KtClassOrObject, FirClass<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by error2<FirSourceElement, KtClassOrObject, FirClass<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING by warning2<FirSourceElement, KtClassOrObject, FirClass<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val MANY_IMPL_MEMBER_NOT_IMPLEMENTED by error2<FirSourceElement, KtClassOrObject, FirClass<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED by error2<FirSourceElement, KtClassOrObject, FirClass<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val RETURN_TYPE_MISMATCH_ON_OVERRIDE by error2<FirSourceElement, KtNamedDeclaration, FirMemberDeclaration, FirMemberDeclaration>(SourceElementPositioningStrategies.DECLARATION_RETURN_TYPE)
|
||||
|
||||
+21
-7
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
@@ -17,6 +18,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
@@ -43,6 +45,7 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
)
|
||||
|
||||
val notImplementedSymbols = mutableListOf<FirCallableSymbol<*>>()
|
||||
val invisibleSymbols = mutableListOf<FirCallableSymbol<*>>()
|
||||
val classPackage = declaration.symbol.classId.packageFqName
|
||||
|
||||
fun FirCallableMemberDeclaration<*>.isInvisible(): Boolean {
|
||||
@@ -67,22 +70,25 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
classScope.processFunctionsByName(name) { namedFunctionSymbol ->
|
||||
val simpleFunction = namedFunctionSymbol.fir
|
||||
if (!simpleFunction.shouldBeImplemented()) return@processFunctionsByName
|
||||
// TODO: private & package-private functions / properties require another diagnostic
|
||||
// (INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER)
|
||||
if (simpleFunction.isInvisible()) return@processFunctionsByName
|
||||
|
||||
if (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
|
||||
notImplementedSymbols += namedFunctionSymbol
|
||||
if (simpleFunction.isInvisible()) {
|
||||
invisibleSymbols += namedFunctionSymbol
|
||||
} else {
|
||||
notImplementedSymbols += namedFunctionSymbol
|
||||
}
|
||||
}
|
||||
classScope.processPropertiesByName(name) { propertySymbol ->
|
||||
val property = propertySymbol.fir as? FirProperty ?: return@processPropertiesByName
|
||||
if (!property.shouldBeImplemented()) return@processPropertiesByName
|
||||
if (property.isInvisible()) return@processPropertiesByName
|
||||
|
||||
notImplementedSymbols += propertySymbol
|
||||
if (property.isInvisible()) {
|
||||
invisibleSymbols += propertySymbol
|
||||
} else {
|
||||
notImplementedSymbols += propertySymbol
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +100,14 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
reporter.reportOn(source, FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)
|
||||
}
|
||||
}
|
||||
if (invisibleSymbols.isNotEmpty()) {
|
||||
val invisible = invisibleSymbols.first().fir
|
||||
if (context.session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses)) {
|
||||
reporter.reportOn(source, FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER, declaration, invisible, context)
|
||||
} else {
|
||||
reporter.reportOn(source, FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING, declaration, invisible, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirCallableDeclaration<*>.isFromInterface(context: CheckerContext): Boolean =
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
// !LANGUAGE: +ProhibitInvisibleAbstractMethodsInSuperclasses
|
||||
// FILE: base/Base.java
|
||||
package base;
|
||||
|
||||
public abstract class Base {
|
||||
public void foo() {
|
||||
packagePrivateFoo();
|
||||
}
|
||||
|
||||
/* package-private */ abstract void packagePrivateFoo();
|
||||
}
|
||||
|
||||
// FILE: Impl.kt
|
||||
package impl
|
||||
import base.*
|
||||
|
||||
class Impl : Base()
|
||||
|
||||
fun foo() {
|
||||
Impl().foo()
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: +ProhibitInvisibleAbstractMethodsInSuperclasses
|
||||
// FILE: base/Base.java
|
||||
package base;
|
||||
|
||||
+3
-3
@@ -27,9 +27,9 @@ package impl
|
||||
import base.*
|
||||
import intermediate.*
|
||||
|
||||
class ImplDirectFromBase : Base()
|
||||
<!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class ImplDirectFromBase<!> : Base()
|
||||
|
||||
object ImplObjDirectFromBase : Base()
|
||||
<!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>object ImplObjDirectFromBase<!> : Base()
|
||||
|
||||
class ImplDirectFromBaseWithOverride : BaseWithOverride()
|
||||
|
||||
@@ -37,7 +37,7 @@ class ImplDirectFromBaseWithOverrid : Base() {
|
||||
override fun internalFoo(): String = ""
|
||||
}
|
||||
|
||||
class ImplViaIntermediate : Intermediate()
|
||||
<!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class ImplViaIntermediate<!> : Intermediate()
|
||||
|
||||
fun foo() {
|
||||
ImplDirectFromBase().foo()
|
||||
|
||||
Vendored
-22
@@ -1,22 +0,0 @@
|
||||
// !LANGUAGE: -ProhibitInvisibleAbstractMethodsInSuperclasses
|
||||
// MODULE: base
|
||||
// FILE: Base.kt
|
||||
package base
|
||||
|
||||
abstract class Base {
|
||||
fun foo(): String {
|
||||
return internalFoo()
|
||||
}
|
||||
internal abstract fun internalFoo(): String
|
||||
}
|
||||
|
||||
// MODULE: impl(base)
|
||||
// FILE: Impl.kt
|
||||
package impl
|
||||
import base.*
|
||||
|
||||
class Impl : Base()
|
||||
|
||||
fun foo() {
|
||||
Impl().foo()
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: -ProhibitInvisibleAbstractMethodsInSuperclasses
|
||||
// MODULE: base
|
||||
// FILE: Base.kt
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ import base.*
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
|
||||
class Case1 : BaseJava() {}
|
||||
<!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class Case1<!> : BaseJava() {}
|
||||
|
||||
fun case1() {
|
||||
val v = Case1()
|
||||
@@ -38,7 +38,7 @@ fun case1() {
|
||||
*/
|
||||
abstract class AbstractClassCase2 : BaseJava() {}
|
||||
|
||||
class Case2 : AbstractClassCase2() {}
|
||||
<!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class Case2<!> : AbstractClassCase2() {}
|
||||
|
||||
fun case2() {
|
||||
val v = Case2()
|
||||
|
||||
+2
-2
@@ -51,7 +51,7 @@ fun case2() {
|
||||
|
||||
// TESTCASE NUMBER: 3
|
||||
|
||||
class Case3 : BaseJava() {}
|
||||
<!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class Case3<!> : BaseJava() {}
|
||||
|
||||
fun case3() {
|
||||
val v = Case3()
|
||||
@@ -63,7 +63,7 @@ fun case3() {
|
||||
*/
|
||||
abstract class AbstractClassCase4 : BaseJava() {}
|
||||
|
||||
class Case4 : AbstractClassCase4() {}
|
||||
<!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class Case4<!> : AbstractClassCase4() {}
|
||||
|
||||
fun case4() {
|
||||
val v = Case4()
|
||||
|
||||
+2
-2
@@ -59,7 +59,7 @@ fun case2() {
|
||||
|
||||
// TESTCASE NUMBER: 3
|
||||
|
||||
class Case3 : BaseKotlin() {}
|
||||
<!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class Case3<!> : BaseKotlin() {}
|
||||
|
||||
fun case3() {
|
||||
val v = Case3()
|
||||
@@ -73,7 +73,7 @@ fun case3() {
|
||||
*/
|
||||
abstract class AbstractClassCase4 : BaseKotlin() {}
|
||||
|
||||
class Case4 : AbstractClassCase4() {}
|
||||
<!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class Case4<!> : AbstractClassCase4() {}
|
||||
|
||||
fun case4() {
|
||||
val v = Case4()
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ abstract class AbstractClassCase1() {
|
||||
public abstract val pub1: String
|
||||
}
|
||||
|
||||
class Case1 : AbstractClassCase1(){
|
||||
<!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class Case1<!> : AbstractClassCase1(){
|
||||
override fun prot() {}
|
||||
|
||||
override fun int() {
|
||||
|
||||
+16
@@ -896,6 +896,22 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER) { firDiagnostic ->
|
||||
InvisibleAbstractMemberFromSuperImpl(
|
||||
firSymbolBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.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),
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED) { firDiagnostic ->
|
||||
ManyImplMemberNotImplementedImpl(
|
||||
firSymbolBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
|
||||
+12
@@ -637,6 +637,18 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val missingDeclaration: KtCallableSymbol
|
||||
}
|
||||
|
||||
abstract class InvisibleAbstractMemberFromSuper : KtFirDiagnostic<KtClassOrObject>() {
|
||||
override val diagnosticClass get() = InvisibleAbstractMemberFromSuper::class
|
||||
abstract val classOrObject: KtClassLikeSymbol
|
||||
abstract val invisibleDeclaration: KtCallableSymbol
|
||||
}
|
||||
|
||||
abstract class InvisibleAbstractMemberFromSuperWarning : KtFirDiagnostic<KtClassOrObject>() {
|
||||
override val diagnosticClass get() = InvisibleAbstractMemberFromSuperWarning::class
|
||||
abstract val classOrObject: KtClassLikeSymbol
|
||||
abstract val invisibleDeclaration: KtCallableSymbol
|
||||
}
|
||||
|
||||
abstract class ManyImplMemberNotImplemented : KtFirDiagnostic<KtClassOrObject>() {
|
||||
override val diagnosticClass get() = ManyImplMemberNotImplemented::class
|
||||
abstract val classOrObject: KtClassLikeSymbol
|
||||
|
||||
+18
@@ -1025,6 +1025,24 @@ internal class AbstractClassMemberNotImplementedImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class InvisibleAbstractMemberFromSuperImpl(
|
||||
override val classOrObject: KtClassLikeSymbol,
|
||||
override val invisibleDeclaration: KtCallableSymbol,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.InvisibleAbstractMemberFromSuper(), KtAbstractFirDiagnostic<KtClassOrObject> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class InvisibleAbstractMemberFromSuperWarningImpl(
|
||||
override val classOrObject: KtClassLikeSymbol,
|
||||
override val invisibleDeclaration: KtCallableSymbol,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.InvisibleAbstractMemberFromSuperWarning(), KtAbstractFirDiagnostic<KtClassOrObject> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ManyImplMemberNotImplementedImpl(
|
||||
override val classOrObject: KtClassLikeSymbol,
|
||||
override val missingDeclaration: KtCallableSymbol,
|
||||
|
||||
Reference in New Issue
Block a user