Collect all deprecations, do not stop on the first found one

#KT-15245 In Progress
This commit is contained in:
Alexander Udalov
2016-12-14 14:18:49 +03:00
parent 82703d9cfd
commit 212240a008
4 changed files with 68 additions and 50 deletions
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DeprecationLevelValue.*
import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import java.util.*
import org.jetbrains.kotlin.utils.SmartList
private val JAVA_DEPRECATED = FqName("java.lang.Deprecated")
@@ -90,9 +90,9 @@ private data class DeprecatedByOverridden(private val deprecations: Collection<D
}
fun DeclarationDescriptor.getDeprecations(): List<Deprecation> {
val deprecation = this.getDeprecationByAnnotation()
if (deprecation != null) {
return listOf(deprecation)
val deprecations = this.getDeprecationsByAnnotation()
if (deprecations.isNotEmpty()) {
return deprecations
}
if (this is CallableMemberDescriptor) {
@@ -112,11 +112,11 @@ private fun deprecationByOverridden(root: CallableMemberDescriptor): Deprecation
visited.add(node)
val deprecatedAnnotation = node.getDeprecationByAnnotation()
val deprecationsByAnnotation = node.getDeprecationsByAnnotation()
val overriddenDescriptors = node.original.overriddenDescriptors
when {
deprecatedAnnotation != null -> {
deprecations.add(deprecatedAnnotation)
deprecationsByAnnotation.isNotEmpty() -> {
deprecations.addAll(deprecationsByAnnotation)
}
overriddenDescriptors.isEmpty() -> {
hasUndeprecatedOverridden = true
@@ -135,58 +135,51 @@ private fun deprecationByOverridden(root: CallableMemberDescriptor): Deprecation
return DeprecatedByOverridden(deprecations)
}
private fun DeclarationDescriptor.getDeprecationByAnnotation(): DeprecatedByAnnotation? {
val ownAnnotation = getDeclaredDeprecatedAnnotation(AnnotationUseSiteTarget.getAssociatedUseSiteTarget(this), true)
if (ownAnnotation != null)
return DeprecatedByAnnotation(ownAnnotation, this)
private fun DeclarationDescriptor.getDeprecationsByAnnotation(): List<Deprecation> {
if (this is TypeAliasConstructorDescriptor) {
// Constructor of type alias has no annotations by itself, all its annotations come from the aliased constructor
// and from the typealias declaration
return underlyingConstructorDescriptor.getDeprecationsByAnnotation() + typeAliasDescriptor.getDeprecationsByAnnotation()
}
val result = SmartList<Deprecation>()
fun addDeprecationIfPresent(target: DeclarationDescriptor) {
val annotation = target.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated)
?: target.annotations.findAnnotation(JAVA_DEPRECATED)
if (annotation != null) {
result.add(DeprecatedByAnnotation(annotation, target))
}
}
fun addUseSiteTargetedDeprecationIfPresent(annotatedDescriptor: DeclarationDescriptor, useSiteTarget: AnnotationUseSiteTarget?) {
if (useSiteTarget != null) {
val annotation = Annotations.findUseSiteTargetedAnnotation(annotatedDescriptor.annotations, useSiteTarget, KotlinBuiltIns.FQ_NAMES.deprecated)
?: Annotations.findUseSiteTargetedAnnotation(annotatedDescriptor.annotations, useSiteTarget, JAVA_DEPRECATED)
if (annotation != null) {
result.add(DeprecatedByAnnotation(annotation, this))
}
}
}
addDeprecationIfPresent(this)
addUseSiteTargetedDeprecationIfPresent(this, AnnotationUseSiteTarget.getAssociatedUseSiteTarget(this))
when (this) {
is ConstructorDescriptor -> {
val classDescriptor = containingDeclaration
val classAnnotation = classDescriptor.getDeclaredDeprecatedAnnotation()
if (classAnnotation != null)
return DeprecatedByAnnotation(classAnnotation, classDescriptor)
if (this is TypeAliasConstructorDescriptor) {
val underlyingConstructorDeprecation = underlyingConstructorDescriptor.getDeprecationByAnnotation()
if (underlyingConstructorDeprecation != null)
return underlyingConstructorDeprecation
}
addDeprecationIfPresent(containingDeclaration)
}
is PropertyAccessorDescriptor -> {
val propertyDescriptor = correspondingProperty
addDeprecationIfPresent(correspondingProperty)
val target = if (this is PropertyGetterDescriptor) AnnotationUseSiteTarget.PROPERTY_GETTER else AnnotationUseSiteTarget.PROPERTY_SETTER
val useSiteAnnotationOnProperty = propertyDescriptor.getDeclaredDeprecatedAnnotation(target, false)
if (useSiteAnnotationOnProperty != null)
return DeprecatedByAnnotation(useSiteAnnotationOnProperty, this)
val propertyAnnotation = propertyDescriptor.getDeclaredDeprecatedAnnotation()
if (propertyAnnotation != null)
return DeprecatedByAnnotation(propertyAnnotation, propertyDescriptor)
addUseSiteTargetedDeprecationIfPresent(
correspondingProperty,
if (this is PropertyGetterDescriptor) AnnotationUseSiteTarget.PROPERTY_GETTER else AnnotationUseSiteTarget.PROPERTY_SETTER
)
}
}
return null
}
private fun DeclarationDescriptor.getDeclaredDeprecatedAnnotation(): AnnotationDescriptor? {
return annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated) ?: annotations.findAnnotation(JAVA_DEPRECATED)
}
private fun DeclarationDescriptor.getDeclaredDeprecatedAnnotation(
target: AnnotationUseSiteTarget?,
findAnnotationsWithoutTarget: Boolean
): AnnotationDescriptor? {
if (findAnnotationsWithoutTarget) {
val annotations = getDeclaredDeprecatedAnnotation()
if (annotations != null) return annotations
}
if (target != null) {
return Annotations.findUseSiteTargetedAnnotation(annotations, target, KotlinBuiltIns.FQ_NAMES.deprecated)
?: Annotations.findUseSiteTargetedAnnotation(annotations, target, JAVA_DEPRECATED)
}
return null
return result.distinct()
}
internal fun createDeprecationDiagnostic(element: PsiElement, deprecation: Deprecation): Diagnostic {
@@ -0,0 +1,8 @@
// KT-15245 Report deprecation on associated declarations if level is greater than the deprecation on the declaration itself
@Deprecated("error", level = DeprecationLevel.ERROR)
class Foo @Deprecated("warning", level = DeprecationLevel.WARNING) constructor()
fun test1() = <!DEPRECATION, DEPRECATION_ERROR!>Foo<!>()
fun test2(): <!DEPRECATION_ERROR!>Foo<!> = <!DEPRECATION, DEPRECATION_ERROR!>Foo<!>()
@@ -0,0 +1,11 @@
package
public fun test1(): Foo
public fun test2(): Foo
@kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "error") public final class Foo {
@kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "warning") public constructor Foo()
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
}
@@ -6240,6 +6240,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/deprecated/unusedImport.kt");
doTest(fileName);
}
@TestMetadata("warningOnConstructorErrorOnClass.kt")
public void testWarningOnConstructorErrorOnClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/deprecated/warningOnConstructorErrorOnClass.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/tests/duplicateJvmSignature")