Check deprecated annotations with use site targets

This commit is contained in:
Yan Zhulanow
2015-08-07 16:27:59 +03:00
parent 1a477bd540
commit 9838f9c942
6 changed files with 69 additions and 10 deletions
@@ -22,6 +22,7 @@ import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
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.Errors
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.resolve.BindingTrace
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 {
private val JAVA_DEPRECATED = FqName(javaClass<Deprecated>().getName())
@@ -63,9 +67,10 @@ public class DeprecatedSymbolValidator : SymbolUsageValidator {
}
private fun DeclarationDescriptor.getDeprecatedAnnotation(): Pair<AnnotationDescriptor, DeclarationDescriptor>? {
val ownAnnotation = getDeclaredDeprecatedAnnotation()
val ownAnnotation = getDeclaredDeprecatedAnnotation(AnnotationUseSiteTarget.getAssociatedUseSiteTarget(this))
if (ownAnnotation != null)
return ownAnnotation to this
when (this) {
is ConstructorDescriptor -> {
val classDescriptor = getContainingDeclaration()
@@ -74,17 +79,39 @@ public class DeprecatedSymbolValidator : SymbolUsageValidator {
return classAnnotation to classDescriptor
}
is PropertyAccessorDescriptor -> {
val propertyDescriptor = getContainingDeclaration()
val propertyAnnotation = propertyDescriptor.getDeclaredDeprecatedAnnotation()
if (propertyAnnotation != null)
return propertyAnnotation to propertyDescriptor
val propertyDescriptor = correspondingProperty
val target = if (this is PropertyGetterDescriptor) PROPERTY_GETTER else PROPERTY_SETTER
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
}
private fun DeclarationDescriptor.getDeclaredDeprecatedAnnotation(): AnnotationDescriptor? {
return getAnnotations().findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated) ?: getAnnotations().findAnnotation(JAVA_DEPRECATED)
private fun DeclarationDescriptor.getDeclaredDeprecatedAnnotation(
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 {
@@ -11,6 +11,6 @@ public class A {
// 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<!>)
}
@@ -9,7 +9,7 @@ kotlin.deprecated(value = "Deprecated in Java") public open class 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
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
@@ -1026,7 +1026,19 @@ public class KotlinBuiltIns {
}
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;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -16,6 +16,8 @@
package org.jetbrains.kotlin.descriptors.annotations
import org.jetbrains.kotlin.descriptors.*
public enum class AnnotationUseSiteTarget(renderName: String? = null) {
FIELD(),
FILE(),
@@ -27,4 +29,14 @@ public enum class AnnotationUseSiteTarget(renderName: String? = null) {
SETTER_PARAMETER("sparam");
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
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.name.FqName
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.
public fun getAllAnnotations(): List<AnnotationWithTarget>