Check deprecated annotations with use site targets
This commit is contained in:
+34
-7
@@ -22,6 +22,7 @@ import com.intellij.psi.util.PsiTreeUtil
|
|||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
@@ -29,6 +30,9 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.PROPERTY_GETTER
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.PROPERTY_SETTER
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
|
||||||
public class DeprecatedSymbolValidator : SymbolUsageValidator {
|
public class DeprecatedSymbolValidator : SymbolUsageValidator {
|
||||||
private val JAVA_DEPRECATED = FqName(javaClass<Deprecated>().getName())
|
private val JAVA_DEPRECATED = FqName(javaClass<Deprecated>().getName())
|
||||||
@@ -63,9 +67,10 @@ public class DeprecatedSymbolValidator : SymbolUsageValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun DeclarationDescriptor.getDeprecatedAnnotation(): Pair<AnnotationDescriptor, DeclarationDescriptor>? {
|
private fun DeclarationDescriptor.getDeprecatedAnnotation(): Pair<AnnotationDescriptor, DeclarationDescriptor>? {
|
||||||
val ownAnnotation = getDeclaredDeprecatedAnnotation()
|
val ownAnnotation = getDeclaredDeprecatedAnnotation(AnnotationUseSiteTarget.getAssociatedUseSiteTarget(this))
|
||||||
if (ownAnnotation != null)
|
if (ownAnnotation != null)
|
||||||
return ownAnnotation to this
|
return ownAnnotation to this
|
||||||
|
|
||||||
when (this) {
|
when (this) {
|
||||||
is ConstructorDescriptor -> {
|
is ConstructorDescriptor -> {
|
||||||
val classDescriptor = getContainingDeclaration()
|
val classDescriptor = getContainingDeclaration()
|
||||||
@@ -74,17 +79,39 @@ public class DeprecatedSymbolValidator : SymbolUsageValidator {
|
|||||||
return classAnnotation to classDescriptor
|
return classAnnotation to classDescriptor
|
||||||
}
|
}
|
||||||
is PropertyAccessorDescriptor -> {
|
is PropertyAccessorDescriptor -> {
|
||||||
val propertyDescriptor = getContainingDeclaration()
|
val propertyDescriptor = correspondingProperty
|
||||||
val propertyAnnotation = propertyDescriptor.getDeclaredDeprecatedAnnotation()
|
|
||||||
if (propertyAnnotation != null)
|
val target = if (this is PropertyGetterDescriptor) PROPERTY_GETTER else PROPERTY_SETTER
|
||||||
return propertyAnnotation to propertyDescriptor
|
val accessorAnnotation = propertyDescriptor.getDeclaredDeprecatedAnnotation(target, false)
|
||||||
|
if (accessorAnnotation != null)
|
||||||
|
return accessorAnnotation to this
|
||||||
|
|
||||||
|
val classDescriptor = containingDeclaration as? ClassDescriptor
|
||||||
|
if (classDescriptor != null && classDescriptor.isCompanionObject) {
|
||||||
|
val classAnnotation = classDescriptor.getDeclaredDeprecatedAnnotation()
|
||||||
|
if (classAnnotation != null)
|
||||||
|
return classAnnotation to classDescriptor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DeclarationDescriptor.getDeclaredDeprecatedAnnotation(): AnnotationDescriptor? {
|
private fun DeclarationDescriptor.getDeclaredDeprecatedAnnotation(
|
||||||
return getAnnotations().findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated) ?: getAnnotations().findAnnotation(JAVA_DEPRECATED)
|
target: AnnotationUseSiteTarget? = null,
|
||||||
|
findAnnotationsWithoutTarget: Boolean = true
|
||||||
|
): AnnotationDescriptor? {
|
||||||
|
if (findAnnotationsWithoutTarget) {
|
||||||
|
val annotations = annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated) ?: annotations.findAnnotation(JAVA_DEPRECATED)
|
||||||
|
if (annotations != null) return annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target != null) {
|
||||||
|
return Annotations.Companion.findUseSiteTargetedAnnotation(annotations, target, KotlinBuiltIns.FQ_NAMES.deprecated)
|
||||||
|
?: Annotations.Companion.findUseSiteTargetedAnnotation(annotations, target, JAVA_DEPRECATED)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDeprecationDiagnostic(element: PsiElement, descriptor: DeclarationDescriptor, deprecated: AnnotationDescriptor): Diagnostic {
|
private fun createDeprecationDiagnostic(element: PsiElement, descriptor: DeclarationDescriptor, deprecated: AnnotationDescriptor): Diagnostic {
|
||||||
|
|||||||
@@ -11,6 +11,6 @@ public class A {
|
|||||||
|
|
||||||
// FILE: B.kt
|
// FILE: B.kt
|
||||||
|
|
||||||
class B(private @deprecated val foo: String) : <!DEPRECATED_SYMBOL_WITH_MESSAGE!>A<!>() {
|
class B(private @property:deprecated val foo: String) : <!DEPRECATED_SYMBOL_WITH_MESSAGE!>A<!>() {
|
||||||
override fun getFoo(text: String): String = super.<!DEPRECATED_SYMBOL_WITH_MESSAGE!>getFoo<!>(text + <!DEPRECATED_SYMBOL!>foo<!>)
|
override fun getFoo(text: String): String = super.<!DEPRECATED_SYMBOL_WITH_MESSAGE!>getFoo<!>(text + <!DEPRECATED_SYMBOL!>foo<!>)
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ kotlin.deprecated(value = "Deprecated in Java") public open class A {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal final class B : A {
|
internal final class B : A {
|
||||||
public constructor B(/*0*/ kotlin.deprecated() foo: kotlin.String)
|
public constructor B(/*0*/ foo: kotlin.String)
|
||||||
kotlin.deprecated() private final val foo: kotlin.String
|
kotlin.deprecated() private final val foo: kotlin.String
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open override /*1*/ fun getFoo(/*0*/ text: kotlin.String): kotlin.String
|
public open override /*1*/ fun getFoo(/*0*/ text: kotlin.String): kotlin.String
|
||||||
|
|||||||
@@ -1026,7 +1026,19 @@ public class KotlinBuiltIns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean containsAnnotation(DeclarationDescriptor descriptor, FqName annotationClassFqName) {
|
private static boolean containsAnnotation(DeclarationDescriptor descriptor, FqName annotationClassFqName) {
|
||||||
return descriptor.getOriginal().getAnnotations().findAnnotation(annotationClassFqName) != null;
|
DeclarationDescriptor original = descriptor.getOriginal();
|
||||||
|
Annotations annotations = original.getAnnotations();
|
||||||
|
|
||||||
|
if (annotations.findAnnotation(annotationClassFqName) != null) return true;
|
||||||
|
|
||||||
|
AnnotationUseSiteTarget associatedUseSiteTarget = AnnotationUseSiteTarget.Companion.getAssociatedUseSiteTarget(descriptor);
|
||||||
|
if (associatedUseSiteTarget != null) {
|
||||||
|
if (annotations.findUseSiteTargetedAnnotation(associatedUseSiteTarget, annotationClassFqName) != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
+12
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors.annotations
|
package org.jetbrains.kotlin.descriptors.annotations
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
|
||||||
public enum class AnnotationUseSiteTarget(renderName: String? = null) {
|
public enum class AnnotationUseSiteTarget(renderName: String? = null) {
|
||||||
FIELD(),
|
FIELD(),
|
||||||
FILE(),
|
FILE(),
|
||||||
@@ -27,4 +29,14 @@ public enum class AnnotationUseSiteTarget(renderName: String? = null) {
|
|||||||
SETTER_PARAMETER("sparam");
|
SETTER_PARAMETER("sparam");
|
||||||
|
|
||||||
public val renderName: String = renderName ?: name().toLowerCase()
|
public val renderName: String = renderName ?: name().toLowerCase()
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public fun getAssociatedUseSiteTarget(descriptor: DeclarationDescriptor): AnnotationUseSiteTarget? = when (descriptor) {
|
||||||
|
is PropertyDescriptor -> PROPERTY
|
||||||
|
is ValueParameterDescriptor -> CONSTRUCTOR_PARAMETER
|
||||||
|
is PropertyGetterDescriptor -> PROPERTY_GETTER
|
||||||
|
is PropertySetterDescriptor -> PROPERTY_SETTER
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors.annotations
|
package org.jetbrains.kotlin.descriptors.annotations
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
|
||||||
@@ -38,6 +39,13 @@ public interface Annotations : Iterable<AnnotationDescriptor> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun findUseSiteTargetedAnnotation(target: AnnotationUseSiteTarget, fqName: FqName): AnnotationDescriptor? {
|
||||||
|
return getUseSiteTargetedAnnotations(target).firstOrNull {
|
||||||
|
val descriptor = it.type.constructor.declarationDescriptor
|
||||||
|
descriptor is ClassDescriptor && fqName.toUnsafe() == DescriptorUtils.getFqName(descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Returns both targeted and annotations without target. Annotation order is preserved.
|
// Returns both targeted and annotations without target. Annotation order is preserved.
|
||||||
public fun getAllAnnotations(): List<AnnotationWithTarget>
|
public fun getAllAnnotations(): List<AnnotationWithTarget>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user