From 0694ee50a3e2e2aca288bb4d6618c36c1784031a Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Fri, 28 Jul 2023 19:56:10 +0200 Subject: [PATCH] K1: Report deprecation on synthetic properties for NOT_CONSIDERED JDK members Currently, for other synthetic properties, deprecation from the original method is already being propagated to the relevant new synthetic property accessor. But what we need is also reporting warnings on synthetic properties accessors call-sites if original methods are considered deprecated as a result of deprecation propagation. KT-60659 Fixed ^KT-60769 Fixed --- ...CompilerTestFE10TestdataTestGenerated.java | 12 ++++ ...sticCompilerFE10TestDataTestGenerated.java | 12 ++++ ...eeOldFrontendDiagnosticsTestGenerated.java | 12 ++++ ...siOldFrontendDiagnosticsTestGenerated.java | 12 ++++ .../deprecation/DeprecationResolver.kt | 61 +++++++++++++------ .../doNotMarkWriteIfGetterDeprecated.fir.kt | 51 ++++++++++++++++ .../doNotMarkWriteIfGetterDeprecated.kt | 51 ++++++++++++++++ .../forSyntheticPropertyOverrides.kt | 40 ++++++++++++ .../implementationsForSequencedCollection.kt | 8 +-- .../testsWithJdk21/newListMethods.kt | 8 +-- .../test/runners/DiagnosticTestGenerated.java | 12 ++++ 11 files changed, 252 insertions(+), 27 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.fir.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/deprecations/forSyntheticPropertyOverrides.kt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index bd66f4fb323..d82dadac802 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -20745,6 +20745,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/j+k/deprecations"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); } + @Test + @TestMetadata("doNotMarkWriteIfGetterDeprecated.kt") + public void testDoNotMarkWriteIfGetterDeprecated() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.kt"); + } + @Test @TestMetadata("forFakeOverrides.kt") public void testForFakeOverrides() throws Exception { @@ -20762,6 +20768,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia public void testForOverrides() throws Exception { runTest("compiler/testData/diagnostics/tests/j+k/deprecations/forOverrides.kt"); } + + @Test + @TestMetadata("forSyntheticPropertyOverrides.kt") + public void testForSyntheticPropertyOverrides() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/deprecations/forSyntheticPropertyOverrides.kt"); + } } @Nested diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index fe8cf605482..a92aaa56950 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -20745,6 +20745,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/j+k/deprecations"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); } + @Test + @TestMetadata("doNotMarkWriteIfGetterDeprecated.kt") + public void testDoNotMarkWriteIfGetterDeprecated() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.kt"); + } + @Test @TestMetadata("forFakeOverrides.kt") public void testForFakeOverrides() throws Exception { @@ -20762,6 +20768,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated public void testForOverrides() throws Exception { runTest("compiler/testData/diagnostics/tests/j+k/deprecations/forOverrides.kt"); } + + @Test + @TestMetadata("forSyntheticPropertyOverrides.kt") + public void testForSyntheticPropertyOverrides() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/deprecations/forSyntheticPropertyOverrides.kt"); + } } @Nested diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index 4540ce58637..52def70f5ac 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -20745,6 +20745,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/j+k/deprecations"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); } + @Test + @TestMetadata("doNotMarkWriteIfGetterDeprecated.kt") + public void testDoNotMarkWriteIfGetterDeprecated() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.kt"); + } + @Test @TestMetadata("forFakeOverrides.kt") public void testForFakeOverrides() throws Exception { @@ -20762,6 +20768,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir public void testForOverrides() throws Exception { runTest("compiler/testData/diagnostics/tests/j+k/deprecations/forOverrides.kt"); } + + @Test + @TestMetadata("forSyntheticPropertyOverrides.kt") + public void testForSyntheticPropertyOverrides() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/deprecations/forSyntheticPropertyOverrides.kt"); + } } @Nested diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index db7311f0593..2831d114413 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -20751,6 +20751,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/j+k/deprecations"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); } + @Test + @TestMetadata("doNotMarkWriteIfGetterDeprecated.kt") + public void testDoNotMarkWriteIfGetterDeprecated() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.kt"); + } + @Test @TestMetadata("forFakeOverrides.kt") public void testForFakeOverrides() throws Exception { @@ -20768,6 +20774,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia public void testForOverrides() throws Exception { runTest("compiler/testData/diagnostics/tests/j+k/deprecations/forOverrides.kt"); } + + @Test + @TestMetadata("forSyntheticPropertyOverrides.kt") + public void testForSyntheticPropertyOverrides() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/deprecations/forSyntheticPropertyOverrides.kt"); + } } @Nested diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecation/DeprecationResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecation/DeprecationResolver.kt index 430c70bb5a5..f6323a6acd9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecation/DeprecationResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecation/DeprecationResolver.kt @@ -39,27 +39,50 @@ class DeprecationResolver( ) { private val deprecations: MemoizedFunctionToNotNull = storageManager.createMemoizedFunction { descriptor -> - val deprecations = descriptor.getOwnDeprecations() - when { - deprecations.isNotEmpty() -> DeprecationInfo(deprecations, hasInheritedDeprecations = false) - descriptor is CallableMemberDescriptor -> { - val inheritedDeprecations = listOfNotNull(deprecationByOverridden(descriptor)) - when (inheritedDeprecations.isNotEmpty()) { - true -> when (languageVersionSettings.supportsFeature(LanguageFeature.StopPropagatingDeprecationThroughOverrides)) { - true -> DeprecationInfo( - inheritedDeprecations.filter { it.forcePropagationToOverrides }, - hasInheritedDeprecations = true, - inheritedDeprecations - ) - false -> DeprecationInfo(inheritedDeprecations, hasInheritedDeprecations = true) - } - false -> DeprecationInfo.EMPTY - } - } - else -> DeprecationInfo.EMPTY - } + computeDeprecation(descriptor) } + private fun computeDeprecation(descriptor: DeclarationDescriptor): DeprecationInfo { + val deprecations = descriptor.getOwnDeprecations() + return when { + deprecations.isNotEmpty() -> DeprecationInfo(deprecations, hasInheritedDeprecations = false) + descriptor is PropertyAccessorDescriptor && descriptor.correspondingProperty is SyntheticPropertyDescriptor -> { + val syntheticProperty = descriptor.correspondingProperty as SyntheticPropertyDescriptor + val originalMethod = + if (descriptor is PropertyGetterDescriptor) syntheticProperty.getMethod else syntheticProperty.setMethod + + @Suppress("FoldInitializerAndIfToElvis") // Wait until KTIJ-26450 is fixed + if (originalMethod == null) return DeprecationInfo.EMPTY + val originalMethodDeprecationInfo = deprecations(originalMethod) + + // Limiting these new (they didn't exist before 1.9.10) deprecations only to WARNING and forcePropagationToOverrides + // (i.e., for overrides of NOT_CONSIDERED JDK members) + // is deliberate once we would like to reduce the scope of affected usages because otherwise + // it might be a big unexpected breaking change for users who are enabled -Werror flag. + val filteredDeprecations = + originalMethodDeprecationInfo.deprecations.filter { + it.deprecationLevel == DeprecationLevelValue.WARNING && it.forcePropagationToOverrides + } + return originalMethodDeprecationInfo.copy(deprecations = filteredDeprecations) + } + descriptor is CallableMemberDescriptor -> { + val inheritedDeprecations = listOfNotNull(deprecationByOverridden(descriptor)) + when (inheritedDeprecations.isNotEmpty()) { + true -> when (languageVersionSettings.supportsFeature(LanguageFeature.StopPropagatingDeprecationThroughOverrides)) { + true -> DeprecationInfo( + inheritedDeprecations.filter { it.forcePropagationToOverrides }, + hasInheritedDeprecations = true, + inheritedDeprecations + ) + false -> DeprecationInfo(inheritedDeprecations, hasInheritedDeprecations = true) + } + false -> DeprecationInfo.EMPTY + } + } + else -> DeprecationInfo.EMPTY + } + } + private data class DeprecationInfo( val deprecations: List, val hasInheritedDeprecations: Boolean, diff --git a/compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.fir.kt b/compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.fir.kt new file mode 100644 index 00000000000..210df54a3a1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.fir.kt @@ -0,0 +1,51 @@ +// LANGUAGE: -StopPropagatingDeprecationThroughOverrides +// FILE: JavaClass.java + +public class JavaClass { + @Deprecated + public String getFoo() { return ""; } + public void setFoo(String x) {} +} + +// FILE: main.kt + +open class KotlinClass : JavaClass() { + @Deprecated("") + override fun getFoo(): String { + return super.getFoo() + } + + override fun setFoo(x: String?) { + super.setFoo(x) + } +} + +class KotlinSubClass : KotlinClass() { + override fun getFoo(): String { + return super.getFoo() + } + + override fun setFoo(x: String?) { + super.setFoo(x) + } +} + +fun main(j: JavaClass, k: KotlinClass, ks: KotlinSubClass) { + j.getFoo() + j.setFoo("") + + j.foo + j.foo = "" + + k.getFoo() + k.setFoo("") + + k.foo + k.foo = "" + + ks.getFoo() + ks.setFoo("") + + ks.foo + ks.foo = "" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.kt b/compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.kt new file mode 100644 index 00000000000..96e21f2f9ea --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.kt @@ -0,0 +1,51 @@ +// LANGUAGE: -StopPropagatingDeprecationThroughOverrides +// FILE: JavaClass.java + +public class JavaClass { + @Deprecated + public String getFoo() { return ""; } + public void setFoo(String x) {} +} + +// FILE: main.kt + +open class KotlinClass : JavaClass() { + @Deprecated("") + override fun getFoo(): String { + return super.getFoo() + } + + override fun setFoo(x: String?) { + super.setFoo(x) + } +} + +class KotlinSubClass : KotlinClass() { + override fun getFoo(): String { + return super.getFoo() + } + + override fun setFoo(x: String?) { + super.setFoo(x) + } +} + +fun main(j: JavaClass, k: KotlinClass, ks: KotlinSubClass) { + j.getFoo() + j.setFoo("") + + j.foo + j.foo = "" + + k.getFoo() + k.setFoo("") + + k.foo + k.foo = "" + + ks.getFoo() + ks.setFoo("") + + ks.foo + ks.foo = "" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/j+k/deprecations/forSyntheticPropertyOverrides.kt b/compiler/testData/diagnostics/tests/j+k/deprecations/forSyntheticPropertyOverrides.kt new file mode 100644 index 00000000000..d047b79caf7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/deprecations/forSyntheticPropertyOverrides.kt @@ -0,0 +1,40 @@ +// FIR_IDENTICAL +// LANGUAGE: -StopPropagatingDeprecationThroughOverrides +// FILE: JavaClass.java + +public class JavaClass { + public String getFoo() { return ""; } + public String getBar() { return ""; } +} + +// FILE: main.kt + +open class KotlinClass : JavaClass() { + @Deprecated("sdas") + override fun getFoo(): String { + return super.getFoo() + } + + @Deprecated("dasd", level = DeprecationLevel.ERROR) + override fun getBar(): String { + return super.getBar() + } +} + +class KotlinSubClass : KotlinClass() { + override fun getFoo(): String { + return super.getFoo() + } + + override fun getBar(): String { + return super.getBar() + } +} + +fun main(kotlinClass: KotlinClass, kotlinSubClass: KotlinSubClass) { + kotlinClass.foo + kotlinClass.bar + + kotlinSubClass.foo + kotlinSubClass.bar +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJdk21/implementationsForSequencedCollection.kt b/compiler/testData/diagnostics/testsWithJdk21/implementationsForSequencedCollection.kt index c31bb0cce3e..0eeb0376861 100644 --- a/compiler/testData/diagnostics/testsWithJdk21/implementationsForSequencedCollection.kt +++ b/compiler/testData/diagnostics/testsWithJdk21/implementationsForSequencedCollection.kt @@ -4,10 +4,10 @@ fun foo(ll: java.util.LinkedList, al: ArrayList, ad: ArrayDeque< ll.addFirst("") ll.addLast("") ll.getFirst() - ll.first // synthetic property for getFirst() + ll.first // synthetic property for getFirst() ll.first() // stdlib extension on List ll.getLast() - ll.last + ll.last ll.last() ll.removeFirst() ll.removeLast() @@ -16,10 +16,10 @@ fun foo(ll: java.util.LinkedList, al: ArrayList, ad: ArrayDeque< al.addFirst("") al.addLast("") al.getFirst() - al.first + al.first al.first() al.getLast() - al.last + al.last al.last() al.removeFirst() al.removeLast() diff --git a/compiler/testData/diagnostics/testsWithJdk21/newListMethods.kt b/compiler/testData/diagnostics/testsWithJdk21/newListMethods.kt index 9913816cda5..a5f58bb0087 100644 --- a/compiler/testData/diagnostics/testsWithJdk21/newListMethods.kt +++ b/compiler/testData/diagnostics/testsWithJdk21/newListMethods.kt @@ -35,10 +35,10 @@ fun foo(x: MutableList, y: ArrayList, z: A) { y.addFirst("") y.addLast("") y.getFirst() - y.first + y.first y.first() y.getLast() - y.last + y.last y.last() y.removeFirst() y.removeLast() @@ -47,10 +47,10 @@ fun foo(x: MutableList, y: ArrayList, z: A) { z.addFirst("") z.addLast("") z.getFirst() - z.first + z.first z.first() z.getLast() - z.last + z.last z.last() z.removeFirst() z.removeLast() diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index cdd8152ed7d..833fb0ad8df 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -20751,6 +20751,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/j+k/deprecations"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true); } + @Test + @TestMetadata("doNotMarkWriteIfGetterDeprecated.kt") + public void testDoNotMarkWriteIfGetterDeprecated() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/deprecations/doNotMarkWriteIfGetterDeprecated.kt"); + } + @Test @TestMetadata("forFakeOverrides.kt") public void testForFakeOverrides() throws Exception { @@ -20768,6 +20774,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { public void testForOverrides() throws Exception { runTest("compiler/testData/diagnostics/tests/j+k/deprecations/forOverrides.kt"); } + + @Test + @TestMetadata("forSyntheticPropertyOverrides.kt") + public void testForSyntheticPropertyOverrides() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/deprecations/forSyntheticPropertyOverrides.kt"); + } } @Nested