[FIR] @JvmOverloads related checkers

This commit is contained in:
Andrey Zinovyev
2021-08-17 17:16:31 +03:00
committed by TeamCityServer
parent 17ae69416c
commit f9b601edae
17 changed files with 222 additions and 74 deletions
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.PrivateForInline
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
import org.jetbrains.kotlin.fir.types.ConeKotlinType
@@ -18,12 +19,6 @@ import org.jetbrains.kotlin.psi.KtAnnotationEntry
object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
val DECLARATIONS by object : DiagnosticGroup("Declarations") {
val CONFLICTING_JVM_DECLARATIONS by error<PsiElement>()
val STRICTFP_ON_CLASS by error<KtAnnotationEntry>()
val VOLATILE_ON_VALUE by error<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error<KtAnnotationEntry>()
val SYNCHRONIZED_ON_ABSTRACT by error<KtAnnotationEntry>()
val SYNCHRONIZED_IN_INTERFACE by error<KtAnnotationEntry>()
val SYNCHRONIZED_ON_INLINE by warning<KtAnnotationEntry>()
}
val TYPES by object : DiagnosticGroup("Types") {
@@ -32,4 +27,20 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
parameter<ConeKotlinType>("actualType")
}
}
val ANNOTATIONS by object : DiagnosticGroup("annotations") {
val STRICTFP_ON_CLASS by error<KtAnnotationEntry>()
val VOLATILE_ON_VALUE by error<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error<KtAnnotationEntry>()
val SYNCHRONIZED_ON_ABSTRACT by error<KtAnnotationEntry>()
val SYNCHRONIZED_IN_INTERFACE by error<KtAnnotationEntry>()
val SYNCHRONIZED_ON_INLINE by warning<KtAnnotationEntry>()
val OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS by warning<KtAnnotationEntry>()
val OVERLOADS_ABSTRACT by error<KtAnnotationEntry>()
val OVERLOADS_INTERFACE by error<KtAnnotationEntry>()
val OVERLOADS_LOCAL by error<KtAnnotationEntry>()
val OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR by deprecationError<KtAnnotationEntry>(LanguageFeature.ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses)
val OVERLOADS_PRIVATE by warning<KtAnnotationEntry>()
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics.jvm
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.psi.KtAnnotationEntry
@@ -19,14 +20,22 @@ import org.jetbrains.kotlin.psi.KtExpression
object FirJvmErrors {
// Declarations
val CONFLICTING_JVM_DECLARATIONS by error0<PsiElement>()
// Types
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
// annotations
val STRICTFP_ON_CLASS by error0<KtAnnotationEntry>()
val VOLATILE_ON_VALUE by error0<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error0<KtAnnotationEntry>()
val SYNCHRONIZED_ON_ABSTRACT by error0<KtAnnotationEntry>()
val SYNCHRONIZED_IN_INTERFACE by error0<KtAnnotationEntry>()
val SYNCHRONIZED_ON_INLINE by warning0<KtAnnotationEntry>()
// Types
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
val OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS by warning0<KtAnnotationEntry>()
val OVERLOADS_ABSTRACT by error0<KtAnnotationEntry>()
val OVERLOADS_INTERFACE by error0<KtAnnotationEntry>()
val OVERLOADS_LOCAL by error0<KtAnnotationEntry>()
val OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR by deprecationError0<KtAnnotationEntry>(ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses)
val OVERLOADS_PRIVATE by warning0<KtAnnotationEntry>()
}
@@ -6,10 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.jvm.checkers
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration.FirJvmExternalDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration.FirStrictfpApplicabilityChecker
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration.FirSynchronizedAnnotationChecker
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration.FirVolatileAnnotationChecker
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration.*
object JvmDeclarationCheckers : DeclarationCheckers() {
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
@@ -30,5 +27,6 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
override val functionCheckers: Set<FirFunctionChecker>
get() = setOf(
FirSynchronizedAnnotationChecker,
FirOverloadsChecker,
)
}
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFunctionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
import org.jetbrains.kotlin.fir.declarations.utils.isActual
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isLocalClassOrAnonymousObject
import org.jetbrains.kotlin.name.FqName
object FirOverloadsChecker : FirFunctionChecker() {
private val JVM_OVERLOADS_FQ_NAME = FqName("kotlin.jvm.JvmOverloads")
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
val annotation = declaration.getAnnotationByFqName(JVM_OVERLOADS_FQ_NAME) ?: return
//todo need to have expect declaration here to check if it has default values
if (declaration.isActual) return
val containingDeclaration = declaration.getContainingClassSymbol(context.session)
when {
containingDeclaration?.classKind == ClassKind.INTERFACE ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_INTERFACE, context)
declaration.isAbstract ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_ABSTRACT, context)
(declaration is FirSimpleFunction && declaration.isLocal) ||
context.containingDeclarations.any { it.isLocalClassOrAnonymousObject() } ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_LOCAL, context)
declaration is FirConstructor && containingDeclaration?.classKind == ClassKind.ANNOTATION_CLASS ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR, context)
!declaration.visibility.isPublicAPI && declaration.visibility != Visibilities.Internal ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_PRIVATE, context)
declaration.valueParameters.none { it.defaultValue != null } ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS, context)
}
}
}
@@ -1,7 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
class C {
@kotlin.jvm.JvmOverloads constructor() {
}
@kotlin.jvm.JvmOverloads fun foo(s: String) {}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER
class C {
<!OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS!>@kotlin.jvm.JvmOverloads<!> constructor() {
@@ -1,11 +0,0 @@
interface T {
@kotlin.jvm.JvmOverloads fun foo(s: String = "OK")
@kotlin.jvm.JvmOverloads fun bar(s: String = "OK") {
}
}
abstract class C {
@kotlin.jvm.JvmOverloads abstract fun foo(s: String = "OK")
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
interface T {
<!OVERLOADS_INTERFACE!>@kotlin.jvm.JvmOverloads<!> fun foo(s: String = "OK")
@@ -1,4 +0,0 @@
// !LANGUAGE: -ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses
annotation class A1 @JvmOverloads constructor(val x: Int = 1)
annotation class A2 @JvmOverloads constructor()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: -ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses
annotation class A1 <!OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_WARNING!>@JvmOverloads<!> constructor(val x: Int = 1)
@@ -1,4 +0,0 @@
// !LANGUAGE: +ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses
annotation class A1 @JvmOverloads constructor(val x: Int = 1)
annotation class A2 @JvmOverloads constructor()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: +ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses
annotation class A1 <!OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_ERROR!>@JvmOverloads<!> constructor(val x: Int = 1)
@@ -1,23 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
class C {
@kotlin.jvm.JvmOverloads private fun foo(s: String = "OK") {
}
@kotlin.jvm.JvmOverloads fun bar(s: String = "OK") {
}
}
fun foo() {
@kotlin.jvm.JvmOverloads fun quux(s: String = "OK") {
}
class D {
@kotlin.jvm.JvmOverloads fun foo(s: String = "OK") {
}
}
val x = object {
@kotlin.jvm.JvmOverloads fun foo(s: String = "OK") {
}
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER
class C {
<!OVERLOADS_PRIVATE!>@kotlin.jvm.JvmOverloads<!> private fun foo(s: String = "OK") {
@@ -3439,6 +3439,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirJvmErrors.JAVA_TYPE_MISMATCH) { firDiagnostic ->
JavaTypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.STRICTFP_ON_CLASS) { firDiagnostic ->
StrictfpOnClassImpl(
firDiagnostic as FirPsiDiagnostic,
@@ -3475,10 +3483,44 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirJvmErrors.JAVA_TYPE_MISMATCH) { firDiagnostic ->
JavaTypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
add(FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS) { firDiagnostic ->
OverloadsWithoutDefaultArgumentsImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.OVERLOADS_ABSTRACT) { firDiagnostic ->
OverloadsAbstractImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.OVERLOADS_INTERFACE) { firDiagnostic ->
OverloadsInterfaceImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.OVERLOADS_LOCAL) { firDiagnostic ->
OverloadsLocalImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR.errorFactory) { firDiagnostic ->
OverloadsAnnotationClassConstructorErrorImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR.warningFactory) { firDiagnostic ->
OverloadsAnnotationClassConstructorWarningImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.OVERLOADS_PRIVATE) { firDiagnostic ->
OverloadsPrivateImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
@@ -2398,6 +2398,12 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = ConflictingJvmDeclarations::class
}
abstract class JavaTypeMismatch : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = JavaTypeMismatch::class
abstract val expectedType: KtType
abstract val actualType: KtType
}
abstract class StrictfpOnClass : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = StrictfpOnClass::class
}
@@ -2422,10 +2428,32 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = SynchronizedOnInline::class
}
abstract class JavaTypeMismatch : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = JavaTypeMismatch::class
abstract val expectedType: KtType
abstract val actualType: KtType
abstract class OverloadsWithoutDefaultArguments : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = OverloadsWithoutDefaultArguments::class
}
abstract class OverloadsAbstract : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = OverloadsAbstract::class
}
abstract class OverloadsInterface : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = OverloadsInterface::class
}
abstract class OverloadsLocal : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = OverloadsLocal::class
}
abstract class OverloadsAnnotationClassConstructorError : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = OverloadsAnnotationClassConstructorError::class
}
abstract class OverloadsAnnotationClassConstructorWarning : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = OverloadsAnnotationClassConstructorWarning::class
}
abstract class OverloadsPrivate : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = OverloadsPrivate::class
}
}
@@ -3878,6 +3878,15 @@ internal class ConflictingJvmDeclarationsImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class JavaTypeMismatchImpl(
override val expectedType: KtType,
override val actualType: KtType,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.JavaTypeMismatch(), KtAbstractFirDiagnostic<KtExpression> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class StrictfpOnClassImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
@@ -3920,12 +3929,52 @@ internal class SynchronizedOnInlineImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class JavaTypeMismatchImpl(
override val expectedType: KtType,
override val actualType: KtType,
internal class OverloadsWithoutDefaultArgumentsImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.JavaTypeMismatch(), KtAbstractFirDiagnostic<KtExpression> {
) : KtFirDiagnostic.OverloadsWithoutDefaultArguments(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class OverloadsAbstractImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.OverloadsAbstract(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class OverloadsInterfaceImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.OverloadsInterface(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class OverloadsLocalImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.OverloadsLocal(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class OverloadsAnnotationClassConstructorErrorImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.OverloadsAnnotationClassConstructorError(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class OverloadsAnnotationClassConstructorWarningImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.OverloadsAnnotationClassConstructorWarning(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class OverloadsPrivateImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.OverloadsPrivate(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}