[FIR] Add JVM diagnostics about external declaration
This commit is contained in:
committed by
TeamCityServer
parent
4907bc296f
commit
816e8f487c
+7
@@ -103,4 +103,11 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
|
||||
val USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL by error<PsiElement>()
|
||||
val NON_JVM_DEFAULT_OVERRIDES_JAVA_DEFAULT by warning<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
}
|
||||
|
||||
val EXTERNAL_DECLARATION by object : DiagnosticGroup("External Declaration") {
|
||||
val EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT by error<KtDeclaration>(PositioningStrategy.ABSTRACT_MODIFIER)
|
||||
val EXTERNAL_DECLARATION_CANNOT_HAVE_BODY by error<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
val EXTERNAL_DECLARATION_IN_INTERFACE by error<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
val EXTERNAL_DECLARATION_CANNOT_BE_INLINED by error<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -83,4 +83,10 @@ object FirJvmErrors {
|
||||
val USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL by error0<PsiElement>()
|
||||
val NON_JVM_DEFAULT_OVERRIDES_JAVA_DEFAULT by warning0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
|
||||
// External Declaration
|
||||
val EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT by error0<KtDeclaration>(SourceElementPositioningStrategies.ABSTRACT_MODIFIER)
|
||||
val EXTERNAL_DECLARATION_CANNOT_HAVE_BODY by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val EXTERNAL_DECLARATION_IN_INTERFACE by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val EXTERNAL_DECLARATION_CANNOT_BE_INLINED by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
|
||||
}
|
||||
|
||||
+42
-5
@@ -5,20 +5,45 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.containingClass
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExternal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInline
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
|
||||
object FirJvmExternalDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
checkInternal(declaration, null, null, context, reporter)
|
||||
}
|
||||
|
||||
private fun checkInternal(
|
||||
declaration: FirDeclaration,
|
||||
reportSource: FirSourceElement?,
|
||||
modality: Modality?,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
if (declaration !is FirMemberDeclaration) return
|
||||
|
||||
if (declaration is FirProperty) {
|
||||
declaration.getter?.let {
|
||||
checkInternal(it, declaration.source, declaration.modality, context, reporter)
|
||||
}
|
||||
}
|
||||
|
||||
if (!declaration.isExternal) return
|
||||
val source = declaration.source ?: return
|
||||
if (source.kind is FirFakeSourceElementKind) return
|
||||
@@ -34,12 +59,24 @@ object FirJvmExternalDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
externalModifier?.let {
|
||||
reporter.reportOn(it.source, FirErrors.WRONG_MODIFIER_TARGET, it.token, target, context)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Implement checkers for these JVM-specific errors (see ExternalFunChecker in FE1.0):
|
||||
// - EXTERNAL_DECLARATION_IN_INTERFACE
|
||||
// - EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT
|
||||
// - EXTERNAL_DECLARATION_CANNOT_HAVE_BODY
|
||||
// - EXTERNAL_DECLARATION_CANNOT_BE_INLINED
|
||||
val containingClassSymbol = declaration.symbol.containingClass()?.toFirRegularClass(context.session)
|
||||
if (containingClassSymbol != null) {
|
||||
if (containingClassSymbol.isInterface) {
|
||||
reporter.reportOn(declaration.source, FirJvmErrors.EXTERNAL_DECLARATION_IN_INTERFACE, context)
|
||||
} else if ((modality ?: declaration.modality) == Modality.ABSTRACT) {
|
||||
reporter.reportOn(reportSource ?: declaration.source, FirJvmErrors.EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT, context)
|
||||
}
|
||||
}
|
||||
|
||||
if (declaration !is FirConstructor && declaration.body != null) {
|
||||
reporter.reportOn(declaration.source, FirJvmErrors.EXTERNAL_DECLARATION_CANNOT_HAVE_BODY, context)
|
||||
}
|
||||
|
||||
if (declaration.isInline) {
|
||||
reporter.reportOn(declaration.source, FirJvmErrors.EXTERNAL_DECLARATION_CANNOT_BE_INLINED, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
@@ -13,6 +13,10 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.CONFLICTIN
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.DELEGATION_BY_IN_JVM_RECORD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.DEPRECATED_JAVA_ANNOTATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.ENUM_JVM_RECORD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.EXTERNAL_DECLARATION_CANNOT_BE_INLINED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.EXTERNAL_DECLARATION_CANNOT_HAVE_BODY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.EXTERNAL_DECLARATION_IN_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.FIELD_IN_JVM_RECORD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.ILLEGAL_JAVA_LANG_RECORD_SUPERTYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.ILLEGAL_JVM_NAME
|
||||
@@ -155,6 +159,11 @@ object FirJvmDefaultErrorMessages {
|
||||
NON_JVM_DEFAULT_OVERRIDES_JAVA_DEFAULT,
|
||||
"Non-@JvmDefault interface method cannot override default Java method. Please annotate this method with @JvmDefault or enable `-Xjvm-default=all|all-compatibility`"
|
||||
)
|
||||
|
||||
map.put(EXTERNAL_DECLARATION_IN_INTERFACE, "Members of interfaces can not be external")
|
||||
map.put(EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT, "External declaration can not be abstract")
|
||||
map.put(EXTERNAL_DECLARATION_CANNOT_HAVE_BODY, "External declaration can not have a body")
|
||||
map.put(EXTERNAL_DECLARATION_CANNOT_BE_INLINED, "Inline functions can not be external")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
abstract class A {
|
||||
abstract val x : Int
|
||||
external get
|
||||
}
|
||||
|
||||
interface B {
|
||||
val x: Int
|
||||
external get
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
abstract class A {
|
||||
<!EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT!>abstract<!> val x : Int
|
||||
external get
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import kotlin.jvm.*
|
||||
|
||||
abstract class C {
|
||||
abstract external fun foo()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
abstract class Local {
|
||||
abstract external fun foo()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
import kotlin.jvm.*
|
||||
|
||||
abstract class C {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import kotlin.jvm.*
|
||||
|
||||
external fun foo() {}
|
||||
|
||||
class C {
|
||||
external fun foo() {}
|
||||
|
||||
companion object {
|
||||
external fun foo() {}
|
||||
}
|
||||
}
|
||||
|
||||
object O {
|
||||
external fun foo() {}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
class Local {
|
||||
external fun foo() {}
|
||||
}
|
||||
|
||||
object {
|
||||
external fun foo() {}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
import kotlin.jvm.*
|
||||
|
||||
<!EXTERNAL_DECLARATION_CANNOT_HAVE_BODY!>external fun foo()<!> {}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import kotlin.jvm.*
|
||||
|
||||
abstract class C {
|
||||
<!NOTHING_TO_INLINE!>inline<!> external fun foo()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
abstract class Local {
|
||||
<!NOTHING_TO_INLINE!>inline<!> external fun foo()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
import kotlin.jvm.*
|
||||
|
||||
abstract class C {
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import kotlin.jvm.*
|
||||
|
||||
external fun <<!REIFIED_TYPE_PARAMETER_NO_INLINE!>reified<!> T> foo()
|
||||
inline external fun <reified T> bar()
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
import kotlin.jvm.*
|
||||
|
||||
external fun <<!REIFIED_TYPE_PARAMETER_NO_INLINE!>reified<!> T> foo()
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import kotlin.jvm.*
|
||||
|
||||
interface Tr {
|
||||
external fun foo()
|
||||
external fun bar() {}
|
||||
|
||||
companion object {
|
||||
external fun foo()
|
||||
external fun bar() {}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
import kotlin.jvm.*
|
||||
|
||||
interface Tr {
|
||||
|
||||
+24
@@ -3756,4 +3756,28 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirJvmErrors.EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT) { firDiagnostic ->
|
||||
ExternalDeclarationCannotBeAbstractImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirJvmErrors.EXTERNAL_DECLARATION_CANNOT_HAVE_BODY) { firDiagnostic ->
|
||||
ExternalDeclarationCannotHaveBodyImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirJvmErrors.EXTERNAL_DECLARATION_IN_INTERFACE) { firDiagnostic ->
|
||||
ExternalDeclarationInInterfaceImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirJvmErrors.EXTERNAL_DECLARATION_CANNOT_BE_INLINED) { firDiagnostic ->
|
||||
ExternalDeclarationCannotBeInlinedImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+16
@@ -2612,4 +2612,20 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = NonJvmDefaultOverridesJavaDefault::class
|
||||
}
|
||||
|
||||
abstract class ExternalDeclarationCannotBeAbstract : KtFirDiagnostic<KtDeclaration>() {
|
||||
override val diagnosticClass get() = ExternalDeclarationCannotBeAbstract::class
|
||||
}
|
||||
|
||||
abstract class ExternalDeclarationCannotHaveBody : KtFirDiagnostic<KtDeclaration>() {
|
||||
override val diagnosticClass get() = ExternalDeclarationCannotHaveBody::class
|
||||
}
|
||||
|
||||
abstract class ExternalDeclarationInInterface : KtFirDiagnostic<KtDeclaration>() {
|
||||
override val diagnosticClass get() = ExternalDeclarationInInterface::class
|
||||
}
|
||||
|
||||
abstract class ExternalDeclarationCannotBeInlined : KtFirDiagnostic<KtDeclaration>() {
|
||||
override val diagnosticClass get() = ExternalDeclarationCannotBeInlined::class
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+28
@@ -4245,3 +4245,31 @@ internal class NonJvmDefaultOverridesJavaDefaultImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ExternalDeclarationCannotBeAbstractImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ExternalDeclarationCannotBeAbstract(), KtAbstractFirDiagnostic<KtDeclaration> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ExternalDeclarationCannotHaveBodyImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ExternalDeclarationCannotHaveBody(), KtAbstractFirDiagnostic<KtDeclaration> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ExternalDeclarationInInterfaceImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ExternalDeclarationInInterface(), KtAbstractFirDiagnostic<KtDeclaration> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ExternalDeclarationCannotBeInlinedImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ExternalDeclarationCannotBeInlined(), KtAbstractFirDiagnostic<KtDeclaration> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user