[FIR] Add JVM diagnostics about external declaration

This commit is contained in:
Ivan Kochurkin
2021-08-28 00:36:57 +03:00
committed by TeamCityServer
parent 4907bc296f
commit 816e8f487c
19 changed files with 138 additions and 76 deletions
@@ -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)
}
}
@@ -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)
}
@@ -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)
}
}
}
@@ -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 {
@@ -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,
)
}
}
@@ -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
}
}
@@ -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)
}