[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
This commit is contained in:
Victoria.Petrakovich
2024-11-18 12:44:48 +00:00
committed by intellij-monorepo-bot
parent 263c0b768a
commit 22f1a86e61
7 changed files with 61 additions and 3 deletions
@@ -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<KaCallableSymbol>): 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"
@@ -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");
@@ -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");
@@ -1,4 +1,5 @@
class JavaChild implements KotlinBase {
// missing @Override is intentional
public String getName() {
return "";
}
@@ -0,0 +1,16 @@
// FIX: Use property access syntax
fun main() {
val w = ClassInheritingBoth()
w.<caret>getName()
}
class ClassInheritingBoth: JavaName, KotlinName {
override fun getName(): String {
return "String"
}
}
interface KotlinName {
fun getName(): String
}
@@ -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
}