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