diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt index 18916f492d4..3eb9956bb14 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt @@ -23,34 +23,133 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.annotations.argumentValue +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import java.util.* private val JAVA_DEPRECATED = FqName("java.lang.Deprecated") -fun DeclarationDescriptor.getDeprecatedAnnotation(): Pair? { +interface Deprecation { + val deprecationLevel: DeprecationLevelValue + val message: String + val target: DeclarationDescriptor +} + +fun Deprecation.deprecatedByOverriddenMessage(): String? = (this as? DeprecatedByOverridden)?.additionalMessage() + +private data class DeprecatedByAnnotation(private val annotation: AnnotationDescriptor, override val target: DeclarationDescriptor) : Deprecation { + override val deprecationLevel: DeprecationLevelValue + get() { + val level = annotation.argumentValue("level") as? ClassDescriptor + + return when (level?.name?.asString()) { + "WARNING" -> DeprecationLevelValue.WARNING + "ERROR" -> DeprecationLevelValue.ERROR + "HIDDEN" -> DeprecationLevelValue.HIDDEN + else -> DeprecationLevelValue.WARNING + } + } + + override val message: String + get() = annotation.argumentValue("message") as? String ?: "" +} + +private data class DeprecatedByOverridden(private val deprecations: Collection) : Deprecation { + init { + assert(deprecations.isNotEmpty()) + assert(deprecations.none { + it is DeprecatedByOverridden + }) + } + + override val deprecationLevel: DeprecationLevelValue = deprecations.map(Deprecation::deprecationLevel).min()!! + + override val target: DeclarationDescriptor + get() = deprecations.first().target + + override val message: String + get() { + val message = deprecations.filter { it.deprecationLevel == this.deprecationLevel }.map { it.message }.toSet().joinToString(". ") + return "${additionalMessage()}. $message" + } + + internal fun additionalMessage() = "Overrides deprecated member in '${DescriptorUtils.getContainingClass(target)!!.fqNameSafe.asString()}'" +} + +fun DeclarationDescriptor.getDeprecation(): Deprecation? { + val deprecation = this.getDeprecationByAnnotation() + if (deprecation != null) { + return deprecation + } + + if (this is CallableMemberDescriptor) { + return deprecationByOverridden(this) + } + + return null +} + +private fun deprecationByOverridden(root: CallableMemberDescriptor): Deprecation? { + val visited = HashSet() + val deprecations = LinkedHashSet() + var hasUndeprecatedOverridden = false + + fun traverse(node: CallableMemberDescriptor) { + if (node in visited) return + + visited.add(node) + + val deprecatedAnnotation = node.getDeprecationByAnnotation() + val overriddenDescriptors = node.overriddenDescriptors + when { + deprecatedAnnotation != null -> { + deprecations.add(deprecatedAnnotation) + } + overriddenDescriptors.isEmpty() -> { + hasUndeprecatedOverridden = true + return + } + else -> { + overriddenDescriptors.forEach { traverse(it) } + } + } + } + + traverse(root) + + if (hasUndeprecatedOverridden || deprecations.isEmpty()) return null + + return DeprecatedByOverridden(deprecations) +} + +private fun DeclarationDescriptor.getDeprecationByAnnotation(): DeprecatedByAnnotation? { val ownAnnotation = getDeclaredDeprecatedAnnotation(AnnotationUseSiteTarget.getAssociatedUseSiteTarget(this)) if (ownAnnotation != null) - return ownAnnotation to this + return DeprecatedByAnnotation(ownAnnotation, this) when (this) { is ConstructorDescriptor -> { val classDescriptor = containingDeclaration val classAnnotation = classDescriptor.getDeclaredDeprecatedAnnotation() if (classAnnotation != null) - return classAnnotation to classDescriptor + return DeprecatedByAnnotation(classAnnotation, classDescriptor) } is PropertyAccessorDescriptor -> { val propertyDescriptor = correspondingProperty val target = if (this is PropertyGetterDescriptor) AnnotationUseSiteTarget.PROPERTY_GETTER else AnnotationUseSiteTarget.PROPERTY_SETTER - val accessorAnnotation = propertyDescriptor.getDeclaredDeprecatedAnnotation(target, false) - if (accessorAnnotation != null) - return accessorAnnotation to this + val useSiteAnnotationOnProperty = propertyDescriptor.getDeclaredDeprecatedAnnotation(target, false) + if (useSiteAnnotationOnProperty != null) + return DeprecatedByAnnotation(useSiteAnnotationOnProperty, this) + + val propertyAnnotation = propertyDescriptor.getDeclaredDeprecatedAnnotation() + if (propertyAnnotation != null) + return DeprecatedByAnnotation(propertyAnnotation, propertyDescriptor) val classDescriptor = containingDeclaration as? ClassDescriptor if (classDescriptor != null && classDescriptor.isCompanionObject) { val classAnnotation = classDescriptor.getDeclaredDeprecatedAnnotation() if (classAnnotation != null) - return classAnnotation to classDescriptor + return DeprecatedByAnnotation(classAnnotation, classDescriptor) } } } @@ -74,31 +173,16 @@ private fun DeclarationDescriptor.getDeclaredDeprecatedAnnotation( return null } -// Reflects values from kotlin.DeprecationLevel +// values from kotlin.DeprecationLevel enum class DeprecationLevelValue { WARNING, ERROR, HIDDEN } -fun AnnotationDescriptor.getDeprecatedAnnotationLevel(): DeprecationLevelValue? { - val level = this.argumentValue("level") as? ClassDescriptor - - return when(level?.name?.asString()) { - "WARNING" -> DeprecationLevelValue.WARNING - "ERROR" -> DeprecationLevelValue.ERROR - "HIDDEN" -> DeprecationLevelValue.HIDDEN - else -> null - } -} - -fun DeclarationDescriptor.getDeprecatedAnnotationLevel(): DeprecationLevelValue? { - return getDeprecatedAnnotation()?.first?.getDeprecatedAnnotationLevel() -} - @Deprecated("Should be removed together with kotlin.HiddenDeclaration") private val HIDDEN_ANNOTATION_FQ_NAME = FqName("kotlin.HiddenDeclaration") fun DeclarationDescriptor.isHiddenInResolution(): Boolean { if (this is FunctionDescriptor && this.isHiddenToOvercomeSignatureClash) return true return annotations.findAnnotation(HIDDEN_ANNOTATION_FQ_NAME) != null - || getDeprecatedAnnotationLevel() == DeprecationLevelValue.HIDDEN + || getDeprecation()?.deprecationLevel == DeprecationLevelValue.HIDDEN } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/DeprecatedSymbolValidator.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/DeprecatedSymbolValidator.kt index 1b1b1dee4bf..0901a2a6e0a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/DeprecatedSymbolValidator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/DeprecatedSymbolValidator.kt @@ -21,27 +21,28 @@ import com.intellij.psi.tree.TokenSet import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.Deprecation import org.jetbrains.kotlin.resolve.DeprecationLevelValue -import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall -import org.jetbrains.kotlin.resolve.getDeprecatedAnnotation -import org.jetbrains.kotlin.resolve.getDeprecatedAnnotationLevel +import org.jetbrains.kotlin.resolve.getDeprecation class DeprecatedSymbolValidator : SymbolUsageValidator { override fun validateCall(resolvedCall: ResolvedCall<*>?, targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) { - val deprecated = targetDescriptor.getDeprecatedAnnotation() - if (deprecated != null) { - val (annotation, target) = deprecated - trace.report(createDeprecationDiagnostic(element, target, annotation)) + val deprecation = targetDescriptor.getDeprecation() + + // avoid duplicating diagnostic when deprecation for property effectively deprecates setter + if (targetDescriptor is PropertySetterDescriptor && targetDescriptor.correspondingProperty.getDeprecation() == deprecation) return + + if (deprecation != null) { + trace.report(createDeprecationDiagnostic(element, deprecation)) } else if (targetDescriptor is PropertyDescriptor) { propertyGetterWorkaround(resolvedCall, targetDescriptor, trace, element) @@ -59,21 +60,19 @@ class DeprecatedSymbolValidator : SymbolUsageValidator { if (superExpression != null && superExpression.getCalleeExpression().getConstructorReferenceExpression() == element) return - val deprecated = targetDescriptor.getDeprecatedAnnotation() - if (deprecated != null) { - val (annotation, target) = deprecated - trace.report(createDeprecationDiagnostic(element, target, annotation)) + val deprecation = targetDescriptor.getDeprecation() + if (deprecation != null) { + trace.report(createDeprecationDiagnostic(element, deprecation)) } } - private fun createDeprecationDiagnostic(element: PsiElement, descriptor: DeclarationDescriptor, deprecated: AnnotationDescriptor): Diagnostic { - val message = deprecated.argumentValue("message") as? String ?: "" - - if (deprecated.getDeprecatedAnnotationLevel() == DeprecationLevelValue.ERROR) { - return Errors.DEPRECATION_ERROR.on(element, descriptor.original, message) + private fun createDeprecationDiagnostic(element: PsiElement, deprecation: Deprecation): Diagnostic { + val targetOriginal = deprecation.target.original + if (deprecation.deprecationLevel == DeprecationLevelValue.ERROR) { + return Errors.DEPRECATION_ERROR.on(element, targetOriginal, deprecation.message) } - return Errors.DEPRECATION.on(element, descriptor.original, message) + return Errors.DEPRECATION.on(element, targetOriginal, deprecation.message) } private val PROPERTY_SET_OPERATIONS = TokenSet.create(KtTokens.EQ, KtTokens.PLUSEQ, KtTokens.MINUSEQ, KtTokens.MULTEQ, diff --git a/compiler/testData/diagnostics/tests/deprecated/deprecatedInheritance.kt b/compiler/testData/diagnostics/tests/deprecated/deprecatedInheritance.kt new file mode 100644 index 00000000000..114ae51efe5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/deprecated/deprecatedInheritance.kt @@ -0,0 +1,140 @@ +package foo + +interface WarningDeprecated { + @Deprecated("", level = DeprecationLevel.WARNING) + fun f() { + + } +} + +interface ErrorDeprecated { + @Deprecated("", level = DeprecationLevel.ERROR) + fun f() { + + } +} + +interface HiddenDeprecated { + @Deprecated("", level = DeprecationLevel.HIDDEN) + fun f() { + + } +} + +interface NotDeprecated { + fun f() { + + } +} + +open class WE : WarningDeprecated, ErrorDeprecated { + override fun f() { + + } +} + +open class WH : WarningDeprecated, HiddenDeprecated { + override fun f() { + + } +} + +open class EH : ErrorDeprecated, HiddenDeprecated { + override fun f() { + + } +} + +open class NW : WarningDeprecated, NotDeprecated { + override fun f() { + + } +} + +open class NE : ErrorDeprecated, NotDeprecated { + override fun f() { + + } +} + +open class NH : HiddenDeprecated, NotDeprecated { + override fun f() { + + } +} + +open class WEH: WarningDeprecated, ErrorDeprecated, HiddenDeprecated { + override fun f() { + + } +} + +open class NWEH: NotDeprecated, WarningDeprecated, ErrorDeprecated, HiddenDeprecated { + override fun f() { + + } +} + +class WE2: WE() + +class NWE2: WE(), NotDeprecated + +class NWE3: WE(), NotDeprecated { + override fun f() { + } +} + +interface E2: ErrorDeprecated +interface W2: WarningDeprecated + +interface EW2: E2, W2 { + override fun f() { + } +} + +interface HEW2: EW2, HiddenDeprecated { + override fun f() { + } +} + +interface ExplicitError: HEW2 { + @Deprecated("", level = DeprecationLevel.ERROR) + override fun f() { + super.f() + } +} + +fun use( + wd: WarningDeprecated, ed: ErrorDeprecated, hd: HiddenDeprecated, + we: WE, wh: WH, eh: EH, nw: NW, ne: NE, nh: NH, + weh: WEH, nweh: NWEH, + we2: WE2, nwe2: NWE2, nwe3: NWE3, + e2: E2, w2: W2, ew2: EW2, hew2: HEW2, + explicitError: ExplicitError +) { + wd.f() + ed.f() + hd.f() + + we.f() + wh.f() + eh.f() + + nw.f() + ne.f() + nh.f() + + weh.f() + nweh.f() + + we2.f() + nwe2.f() + nwe3.f() + + e2.f() + w2.f() + ew2.f() + hew2.f() + + explicitError.f() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/deprecated/deprecatedInheritance.txt b/compiler/testData/diagnostics/tests/deprecated/deprecatedInheritance.txt new file mode 100644 index 00000000000..1663b51ed9e --- /dev/null +++ b/compiler/testData/diagnostics/tests/deprecated/deprecatedInheritance.txt @@ -0,0 +1,156 @@ +package + +package foo { + public fun use(/*0*/ wd: foo.WarningDeprecated, /*1*/ ed: foo.ErrorDeprecated, /*2*/ hd: foo.HiddenDeprecated, /*3*/ we: foo.WE, /*4*/ wh: foo.WH, /*5*/ eh: foo.EH, /*6*/ nw: foo.NW, /*7*/ ne: foo.NE, /*8*/ nh: foo.NH, /*9*/ weh: foo.WEH, /*10*/ nweh: foo.NWEH, /*11*/ we2: foo.WE2, /*12*/ nwe2: foo.NWE2, /*13*/ nwe3: foo.NWE3, /*14*/ e2: foo.E2, /*15*/ w2: foo.W2, /*16*/ ew2: foo.EW2, /*17*/ hew2: foo.HEW2, /*18*/ explicitError: foo.ExplicitError): kotlin.Unit + + public interface E2 : foo.ErrorDeprecated { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "") public open override /*1*/ /*fake_override*/ fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class EH : foo.ErrorDeprecated, foo.HiddenDeprecated { + public constructor EH() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun f(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public interface EW2 : foo.E2, foo.W2 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun f(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public interface ErrorDeprecated { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "") public open fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public interface ExplicitError : foo.HEW2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "") public open override /*1*/ fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public interface HEW2 : foo.EW2, foo.HiddenDeprecated { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun f(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public interface HiddenDeprecated { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "") public open fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class NE : foo.ErrorDeprecated, foo.NotDeprecated { + public constructor NE() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun f(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class NH : foo.HiddenDeprecated, foo.NotDeprecated { + public constructor NH() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun f(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class NW : foo.WarningDeprecated, foo.NotDeprecated { + public constructor NW() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun f(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class NWE2 : foo.WE, foo.NotDeprecated { + public constructor NWE2() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun f(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class NWE3 : foo.WE, foo.NotDeprecated { + public constructor NWE3() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun f(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class NWEH : foo.NotDeprecated, foo.WarningDeprecated, foo.ErrorDeprecated, foo.HiddenDeprecated { + public constructor NWEH() + public open override /*4*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*4*/ fun f(): kotlin.Unit + public open override /*4*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*4*/ /*fake_override*/ fun toString(): kotlin.String + } + + public interface NotDeprecated { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public interface W2 : foo.WarningDeprecated { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "") public open override /*1*/ /*fake_override*/ fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class WE : foo.WarningDeprecated, foo.ErrorDeprecated { + public constructor WE() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun f(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class WE2 : foo.WE { + public constructor WE2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class WEH : foo.WarningDeprecated, foo.ErrorDeprecated, foo.HiddenDeprecated { + public constructor WEH() + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*3*/ fun f(): kotlin.Unit + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class WH : foo.WarningDeprecated, foo.HiddenDeprecated { + public constructor WH() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun f(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public interface WarningDeprecated { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "") public open fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/testData/diagnostics/tests/deprecated/deprecatedPropertyInheritance.kt b/compiler/testData/diagnostics/tests/deprecated/deprecatedPropertyInheritance.kt new file mode 100644 index 00000000000..5c208d6b88d --- /dev/null +++ b/compiler/testData/diagnostics/tests/deprecated/deprecatedPropertyInheritance.kt @@ -0,0 +1,135 @@ +package foo + +interface HiddenDeprecated { + @Deprecated("", level = DeprecationLevel.HIDDEN) + var p: Int +} + +interface NoDeprecation { + var p: Int +} + + +open class WarningDeprecated { + @Deprecated("", level = DeprecationLevel.WARNING) + open var p: Int = 3 +} + +open class ErrorDeprecated { + @Deprecated("", level = DeprecationLevel.ERROR) + open var p: Int = 3 +} + +open class GetterDeprecated { + open var p: Int = 3 + @Deprecated("") get +} + +open class SetterDeprecated { + open var p: Int = 3 + @Deprecated("") set +} + +class WD: WarningDeprecated() { + override var p: Int + get() = 3 + set(value) {} +} + +class ED: ErrorDeprecated() { + override var p: Int + get() = 3 + set(value) { + } +} + +class GD: GetterDeprecated() { + override var p: Int + get() = 3 + set(value) { + } +} + +class SD: SetterDeprecated() { + override var p: Int + get() = 3 + set(value) { + } +} + +class SDH: SetterDeprecated(), HiddenDeprecated { + override var p: Int + get() = 3 + set(value) { + } +} + +class EDH: ErrorDeprecated(), HiddenDeprecated { + override var p: Int + get() = 3 + set(value) { + } +} + +class NED: ErrorDeprecated(), NoDeprecation { + override var p: Int + get() = 3 + set(value) { + } +} + +class Diff { + @Deprecated("", level = DeprecationLevel.WARNING) + var p: Int + @Deprecated("", level = DeprecationLevel.ERROR) get() = 3 + @Deprecated("", level = DeprecationLevel.HIDDEN) set(value) { + + } +} + +fun use( + warningDeprecated: WarningDeprecated, errorDeprecated: ErrorDeprecated, setterDeprecated: SetterDeprecated, + getterDeprecated: GetterDeprecated, hiddenDeprecated: HiddenDeprecated, + wd: WD, ed: ED, gd: GD, sd: SD, + sdh: SDH, edh: EDH, ned: NED, + diff: Diff +) { + warningDeprecated.p + warningDeprecated.p = 1 + + errorDeprecated.p + errorDeprecated.p = 1 + + getterDeprecated.p + getterDeprecated.p = 1 + + setterDeprecated.p + setterDeprecated.p = 1 + + hiddenDeprecated.p + hiddenDeprecated.p = 1 + + wd.p + wd.p = 1 + + ed.p + ed.p = 1 + + gd.p + gd.p = 1 + + sd.p + sd.p = 1 + + sdh.p + sdh.p = 1 + + edh.p + edh.p = 1 + + ned.p + ned.p = 1 + + diff.p + diff.p = 1 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/deprecated/deprecatedPropertyInheritance.txt b/compiler/testData/diagnostics/tests/deprecated/deprecatedPropertyInheritance.txt new file mode 100644 index 00000000000..52b85367b65 --- /dev/null +++ b/compiler/testData/diagnostics/tests/deprecated/deprecatedPropertyInheritance.txt @@ -0,0 +1,115 @@ +package + +package foo { + public fun use(/*0*/ warningDeprecated: foo.WarningDeprecated, /*1*/ errorDeprecated: foo.ErrorDeprecated, /*2*/ setterDeprecated: foo.SetterDeprecated, /*3*/ getterDeprecated: foo.GetterDeprecated, /*4*/ hiddenDeprecated: foo.HiddenDeprecated, /*5*/ wd: foo.WD, /*6*/ ed: foo.ED, /*7*/ gd: foo.GD, /*8*/ sd: foo.SD, /*9*/ sdh: foo.SDH, /*10*/ edh: foo.EDH, /*11*/ ned: foo.NED, /*12*/ diff: foo.Diff): kotlin.Unit + + public final class Diff { + public constructor Diff() + @kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "") public final var p: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class ED : foo.ErrorDeprecated { + public constructor ED() + public open override /*1*/ var p: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class EDH : foo.ErrorDeprecated, foo.HiddenDeprecated { + public constructor EDH() + public open override /*2*/ var p: kotlin.Int + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class ErrorDeprecated { + public constructor ErrorDeprecated() + @kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "") public open var p: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class GD : foo.GetterDeprecated { + public constructor GD() + public open override /*1*/ var p: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class GetterDeprecated { + public constructor GetterDeprecated() + public open var p: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public interface HiddenDeprecated { + @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "") public abstract var p: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class NED : foo.ErrorDeprecated, foo.NoDeprecation { + public constructor NED() + public open override /*2*/ var p: kotlin.Int + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public interface NoDeprecation { + public abstract var p: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class SD : foo.SetterDeprecated { + public constructor SD() + public open override /*1*/ var p: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class SDH : foo.SetterDeprecated, foo.HiddenDeprecated { + public constructor SDH() + public open override /*2*/ var p: kotlin.Int + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class SetterDeprecated { + public constructor SetterDeprecated() + public open var p: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class WD : foo.WarningDeprecated { + public constructor WD() + public open override /*1*/ var p: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public open class WarningDeprecated { + public constructor WarningDeprecated() + @kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "") public open var p: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 985d2f0630f..f746717f17f 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -4956,6 +4956,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("deprecatedInheritance.kt") + public void testDeprecatedInheritance() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/deprecated/deprecatedInheritance.kt"); + doTest(fileName); + } + + @TestMetadata("deprecatedPropertyInheritance.kt") + public void testDeprecatedPropertyInheritance() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/deprecated/deprecatedPropertyInheritance.kt"); + doTest(fileName); + } + @TestMetadata("functionUsage.kt") public void testFunctionUsage() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/deprecated/functionUsage.kt"); diff --git a/idea/resources/inspectionDescriptions/OverridingDeprecatedMember.html b/idea/resources/inspectionDescriptions/OverridingDeprecatedMember.html new file mode 100644 index 00000000000..54d3953197a --- /dev/null +++ b/idea/resources/inspectionDescriptions/OverridingDeprecatedMember.html @@ -0,0 +1,5 @@ + + +This inspection reports deprecated members being overridden. + + diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index dd3277f94bf..86c09967bf2 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -1270,6 +1270,14 @@ level="WARNING" /> + + + + test.kt + 15 + light_idea_test_case + + Overriding deprecated member + Overrides deprecated member in 'foo.I' + + + test.kt + 20 + light_idea_test_case + + Overriding deprecated member + Overrides deprecated member in 'foo.I' + + + test.kt + 25 + light_idea_test_case + + Overriding deprecated member + Overrides deprecated member in 'foo.I' + + + + test.kt + 31 + light_idea_test_case + + Overriding deprecated member + Overrides deprecated member in 'foo.I' + + + + test.kt + 32 + light_idea_test_case + + Overriding deprecated member + Overrides deprecated member in 'foo.I' + + + + test.kt + 30 + light_idea_test_case + + Overriding deprecated member + Overrides deprecated member in 'foo.I' + + + + test.kt + 39 + light_idea_test_case + + Overriding deprecated member + Overrides deprecated member in 'foo.I' + + diff --git a/idea/testData/inspections/overridingDeprecatedMember/inspectionData/inspections.test b/idea/testData/inspections/overridingDeprecatedMember/inspectionData/inspections.test new file mode 100644 index 00000000000..cd9b3e9457f --- /dev/null +++ b/idea/testData/inspections/overridingDeprecatedMember/inspectionData/inspections.test @@ -0,0 +1 @@ +// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.OverridingDeprecatedMemberInspection \ No newline at end of file diff --git a/idea/testData/inspections/overridingDeprecatedMember/test.kt b/idea/testData/inspections/overridingDeprecatedMember/test.kt new file mode 100644 index 00000000000..ff2fa6ebc9e --- /dev/null +++ b/idea/testData/inspections/overridingDeprecatedMember/test.kt @@ -0,0 +1,47 @@ +package foo + +interface I { + @Deprecated("") + fun f(): Int + + @Deprecated("") + var p: Int + + var i: Int + @Deprecated("") set +} + +interface II : I { + override fun f(): Int { + } +} + +interface III : I { + override fun f(): Int { + } +} + +class C : I { + override fun f(): Int { + } +} + +interface IP : I { + override var p: Int + get() = throw UnsupportedOperationException() + set(value) { + } +} + +interface IA : I { + override var i: Int + get() = throw UnsupportedOperationException() + set(value) { + } +} + +interface Explicit : I { + @Deprecated("a") + override fun f(): Int { + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java index ca5fdaca7b1..1dd319e3793 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java @@ -118,6 +118,12 @@ public class InspectionTestGenerated extends AbstractInspectionTest { doTest(fileName); } + @TestMetadata("overridingDeprecatedMember/inspectionData/inspections.test") + public void testOverridingDeprecatedMember_inspectionData_Inspections_test() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/overridingDeprecatedMember/inspectionData/inspections.test"); + doTest(fileName); + } + @TestMetadata("redundantSamConstructor/inspectionData/inspections.test") public void testRedundantSamConstructor_inspectionData_Inspections_test() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/redundantSamConstructor/inspectionData/inspections.test");