FIR: support JVM_DEFAULT_WITH_COMPATIBILITY_* diagnostics (FE 1.0 sync)

This commit is contained in:
Mikhail Glukhikh
2021-12-08 17:44:08 +03:00
committed by TeamCityServer
parent 178290eac3
commit 533e802c8d
14 changed files with 108 additions and 53 deletions
@@ -4110,6 +4110,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirJvmErrors.JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION) { firDiagnostic ->
JvmDefaultWithCompatibilityInDeclarationImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirJvmErrors.JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE) { firDiagnostic ->
JvmDefaultWithCompatibilityNotOnInterfaceImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirJvmErrors.USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL) { firDiagnostic ->
UsageOfJvmDefaultThroughSuperCallImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -2859,6 +2859,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val annotation: String
}
abstract class JvmDefaultWithCompatibilityInDeclaration : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = JvmDefaultWithCompatibilityInDeclaration::class
}
abstract class JvmDefaultWithCompatibilityNotOnInterface : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = JvmDefaultWithCompatibilityNotOnInterface::class
}
abstract class UsageOfJvmDefaultThroughSuperCall : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = UsageOfJvmDefaultThroughSuperCall::class
}
@@ -3456,6 +3456,16 @@ internal class JvmDefaultInDeclarationImpl(
override val token: ValidityToken,
) : KtFirDiagnostic.JvmDefaultInDeclaration(), KtAbstractFirDiagnostic<KtElement>
internal class JvmDefaultWithCompatibilityInDeclarationImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.JvmDefaultWithCompatibilityInDeclaration(), KtAbstractFirDiagnostic<KtElement>
internal class JvmDefaultWithCompatibilityNotOnInterfaceImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.JvmDefaultWithCompatibilityNotOnInterface(), KtAbstractFirDiagnostic<KtElement>
internal class UsageOfJvmDefaultThroughSuperCallImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken,
@@ -112,6 +112,8 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
val JVM_DEFAULT_IN_DECLARATION by error<KtElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
parameter<String>("annotation")
}
val JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION by error<KtElement>()
val JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE by error<KtElement>()
val USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL by error<PsiElement>()
val NON_JVM_DEFAULT_OVERRIDES_JAVA_DEFAULT by warning<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
}
@@ -93,6 +93,8 @@ object FirJvmErrors {
val JVM_DEFAULT_IN_JVM6_TARGET by error1<PsiElement, String>()
val JVM_DEFAULT_REQUIRED_FOR_OVERRIDE by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val JVM_DEFAULT_IN_DECLARATION by error1<KtElement, String>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
val JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION by error0<KtElement>()
val JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE by error0<KtElement>()
val USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL by error0<PsiElement>()
val NON_JVM_DEFAULT_OVERRIDES_JAVA_DEFAULT by warning0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
@@ -36,6 +36,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAUL
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAULT_NOT_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAULT_REQUIRED_FOR_OVERRIDE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_INLINE_WITHOUT_VALUE_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_PACKAGE_NAME_CANNOT_BE_EMPTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_PACKAGE_NAME_MUST_BE_VALID_NAME
@@ -176,6 +178,14 @@ object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
)
map.put(JVM_DEFAULT_REQUIRED_FOR_OVERRIDE, "'@JvmDefault' is required for an override of a '@JvmDefault' member")
map.put(JVM_DEFAULT_IN_DECLARATION, "Usage of ''@{0}'' is only allowed with -Xjvm-default option", STRING)
map.put(
JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION,
"Usage of '@JvmDefaultWithCompatibility' is only allowed with '-Xjvm-default=all' option"
)
map.put(
JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE,
"'@JvmDefaultWithCompatibility' annotation is only allowed on interfaces"
)
map.put(
USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL,
"Super calls of '@JvmDefault' members are only allowed with -Xjvm-default option"
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionCallableSymbol
import org.jetbrains.kotlin.name.JvmNames.JVM_DEFAULT_CLASS_ID
import org.jetbrains.kotlin.name.JvmNames.JVM_DEFAULT_NO_COMPATIBILITY_CLASS_ID
import org.jetbrains.kotlin.name.JvmNames.JVM_DEFAULT_WITH_COMPATIBILITY_CLASS_ID
object FirJvmDefaultChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -36,35 +37,67 @@ object FirJvmDefaultChecker : FirBasicDeclarationChecker() {
if (defaultAnnotation != null) {
val containingDeclaration = context.findClosest<FirClassLikeDeclaration>()
if (containingDeclaration !is FirClass || !containingDeclaration.isInterface) {
reporter.reportOn(defaultAnnotation.source, FirJvmErrors.JVM_DEFAULT_NOT_IN_INTERFACE, context)
return
} else if (context.isJvm6()) {
reporter.reportOn(defaultAnnotation.source, FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET, "JvmDefault", context)
return
} else if (!jvmDefaultMode.isEnabled) {
reporter.reportOn(defaultAnnotation.source, FirJvmErrors.JVM_DEFAULT_IN_DECLARATION, "JvmDefault", context)
return
val source = defaultAnnotation.source
when {
containingDeclaration !is FirClass || !containingDeclaration.isInterface -> {
reporter.reportOn(source, FirJvmErrors.JVM_DEFAULT_NOT_IN_INTERFACE, context)
return
}
context.isJvm6() -> {
reporter.reportOn(source, FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET, "JvmDefault", context)
return
}
!jvmDefaultMode.isEnabled -> {
reporter.reportOn(source, FirJvmErrors.JVM_DEFAULT_IN_DECLARATION, "JvmDefault", context)
return
}
}
} else {
val annotation = declaration.getAnnotationByClassId(JVM_DEFAULT_NO_COMPATIBILITY_CLASS_ID)
if (annotation != null) {
if (context.isJvm6()) {
reporter.reportOn(
annotation.source,
FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET,
"JvmDefaultWithoutCompatibility",
context
)
return
} else if (!jvmDefaultMode.isEnabled) {
reporter.reportOn(
annotation.source,
FirJvmErrors.JVM_DEFAULT_IN_DECLARATION,
"JvmDefaultWithoutCompatibility",
context
)
return
val annotationNoCompatibility = declaration.getAnnotationByClassId(JVM_DEFAULT_NO_COMPATIBILITY_CLASS_ID)
if (annotationNoCompatibility != null) {
val source = annotationNoCompatibility.source
when {
context.isJvm6() -> {
reporter.reportOn(
source,
FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET,
"JvmDefaultWithoutCompatibility",
context
)
return
}
!jvmDefaultMode.isEnabled -> {
reporter.reportOn(
source,
FirJvmErrors.JVM_DEFAULT_IN_DECLARATION,
"JvmDefaultWithoutCompatibility",
context
)
return
}
}
}
val annotationWithCompatibility = declaration.getAnnotationByClassId(JVM_DEFAULT_WITH_COMPATIBILITY_CLASS_ID)
if (annotationWithCompatibility != null) {
val source = annotationWithCompatibility.source
when {
context.isJvm6() -> {
reporter.reportOn(
source,
FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET,
"JvmDefaultWithCompatibility",
context
)
return
}
jvmDefaultMode != JvmDefaultMode.ALL_INCOMPATIBLE -> {
reporter.reportOn(source, FirJvmErrors.JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION, context)
return
}
declaration !is FirRegularClass || !declaration.isInterface -> {
reporter.reportOn(source, FirJvmErrors.JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE, context)
return
}
}
}
}
@@ -1,7 +0,0 @@
// !JVM_TARGET: 1.6
@JvmDefaultWithCompatibility
interface A {}
@JvmDefaultWithCompatibility
class B : A {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !JVM_TARGET: 1.6
<!JVM_DEFAULT_IN_JVM6_TARGET!>@JvmDefaultWithCompatibility<!>
@@ -1,10 +0,0 @@
// !JVM_TARGET: 1.8
// !JVM_DEFAULT_MODE: all
@JvmDefaultWithCompatibility
interface A<T> {
fun test(p: T) {}
}
@JvmDefaultWithCompatibility
class B : A<String> {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !JVM_TARGET: 1.8
// !JVM_DEFAULT_MODE: all
@@ -1,9 +0,0 @@
// !JVM_TARGET: 1.8
@JvmDefaultWithCompatibility
interface A<T> {
fun test(p: T) {}
}
@JvmDefaultWithCompatibility
class B : A<String> {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !JVM_TARGET: 1.8
<!JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION!>@JvmDefaultWithCompatibility<!>
@@ -21,6 +21,7 @@ object JvmNames {
val JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME = FqName("kotlin.jvm.JvmDefaultWithoutCompatibility")
val JVM_DEFAULT_WITH_COMPATIBILITY_FQ_NAME = FqName("kotlin.jvm.JvmDefaultWithCompatibility")
val JVM_DEFAULT_NO_COMPATIBILITY_CLASS_ID = ClassId.topLevel(JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME)
val JVM_DEFAULT_WITH_COMPATIBILITY_CLASS_ID = ClassId.topLevel(JVM_DEFAULT_WITH_COMPATIBILITY_FQ_NAME)
val JVM_OVERLOADS_FQ_NAME = FqName("kotlin.jvm.JvmOverloads")
val JVM_OVERLOADS_CLASS_ID = ClassId.topLevel(JVM_OVERLOADS_FQ_NAME)