[FIR] Report warning on non-deprecated overrides of deprecated members

^KT-47902
This commit is contained in:
Dmitriy Novozhilov
2021-08-27 17:30:59 +03:00
parent ef9ad5af51
commit 88913aa2a3
18 changed files with 140 additions and 40 deletions
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
import org.jetbrains.kotlin.resolve.deprecation.Deprecation
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
import org.jetbrains.kotlin.types.Variance
import kotlin.properties.PropertyDelegateProvider
@@ -239,6 +240,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val DEPRECATED_SINCE_KOTLIN_WITH_DEPRECATED_LEVEL by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
val DEPRECATED_SINCE_KOTLIN_OUTSIDE_KOTLIN_SUBPACKAGE by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
val OVERRIDE_DEPRECATION by warning<KtNamedDeclaration>(PositioningStrategy.DECLARATION_NAME) {
parameter<Symbol>("overridenSymbol")
parameter<Deprecation>("deprecationInfo")
}
val ANNOTATION_ON_SUPERCLASS by deprecationError<KtAnnotationEntry>(LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes)
val RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION by deprecationError<PsiElement>(LanguageFeature.RestrictRetentionForExpressionAnnotations)
val WRONG_ANNOTATION_TARGET by error<KtAnnotationEntry> {
@@ -83,6 +83,7 @@ import org.jetbrains.kotlin.psi.KtWhenCondition
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
import org.jetbrains.kotlin.resolve.deprecation.Deprecation
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
import org.jetbrains.kotlin.types.Variance
@@ -221,6 +222,7 @@ object FirErrors {
val DEPRECATED_SINCE_KOTLIN_WITHOUT_DEPRECATED by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val DEPRECATED_SINCE_KOTLIN_WITH_DEPRECATED_LEVEL by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val DEPRECATED_SINCE_KOTLIN_OUTSIDE_KOTLIN_SUBPACKAGE by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val OVERRIDE_DEPRECATION by warning2<KtNamedDeclaration, FirBasedSymbol<*>, Deprecation>(SourceElementPositioningStrategies.DECLARATION_NAME)
val ANNOTATION_ON_SUPERCLASS by deprecationError0<KtAnnotationEntry>(ProhibitUseSiteTargetAnnotationsOnSuperTypes)
val RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION by deprecationError0<PsiElement>(RestrictRetentionForExpressionAnnotations)
val WRONG_ANNOTATION_TARGET by error1<KtAnnotationEntry, String>()
@@ -169,6 +169,23 @@ object FirOverrideChecker : FirClassChecker() {
}
}
private fun FirCallableSymbol<*>.checkDeprecation(
reporter: DiagnosticReporter,
overriddenSymbols: List<FirCallableSymbol<*>>,
context: CheckerContext
) {
val ownDeprecation = this.deprecation
if (ownDeprecation == null || ownDeprecation.isNotEmpty()) return
for (overriddenSymbol in overriddenSymbols) {
val deprecationInfoFromOverridden = overriddenSymbol.deprecation ?: continue
val deprecationFromOverriddenSymbol = deprecationInfoFromOverridden.all
?: deprecationInfoFromOverridden.bySpecificSite?.values?.firstOrNull()
?: continue
reporter.reportOn(source, FirErrors.OVERRIDE_DEPRECATION, overriddenSymbol, deprecationFromOverriddenSymbol, context)
return
}
}
// See [OverrideResolver#isReturnTypeOkForOverride]
private fun FirCallableSymbol<*>.checkReturnType(
overriddenSymbols: List<FirCallableSymbol<*>>,
@@ -266,6 +283,8 @@ object FirOverrideChecker : FirClassChecker() {
member.checkVisibility(containingClass, reporter, overriddenMemberSymbols, context)
member.checkDeprecation(reporter, overriddenMemberSymbols, context)
val restriction = member.checkReturnType(
overriddenSymbols = overriddenMemberSymbols,
typeCheckerState = typeCheckerState,
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.diagnostics.rendering.LanguageFeatureMessageRenderer
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.RENDER_POSITION_VARIANCE
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.STRING
@@ -64,9 +66,9 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_PASSED_T
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNED_VALUE_IS_NEVER_READ
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNMENT_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGN_OPERATOR_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BACKING_FIELD_IN_INTERFACE
@@ -318,6 +320,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OTHER_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OVERRIDE_BY_INLINE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OVERRIDE_DEPRECATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OVERRIDING_FINAL_MEMBER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PACKAGE_CANNOT_BE_IMPORTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED
@@ -665,6 +668,12 @@ class FirDefaultErrorMessages {
DEPRECATED_SINCE_KOTLIN_OUTSIDE_KOTLIN_SUBPACKAGE,
"DeprecatedSinceKotlin annotation cannot be used outside 'kotlin' subpackages"
)
map.put(
OVERRIDE_DEPRECATION,
"This declaration overrides deprecated member but not marked as deprecated itself. Please add @Deprecated annotation or suppress",
TO_STRING,
TO_STRING
)
map.put(ANNOTATION_ON_SUPERCLASS, "Annotations on superclass are meaningless")
map.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING)
map.put(INAPPLICABLE_TARGET_ON_PROPERTY, "''@{0}:'' annotations could be applied only to property declarations", TO_STRING)
@@ -29,49 +29,49 @@ interface NotDeprecated {
}
open class WE : WarningDeprecated, ErrorDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class WH : WarningDeprecated, HiddenDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class EH : ErrorDeprecated, HiddenDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class NW : WarningDeprecated, NotDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class NE : ErrorDeprecated, NotDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class NH : HiddenDeprecated, NotDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class WEH: WarningDeprecated, ErrorDeprecated, HiddenDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class NWEH: NotDeprecated, WarningDeprecated, ErrorDeprecated, HiddenDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
@@ -89,12 +89,12 @@ interface E2: ErrorDeprecated
interface W2: WarningDeprecated
interface EW2: E2, W2 {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
interface HEW2: EW2, HiddenDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
@@ -29,49 +29,49 @@ interface NotDeprecated {
}
open class WE : WarningDeprecated, ErrorDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class WH : WarningDeprecated, HiddenDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class EH : ErrorDeprecated, HiddenDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class NW : WarningDeprecated, NotDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class NE : ErrorDeprecated, NotDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class NH : HiddenDeprecated, NotDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class WEH: WarningDeprecated, ErrorDeprecated, HiddenDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
open class NWEH: NotDeprecated, WarningDeprecated, ErrorDeprecated, HiddenDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
@@ -89,12 +89,12 @@ interface E2: ErrorDeprecated
interface W2: WarningDeprecated
interface EW2: E2, W2 {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
interface HEW2: EW2, HiddenDeprecated {
override fun f() {
override fun <!OVERRIDE_DEPRECATION!>f<!>() {
}
}
@@ -32,48 +32,48 @@ open class SetterDeprecated {
}
class WD: WarningDeprecated() {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {}
}
class ED: ErrorDeprecated() {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
}
class GD: GetterDeprecated() {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
}
class SD: SetterDeprecated() {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
}
class SDH: SetterDeprecated(), HiddenDeprecated {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
}
class EDH: ErrorDeprecated(), HiddenDeprecated {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
}
class NED: ErrorDeprecated(), NoDeprecation {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
@@ -32,48 +32,48 @@ open class SetterDeprecated {
}
class WD: WarningDeprecated() {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {}
}
class ED: ErrorDeprecated() {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
}
class GD: GetterDeprecated() {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
}
class SD: SetterDeprecated() {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
}
class SDH: SetterDeprecated(), HiddenDeprecated {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
}
class EDH: ErrorDeprecated(), HiddenDeprecated {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
}
class NED: ErrorDeprecated(), NoDeprecation {
override var p: Int
override var <!OVERRIDE_DEPRECATION!>p<!>: Int
get() = 3
set(value) {
}
@@ -0,0 +1,16 @@
// !DIAGNOSTICS: -NO_VALUE_FOR_PARAMETER
// FILE: A.java
@Deprecated
public class A {
@Deprecated
public String getFoo(String text) {
return text;
}
}
// FILE: B.kt
class B(private @property:Deprecated val foo: String) : <!DEPRECATION!>A<!>() {
override fun <!OVERRIDE_DEPRECATION!>getFoo<!>(text: String): String = super.<!DEPRECATION!>getFoo<!>(text + <!DEPRECATION!>foo<!>)
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -NO_VALUE_FOR_PARAMETER
// FILE: A.java
@@ -16,7 +16,7 @@ interface WithDeprecation {
}
class A : J(), WithDeprecation {
override fun foo() {}
override fun <!OVERRIDE_DEPRECATION!>foo<!>() {}
}
fun main() {
@@ -0,0 +1,23 @@
// FILE: J.java
public interface J {
@Deprecated
public void foo();
}
// FILE: J2.java
public interface J2 extends J {
@Override
public void foo();
}
// FILE: main.kt
interface A : J {
override fun <!OVERRIDE_DEPRECATION!>foo<!>()
}
fun main(j: J, j2: J2, a: A) {
j.<!DEPRECATION!>foo<!>()
j2.foo()
a.foo()
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// FILE: J.java
public interface J {
@Deprecated
@@ -58,13 +58,13 @@ interface I {
}
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class X<!> : I {
override fun foo1() {
override fun <!OVERRIDE_DEPRECATION!>foo1<!>() {
}
}
class B : A(<!ARGUMENT_TYPE_MISMATCH!>""<!>) {
// still can override it
override fun memberFun() {
override fun <!OVERRIDE_DEPRECATION!>memberFun<!>() {
super.<!INVISIBLE_REFERENCE!>memberFun<!>() // but cannot call super :)
}
}
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
import org.jetbrains.kotlin.resolve.deprecation.Deprecation
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.types.Variance
import kotlin.reflect.KClass
@@ -336,6 +337,7 @@ private object FirToKtConversionCreator {
FqName::class,
FirModuleData::class,
ExpectActualCompatibility.Incompatible::class,
Deprecation::class,
)
private val KType.kClass: KClass<*>
@@ -761,6 +761,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.OVERRIDE_DEPRECATION) { firDiagnostic ->
OverrideDeprecationImpl(
firSymbolBuilder.buildSymbol(firDiagnostic.a.fir),
firDiagnostic.b,
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.ANNOTATION_ON_SUPERCLASS.errorFactory) { firDiagnostic ->
AnnotationOnSuperclassErrorImpl(
firDiagnostic as FirPsiDiagnostic,
@@ -70,6 +70,7 @@ import org.jetbrains.kotlin.psi.KtWhenCondition
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
import org.jetbrains.kotlin.resolve.deprecation.Deprecation
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
import org.jetbrains.kotlin.types.Variance
@@ -548,6 +549,12 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = DeprecatedSinceKotlinOutsideKotlinSubpackage::class
}
abstract class OverrideDeprecation : KtFirDiagnostic<KtNamedDeclaration>() {
override val diagnosticClass get() = OverrideDeprecation::class
abstract val overridenSymbol: KtSymbol
abstract val deprecationInfo: Deprecation
}
abstract class AnnotationOnSuperclassError : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = AnnotationOnSuperclassError::class
}
@@ -72,6 +72,7 @@ import org.jetbrains.kotlin.psi.KtWhenCondition
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
import org.jetbrains.kotlin.resolve.deprecation.Deprecation
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
import org.jetbrains.kotlin.types.Variance
@@ -876,6 +877,15 @@ internal class DeprecatedSinceKotlinOutsideKotlinSubpackageImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class OverrideDeprecationImpl(
override val overridenSymbol: KtSymbol,
override val deprecationInfo: Deprecation,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.OverrideDeprecation(), KtAbstractFirDiagnostic<KtNamedDeclaration> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class AnnotationOnSuperclassErrorImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,