[K2] Warn about deprecation and opt-in markers for overrides of Any

^KT-62620 Fixed

Include opt-in markers in the diagnostics
This commit is contained in:
Alejandro Serrano Mena
2023-10-16 16:00:40 +02:00
committed by Space Team
parent 6afe716238
commit b9b15cba08
17 changed files with 300 additions and 1 deletions
@@ -1195,6 +1195,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.POTENTIALLY_NON_REPORTED_ANNOTATION) { firDiagnostic ->
PotentiallyNonReportedAnnotationImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirJsErrors.WRONG_JS_QUALIFIER) { firDiagnostic ->
WrongJsQualifierImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -867,6 +867,10 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = NonSourceAnnotationOnInlinedLambdaExpression::class
}
interface PotentiallyNonReportedAnnotation : KtFirDiagnostic<KtAnnotationEntry> {
override val diagnosticClass get() = PotentiallyNonReportedAnnotation::class
}
interface WrongJsQualifier : KtFirDiagnostic<KtElement> {
override val diagnosticClass get() = WrongJsQualifier::class
}
@@ -1038,6 +1038,11 @@ internal class NonSourceAnnotationOnInlinedLambdaExpressionImpl(
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtAnnotationEntry>(firDiagnostic, token), KtFirDiagnostic.NonSourceAnnotationOnInlinedLambdaExpression
internal class PotentiallyNonReportedAnnotationImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtAnnotationEntry>(firDiagnostic, token), KtFirDiagnostic.PotentiallyNonReportedAnnotation
internal class WrongJsQualifierImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
@@ -1878,6 +1878,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
}
@Test
@TestMetadata("DeprecationOnAny.kt")
public void testDeprecationOnAny() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/DeprecationOnAny.kt");
}
@Test
@TestMetadata("dontReportWarningAboutChangingExecutionOrderForVararg.kt")
public void testDontReportWarningAboutChangingExecutionOrderForVararg() throws Exception {
@@ -1878,6 +1878,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
}
@Test
@TestMetadata("DeprecationOnAny.kt")
public void testDeprecationOnAny() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/DeprecationOnAny.kt");
}
@Test
@TestMetadata("dontReportWarningAboutChangingExecutionOrderForVararg.kt")
public void testDontReportWarningAboutChangingExecutionOrderForVararg() throws Exception {
@@ -1878,6 +1878,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
}
@Test
@TestMetadata("DeprecationOnAny.kt")
public void testDeprecationOnAny() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/DeprecationOnAny.kt");
}
@Test
@TestMetadata("dontReportWarningAboutChangingExecutionOrderForVararg.kt")
public void testDontReportWarningAboutChangingExecutionOrderForVararg() throws Exception {
@@ -1884,6 +1884,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
}
@Test
@TestMetadata("DeprecationOnAny.kt")
public void testDeprecationOnAny() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/DeprecationOnAny.kt");
}
@Test
@TestMetadata("dontReportWarningAboutChangingExecutionOrderForVararg.kt")
public void testDontReportWarningAboutChangingExecutionOrderForVararg() throws Exception {
@@ -403,6 +403,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val VOLATILE_ON_DELEGATE by error<KtAnnotationEntry>()
val NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION by error<KtAnnotationEntry>()
val POTENTIALLY_NON_REPORTED_ANNOTATION by warning<KtAnnotationEntry>()
}
val OPT_IN by object : DiagnosticGroup("OptIn") {
@@ -302,6 +302,7 @@ object FirErrors {
val VOLATILE_ON_VALUE by error0<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error0<KtAnnotationEntry>()
val NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION by error0<KtAnnotationEntry>()
val POTENTIALLY_NON_REPORTED_ANNOTATION by warning0<KtAnnotationEntry>()
// OptIn
val OPT_IN_USAGE by warning2<PsiElement, FqName, String>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -71,6 +71,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirMemberFunctionsChecker,
FirDataObjectContentChecker,
ContractSyntaxV2FunctionChecker,
FirAnyDeprecationChecker,
)
override val propertyCheckers: Set<FirPropertyChecker>
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2023 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.checkers.declaration
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.directOverriddenFunctions
import org.jetbrains.kotlin.fir.analysis.checkers.getAnnotationClassForOptInMarker
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.getDeprecationsProviderFromAnnotations
import org.jetbrains.kotlin.fir.declarations.utils.isMethodOfAny
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
object FirAnyDeprecationChecker : FirSimpleFunctionChecker() {
private val firstKotlin = LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_0, ApiVersion.KOTLIN_1_0)
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isOverride || !declaration.symbol.isMethodOfAny) return
declaration.annotations.forEach { annotation ->
val isDeprecationMarker =
listOf(annotation)
.getDeprecationsProviderFromAnnotations(context.session, false)
.getDeprecationsInfo(firstKotlin)
?.isNotEmpty() == true
val isOptInMarker =
annotation.getAnnotationClassForOptInMarker(context.session) != null
if (isDeprecationMarker || isOptInMarker)
reporter.reportOn(annotation.source, FirErrors.POTENTIALLY_NON_REPORTED_ANNOTATION, context)
}
}
}
@@ -490,6 +490,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PACKAGE_CANNOT_BE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PACKAGE_OR_CLASSIFIER_REDECLARATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PLATFORM_CLASS_MAPPED_TO_KOTLIN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PLUGIN_ANNOTATION_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.POTENTIALLY_NON_REPORTED_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRE_RELEASE_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS
@@ -1032,6 +1033,10 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION,
"The lambda expression here is an inlined argument, so this annotation cannot be stored anywhere.",
)
map.put(
POTENTIALLY_NON_REPORTED_ANNOTATION,
"Deprecations and opt-ins on a method overridden from 'Any' may not be reported.",
)
// OptIn
map.put(OPT_IN_USAGE, "{1}", TO_STRING, STRING)
@@ -0,0 +1,30 @@
annotation class Other
@RequiresOptIn(message = "This is a test.")
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.FUNCTION)
annotation class OptInMarker
class A {
@Other
<!POTENTIALLY_NON_REPORTED_ANNOTATION!>@Deprecated("equals")<!>
<!POTENTIALLY_NON_REPORTED_ANNOTATION!>@SinceKotlin("1.2")<!>
override fun equals(other: Any?): Boolean {
return super.equals(other)
}
<!POTENTIALLY_NON_REPORTED_ANNOTATION!>@SinceKotlin("1.3")<!>
override fun hashCode(): Int {
return super.hashCode()
}
<!POTENTIALLY_NON_REPORTED_ANNOTATION!>@Deprecated("toString")<!>
<!POTENTIALLY_NON_REPORTED_ANNOTATION!>@OptInMarker<!>
override fun toString(): String {
return super.toString()
}
@Deprecated("other")
@OptInMarker
fun test(): Int = 5
}
@@ -0,0 +1,30 @@
annotation class Other
@RequiresOptIn(message = "This is a test.")
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.FUNCTION)
annotation class OptInMarker
class A {
@Other
@Deprecated("equals")
@SinceKotlin("1.2")
override fun equals(other: Any?): Boolean {
return super.equals(other)
}
@SinceKotlin("1.3")
override fun hashCode(): Int {
return super.hashCode()
}
@Deprecated("toString")
@OptInMarker
override fun toString(): String {
return super.toString()
}
@Deprecated("other")
@OptInMarker
fun test(): Int = 5
}
@@ -0,0 +1,147 @@
// !OPT_IN: kotlin.RequiresOptIn
// FILE: api.kt
package api
import kotlin.annotation.AnnotationTarget.*
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(CLASS, ANNOTATION_CLASS, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION,
PROPERTY_SETTER, TYPEALIAS)
@Retention(AnnotationRetention.BINARY)
annotation class E1
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
<!OPT_IN_MARKER_WITH_WRONG_TARGET!>@Target(FILE)<!>
annotation class E2
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
<!OPT_IN_MARKER_WITH_WRONG_TARGET!>@Target(EXPRESSION)<!>
<!OPT_IN_MARKER_WITH_WRONG_RETENTION!>@Retention(AnnotationRetention.SOURCE)<!>
annotation class E3
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
<!OPT_IN_MARKER_WITH_WRONG_TARGET!>@Target(TYPE_PARAMETER)<!>
@Retention(AnnotationRetention.BINARY)
annotation class E3A
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
<!OPT_IN_MARKER_WITH_WRONG_TARGET!>@Target(TYPE)<!>
@Retention(AnnotationRetention.BINARY)
annotation class E3B
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(PROPERTY_GETTER)
@Retention(AnnotationRetention.BINARY)
annotation class E4
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(PROPERTY_SETTER)
@Retention(AnnotationRetention.BINARY)
annotation class E5
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(PROPERTY, FUNCTION, PROPERTY_SETTER, VALUE_PARAMETER, FIELD, LOCAL_VARIABLE, CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class E6
var some: Int
<!OPT_IN_MARKER_ON_WRONG_TARGET!>@E4<!>
get() = 42
@E5
set(value) {}
<!OPT_IN_MARKER_ON_WRONG_TARGET!>@get:E4<!>
val another: Int = 42
class My {
<!POTENTIALLY_NON_REPORTED_ANNOTATION!>@E6<!>
override fun hashCode() = 0
}
interface Base {
val bar: Int
val baz: Int
@E6
fun foo()
fun String.withReceiver()
}
class Derived : Base {
@E6
override val bar: Int = 42
@set:E6 <!OPT_IN_MARKER_ON_WRONG_TARGET!>@setparam:E6<!>
override var baz: Int = 13
@E6
override fun foo() {}
override fun <!OPT_IN_MARKER_ON_WRONG_TARGET!>@receiver:E6<!> String.withReceiver() {}
}
class Wrapper(@property:E6 val foo: Int)
@E6
interface BaseMarked {
val bar: Int
}
@E6
class Outer {
interface Nested {
val baz: Int
}
}
@OptIn(E6::class)
class DerivedOptIn : BaseMarked, Outer.Nested {
@E6
override val bar: Int = 42 // Ok
@E6
override val baz: Int = 24 // Ok
}
abstract class Another(<!OPT_IN_MARKER_ON_WRONG_TARGET!>@param:E6<!> val x: String) : Base {
<!OPT_IN_MARKER_ON_WRONG_TARGET!>@delegate:E6<!>
override val bar: Int by lazy { 42 }
fun baz(<!OPT_IN_MARKER_ON_WRONG_TARGET!>@E6<!> param: Int) {
<!OPT_IN_MARKER_ON_WRONG_TARGET!>@E6<!> val x = param
}
}
interface A {
fun f()
}
interface B {
@E6
fun f()
}
interface C1 : A, B
interface C2 : B, A
class X1 : C1 {
@E6 // Ok
override fun f() {}
}
class X2 : C2 {
@E6 // Ok
override fun f() {}
}
open class Y(val b: B): B by b
class Z(b: B) : Y(b) {
@E6
override fun f() {}
}
class WithSetter(@set:E6 var withSetter: String)
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// !OPT_IN: kotlin.RequiresOptIn
// FILE: api.kt
@@ -1884,6 +1884,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
}
@Test
@TestMetadata("DeprecationOnAny.kt")
public void testDeprecationOnAny() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/DeprecationOnAny.kt");
}
@Test
@TestMetadata("dontReportWarningAboutChangingExecutionOrderForVararg.kt")
public void testDontReportWarningAboutChangingExecutionOrderForVararg() throws Exception {