Collect all deprecations, do not stop on the first found one
#KT-15245 In Progress
This commit is contained in:
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.resolve.DeprecationLevelValue.*
|
import org.jetbrains.kotlin.resolve.DeprecationLevelValue.*
|
||||||
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import java.util.*
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
|
||||||
private val JAVA_DEPRECATED = FqName("java.lang.Deprecated")
|
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> {
|
fun DeclarationDescriptor.getDeprecations(): List<Deprecation> {
|
||||||
val deprecation = this.getDeprecationByAnnotation()
|
val deprecations = this.getDeprecationsByAnnotation()
|
||||||
if (deprecation != null) {
|
if (deprecations.isNotEmpty()) {
|
||||||
return listOf(deprecation)
|
return deprecations
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this is CallableMemberDescriptor) {
|
if (this is CallableMemberDescriptor) {
|
||||||
@@ -112,11 +112,11 @@ private fun deprecationByOverridden(root: CallableMemberDescriptor): Deprecation
|
|||||||
|
|
||||||
visited.add(node)
|
visited.add(node)
|
||||||
|
|
||||||
val deprecatedAnnotation = node.getDeprecationByAnnotation()
|
val deprecationsByAnnotation = node.getDeprecationsByAnnotation()
|
||||||
val overriddenDescriptors = node.original.overriddenDescriptors
|
val overriddenDescriptors = node.original.overriddenDescriptors
|
||||||
when {
|
when {
|
||||||
deprecatedAnnotation != null -> {
|
deprecationsByAnnotation.isNotEmpty() -> {
|
||||||
deprecations.add(deprecatedAnnotation)
|
deprecations.addAll(deprecationsByAnnotation)
|
||||||
}
|
}
|
||||||
overriddenDescriptors.isEmpty() -> {
|
overriddenDescriptors.isEmpty() -> {
|
||||||
hasUndeprecatedOverridden = true
|
hasUndeprecatedOverridden = true
|
||||||
@@ -135,58 +135,51 @@ private fun deprecationByOverridden(root: CallableMemberDescriptor): Deprecation
|
|||||||
return DeprecatedByOverridden(deprecations)
|
return DeprecatedByOverridden(deprecations)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DeclarationDescriptor.getDeprecationByAnnotation(): DeprecatedByAnnotation? {
|
private fun DeclarationDescriptor.getDeprecationsByAnnotation(): List<Deprecation> {
|
||||||
val ownAnnotation = getDeclaredDeprecatedAnnotation(AnnotationUseSiteTarget.getAssociatedUseSiteTarget(this), true)
|
if (this is TypeAliasConstructorDescriptor) {
|
||||||
if (ownAnnotation != null)
|
// Constructor of type alias has no annotations by itself, all its annotations come from the aliased constructor
|
||||||
return DeprecatedByAnnotation(ownAnnotation, this)
|
// 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) {
|
when (this) {
|
||||||
is ConstructorDescriptor -> {
|
is ConstructorDescriptor -> {
|
||||||
val classDescriptor = containingDeclaration
|
addDeprecationIfPresent(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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is PropertyAccessorDescriptor -> {
|
is PropertyAccessorDescriptor -> {
|
||||||
val propertyDescriptor = correspondingProperty
|
addDeprecationIfPresent(correspondingProperty)
|
||||||
|
|
||||||
val target = if (this is PropertyGetterDescriptor) AnnotationUseSiteTarget.PROPERTY_GETTER else AnnotationUseSiteTarget.PROPERTY_SETTER
|
addUseSiteTargetedDeprecationIfPresent(
|
||||||
val useSiteAnnotationOnProperty = propertyDescriptor.getDeclaredDeprecatedAnnotation(target, false)
|
correspondingProperty,
|
||||||
if (useSiteAnnotationOnProperty != null)
|
if (this is PropertyGetterDescriptor) AnnotationUseSiteTarget.PROPERTY_GETTER else AnnotationUseSiteTarget.PROPERTY_SETTER
|
||||||
return DeprecatedByAnnotation(useSiteAnnotationOnProperty, this)
|
)
|
||||||
|
|
||||||
val propertyAnnotation = propertyDescriptor.getDeclaredDeprecatedAnnotation()
|
|
||||||
if (propertyAnnotation != null)
|
|
||||||
return DeprecatedByAnnotation(propertyAnnotation, propertyDescriptor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun DeclarationDescriptor.getDeclaredDeprecatedAnnotation(): AnnotationDescriptor? {
|
return result.distinct()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun createDeprecationDiagnostic(element: PsiElement, deprecation: Deprecation): Diagnostic {
|
internal fun createDeprecationDiagnostic(element: PsiElement, deprecation: Deprecation): Diagnostic {
|
||||||
|
|||||||
+8
@@ -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<!>()
|
||||||
+11
@@ -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");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/deprecated/unusedImport.kt");
|
||||||
doTest(fileName);
|
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")
|
@TestMetadata("compiler/testData/diagnostics/tests/duplicateJvmSignature")
|
||||||
|
|||||||
Reference in New Issue
Block a user