[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:
committed by
Space Team
parent
6afe716238
commit
b9b15cba08
+6
@@ -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,
|
||||
|
||||
+4
@@ -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
|
||||
}
|
||||
|
||||
+5
@@ -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,
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+2
@@ -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)
|
||||
|
||||
+1
@@ -71,6 +71,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirMemberFunctionsChecker,
|
||||
FirDataObjectContentChecker,
|
||||
ContractSyntaxV2FunctionChecker,
|
||||
FirAnyDeprecationChecker,
|
||||
)
|
||||
|
||||
override val propertyCheckers: Set<FirPropertyChecker>
|
||||
|
||||
+39
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -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
|
||||
}
|
||||
+147
@@ -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
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
// !OPT_IN: kotlin.RequiresOptIn
|
||||
// FILE: api.kt
|
||||
|
||||
|
||||
Generated
+6
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user