Member is considered deprecated if it overrides only deprecated members

Property accessor is considered deprecated when the property is
Provide IDE inspection to strikeout members overriding deprecated members (like in java)
This commit is contained in:
Pavel V. Talanov
2016-01-12 19:28:22 +03:00
parent 9b3d97470f
commit db07d783a2
14 changed files with 871 additions and 43 deletions
@@ -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<AnnotationDescriptor, DeclarationDescriptor>? {
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>) : 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<CallableMemberDescriptor>()
val deprecations = LinkedHashSet<Deprecation>()
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
}
@@ -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,
@@ -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()
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>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.<!DEPRECATION!>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.<!DEPRECATION!>f<!>()
ed.<!DEPRECATION_ERROR!>f<!>()
hd.<!UNRESOLVED_REFERENCE!>f<!>()
we.<!DEPRECATION!>f<!>()
wh.<!DEPRECATION!>f<!>()
eh.<!DEPRECATION_ERROR!>f<!>()
nw.f()
ne.f()
nh.f()
weh.<!DEPRECATION!>f<!>()
nweh.f()
we2.<!DEPRECATION!>f<!>()
nwe2.f()
nwe3.f()
e2.<!DEPRECATION_ERROR!>f<!>()
w2.<!DEPRECATION!>f<!>()
ew2.<!DEPRECATION!>f<!>()
hew2.<!DEPRECATION!>f<!>()
explicitError.<!DEPRECATION_ERROR!>f<!>()
}
@@ -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
}
}
@@ -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.<!DEPRECATION!>p<!>
warningDeprecated.<!DEPRECATION!>p<!> = 1
errorDeprecated.<!DEPRECATION_ERROR!>p<!>
errorDeprecated.<!DEPRECATION_ERROR!>p<!> = 1
getterDeprecated.<!DEPRECATION!>p<!>
getterDeprecated.p = 1
setterDeprecated.p
setterDeprecated.<!DEPRECATION!>p<!> = 1
hiddenDeprecated.<!UNRESOLVED_REFERENCE!>p<!>
hiddenDeprecated.<!UNRESOLVED_REFERENCE!>p<!> = 1
wd.<!DEPRECATION!>p<!>
wd.<!DEPRECATION!>p<!> = 1
ed.<!DEPRECATION_ERROR!>p<!>
ed.<!DEPRECATION_ERROR!>p<!> = 1
gd.<!DEPRECATION!>p<!>
gd.p = 1
sd.p
sd.<!DEPRECATION!>p<!> = 1
sdh.p
sdh.<!DEPRECATION!>p<!> = 1
edh.<!DEPRECATION_ERROR!>p<!>
edh.<!DEPRECATION_ERROR!>p<!> = 1
ned.p
ned.p = 1
diff.<!DEPRECATION!>p<!>
diff.<!DEPRECATION, DEPRECATION!>p<!> = 1
}
@@ -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
}
}
@@ -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");
@@ -0,0 +1,5 @@
<html>
<body>
This inspection reports deprecated members being overridden.
</body>
</html>
+8
View File
@@ -1270,6 +1270,14 @@
level="WARNING"
/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.OverridingDeprecatedMemberInspection"
shortName="OverridingDeprecatedMember"
displayName="Overriding deprecated member"
groupName="Kotlin"
enabledByDefault="true"
level="WARNING"
/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.kdoc.KDocUnresolvedReferenceInspection"
displayName="Unresolved reference in KDoc"
groupName="Kotlin"
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.resolve.deprecatedByOverriddenMessage
import org.jetbrains.kotlin.resolve.getDeprecation
class OverridingDeprecatedMemberInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() {
override fun visitNamedDeclaration(declaration: KtNamedDeclaration) {
registerProblemIfNeeded(declaration, declaration.nameIdentifier ?: return)
}
override fun visitPropertyAccessor(accessor: KtPropertyAccessor) {
registerProblemIfNeeded(accessor, accessor.namePlaceholder)
}
private fun registerProblemIfNeeded(declaration: KtDeclaration, targetForProblem: PsiElement) {
val accessorDescriptor = declaration.resolveToDescriptor() as? CallableMemberDescriptor ?: return
val message = accessorDescriptor.getDeprecation()?.deprecatedByOverriddenMessage() ?: return
val problem = holder.manager.createProblemDescriptor(
targetForProblem,
message,
/* showTooltip = */ true,
ProblemHighlightType.LIKE_DEPRECATED,
isOnTheFly
)
holder.registerProblem(problem)
}
}
}
}
@@ -0,0 +1,62 @@
<problems>
<problem>
<file>test.kt</file>
<line>15</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt"/>
<problem_class severity="WARNING" attribute_key="DEPRECATED_ATTRIBUTES">Overriding deprecated member</problem_class>
<description>Overrides deprecated member in 'foo.I'</description>
</problem>
<problem>
<file>test.kt</file>
<line>20</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt"/>
<problem_class severity="WARNING" attribute_key="DEPRECATED_ATTRIBUTES">Overriding deprecated member</problem_class>
<description>Overrides deprecated member in 'foo.I'</description>
</problem>
<problem>
<file>test.kt</file>
<line>25</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt"/>
<problem_class severity="WARNING" attribute_key="DEPRECATED_ATTRIBUTES">Overriding deprecated member</problem_class>
<description>Overrides deprecated member in 'foo.I'</description>
</problem>
<problem>
<file>test.kt</file>
<line>31</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WARNING" attribute_key="DEPRECATED_ATTRIBUTES">Overriding deprecated member</problem_class>
<description>Overrides deprecated member in 'foo.I'</description>
</problem>
<problem>
<file>test.kt</file>
<line>32</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WARNING" attribute_key="DEPRECATED_ATTRIBUTES">Overriding deprecated member</problem_class>
<description>Overrides deprecated member in 'foo.I'</description>
</problem>
<problem>
<file>test.kt</file>
<line>30</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WARNING" attribute_key="DEPRECATED_ATTRIBUTES">Overriding deprecated member</problem_class>
<description>Overrides deprecated member in 'foo.I'</description>
</problem>
<problem>
<file>test.kt</file>
<line>39</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WARNING" attribute_key="DEPRECATED_ATTRIBUTES">Overriding deprecated member</problem_class>
<description>Overrides deprecated member in 'foo.I'</description>
</problem>
</problems>
@@ -0,0 +1 @@
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.OverridingDeprecatedMemberInspection
@@ -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 {
}
}
@@ -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");