From 22f1a86e6181771f564661d38a0ea191e1999fb4 Mon Sep 17 00:00:00 2001 From: "Victoria.Petrakovich" Date: Wed, 13 Nov 2024 17:26:37 +0100 Subject: [PATCH] [kotlin] Fix checking a method to have a Java origin in overridden symbols If a method overrides some Java method and that method is not overridden with anything else, it means that this method originates from Java. In comparison to the previous wrong implementation, for the case `class ClassInheritingBoth: JavaName, KotlinName` the current implementation works regardless of the order of implemented interfaces `JavaName`, `KotlinName`. ^KTIJ-30819 Fixed (cherry picked from commit eb262ccbf0c4c38248a260130d58316fa7a8bb65) IJ-CR-148612 GitOrigin-RevId: 12a28f209e160b02d0e87e4af813c373a4f193a9 --- .../UsePropertyAccessSyntaxInspection.kt | 18 +++++++++++++++--- .../tests/K2LocalInspectionTestGenerated.java | 5 +++++ .../LocalInspectionTestGenerated.java | 5 +++++ ...eplaceImplicitOverrideOfKotlinMethod.1.java | 1 + .../replaceWhenMultipleInheritance.1.java | 3 +++ .../replaceWhenMultipleInheritance.kt | 16 ++++++++++++++++ .../replaceWhenMultipleInheritance.kt.after | 16 ++++++++++++++++ 7 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.1.java create mode 100644 plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.kt create mode 100644 plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.kt.after diff --git a/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/UsePropertyAccessSyntaxInspection.kt b/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/UsePropertyAccessSyntaxInspection.kt index 1dc3815ba482..d65f456a321e 100644 --- a/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/UsePropertyAccessSyntaxInspection.kt +++ b/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/UsePropertyAccessSyntaxInspection.kt @@ -405,9 +405,7 @@ class UsePropertyAccessSyntaxInspection : LocalInspectionTool(), CleanupLocalIns propertyName: String ): Boolean { val allOverriddenSymbols = symbol.allOverriddenSymbolsWithSelf.toList() - // allOverriddenSymbolsWithSelf is a sequence, and if the last element in the list it forms is not a Java symbol, - // then it means it's not for our inspection. This list can't be empty because it contains the `symbol` itself - if (!allOverriddenSymbols.last().origin.isJavaSourceOrLibrary()) return false + if (!functionOriginateFromJava(allOverriddenSymbols)) return false if (functionOrItsAncestorIsInNotPropertiesList(allOverriddenSymbols, callExpression)) return false // Check that the receiver or its ancestors don't have public fields with the same name as the probable synthetic property @@ -573,6 +571,20 @@ class UsePropertyAccessSyntaxInspection : LocalInspectionTool(), CleanupLocalIns return false } + context(KaSession) + private fun functionOriginateFromJava(allOverriddenSymbols: List): Boolean { + // Calling `.reversed()` – small optimization because the last Java symbol in the list more probable doesn't have overrides + val javaSymbols = allOverriddenSymbols.filter { it.origin.isJavaSourceOrLibrary() }.reversed() + if (javaSymbols.isEmpty()) return false + for (javaSymbol in javaSymbols) { + if (javaSymbol.allOverriddenSymbols.toList().isEmpty()) { + // Nothing overrides it, true Java origin + return true + } + } + return false + } + /** * Check if this set() is used after `return` * Covered with the test "dontReplaceSetterIfItGoesAfterReturn" diff --git a/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/inspections/tests/K2LocalInspectionTestGenerated.java b/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/inspections/tests/K2LocalInspectionTestGenerated.java index 0e771dd8804f..1c96761f77ac 100644 --- a/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/inspections/tests/K2LocalInspectionTestGenerated.java +++ b/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/inspections/tests/K2LocalInspectionTestGenerated.java @@ -6555,6 +6555,11 @@ public abstract class K2LocalInspectionTestGenerated extends AbstractK2LocalInsp runTest("../../../idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceSetterToIsSetter.kt"); } + @TestMetadata("replaceWhenMultipleInheritance.kt") + public void testReplaceWhenMultipleInheritance() throws Exception { + runTest("../../../idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.kt"); + } + @TestMetadata("replaceWithBackticks.kt") public void testReplaceWithBackticks() throws Exception { runTest("../../../idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWithBackticks.kt"); diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 935acb92cd53..d7afc6c5157f 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -19477,6 +19477,11 @@ public abstract class LocalInspectionTestGenerated extends AbstractLocalInspecti runTest("testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceSetterToIsSetter.kt"); } + @TestMetadata("replaceWhenMultipleInheritance.kt") + public void testReplaceWhenMultipleInheritance() throws Exception { + runTest("testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.kt"); + } + @TestMetadata("replaceWithBackticks.kt") public void testReplaceWithBackticks() throws Exception { runTest("testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWithBackticks.kt"); diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/dontReplaceImplicitOverrideOfKotlinMethod.1.java b/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/dontReplaceImplicitOverrideOfKotlinMethod.1.java index 44c5218838e1..be3c9231e307 100644 --- a/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/dontReplaceImplicitOverrideOfKotlinMethod.1.java +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/dontReplaceImplicitOverrideOfKotlinMethod.1.java @@ -1,4 +1,5 @@ class JavaChild implements KotlinBase { + // missing @Override is intentional public String getName() { return ""; } diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.1.java b/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.1.java new file mode 100644 index 000000000000..c6aa7c957ace --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.1.java @@ -0,0 +1,3 @@ +public interface JavaName { + String getName(); +} diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.kt b/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.kt new file mode 100644 index 000000000000..0ebd4f173fa1 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.kt @@ -0,0 +1,16 @@ +// FIX: Use property access syntax +fun main() { + val w = ClassInheritingBoth() + w.getName() +} + +class ClassInheritingBoth: JavaName, KotlinName { + + override fun getName(): String { + return "String" + } +} + +interface KotlinName { + fun getName(): String +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.kt.after b/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.kt.after new file mode 100644 index 000000000000..1456e483666c --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/usePropertyAccessSyntax/dotQualifiedExpressions/replaceWhenMultipleInheritance.kt.after @@ -0,0 +1,16 @@ +// FIX: Use property access syntax +fun main() { + val w = ClassInheritingBoth() + w.name +} + +class ClassInheritingBoth: JavaName, KotlinName { + + override fun getName(): String { + return "String" + } +} + +interface KotlinName { + fun getName(): String +} \ No newline at end of file