[kotlin] K2 ReplaceGetOrSetInspection: make Java method calls INFORMATION level

^KTIJ-24850 Fixed

closes https://github.com/JetBrains/intellij-community/pull/2345

GitOrigin-RevId: 527e2c32194650f6d33e0f2b1d7487a9f1bee85d
This commit is contained in:
Toshiaki Kameyama
2023-03-13 20:41:42 +00:00
committed by intellij-monorepo-bot
parent 6618aeabd8
commit 5206574475
16 changed files with 179 additions and 3 deletions
@@ -1,20 +1,28 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.k2.codeinsight.inspections
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING
import com.intellij.codeInspection.ProblemHighlightType.INFORMATION
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.calls.KtSimpleFunctionCall
import org.jetbrains.kotlin.analysis.api.calls.successfulCallOrNull
import org.jetbrains.kotlin.analysis.api.calls.symbol
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtVariableLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.psiSafe
import org.jetbrains.kotlin.idea.base.psi.textRangeIn
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.codeinsight.api.applicable.inspections.AbstractKotlinApplicableInspectionWithContext
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.applicabilityRange
import org.jetbrains.kotlin.idea.codeinsights.impl.base.inspections.ReplaceGetOrSetInspectionUtils
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.psi.psiUtil.getPossiblyQualifiedCallExpression
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -24,7 +32,7 @@ internal class ReplaceGetOrSetInspection :
KtDotQualifiedExpression::class
) {
class Context(val calleeName: Name)
class Context(val calleeName: Name, val problemHighlightType: ProblemHighlightType)
override fun getProblemDescription(element: KtDotQualifiedExpression, context: Context): String =
KotlinBundle.message("explicit.0.call", context.calleeName)
@@ -38,6 +46,9 @@ internal class ReplaceGetOrSetInspection :
dotQualifiedExpression.getPossiblyQualifiedCallExpression()?.calleeExpression?.textRangeIn(dotQualifiedExpression)
}
override fun getProblemHighlightType(element: KtDotQualifiedExpression, context: Context): ProblemHighlightType =
context.problemHighlightType
override fun isApplicableByPsi(element: KtDotQualifiedExpression): Boolean =
ReplaceGetOrSetInspectionUtils.looksLikeGetOrSetOperatorCall(element)
@@ -57,7 +68,10 @@ internal class ReplaceGetOrSetInspection :
element.getPossiblyQualifiedCallExpression()?.getKtType()?.isUnit != true &&
element.isUsedAsExpression()
) return null
return Context(functionSymbol.name)
val problemHighlightType = if (functionSymbol.isExplicitOperator()) GENERIC_ERROR_OR_WARNING else INFORMATION
return Context(functionSymbol.name, problemHighlightType)
}
override fun apply(element: KtDotQualifiedExpression, context: Context, project: Project, editor: Editor?) {
@@ -67,4 +81,10 @@ internal class ReplaceGetOrSetInspection :
editor
)
}
context(KtAnalysisSession)
private fun KtFunctionSymbol.isExplicitOperator(): Boolean {
fun KtCallableSymbol.hasOperatorKeyword() = psiSafe<KtNamedFunction>()?.hasModifier(KtTokens.OPERATOR_KEYWORD) == true
return hasOperatorKeyword() || getAllOverriddenSymbols().any { it.hasOperatorKeyword() }
}
}
@@ -505,6 +505,21 @@ public abstract class K2LocalInspectionTestGenerated extends AbstractK2LocalInsp
runTest("../../../idea/tests/testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/invalidArgument.kt");
}
@TestMetadata("javaGet.kt")
public void testJavaGet() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/javaGet.kt");
}
@TestMetadata("javaSet.kt")
public void testJavaSet() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/javaSet.kt");
}
@TestMetadata("javaSet2.kt")
public void testJavaSet2() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/javaSet2.kt");
}
@TestMetadata("missingDefaultArgument.kt")
public void testMissingDefaultArgument() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/missingDefaultArgument.kt");
@@ -525,6 +540,11 @@ public abstract class K2LocalInspectionTestGenerated extends AbstractK2LocalInsp
runTest("../../../idea/tests/testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/notOperator.kt");
}
@TestMetadata("overriddenSet.kt")
public void testOverriddenSet() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/overriddenSet.kt");
}
@TestMetadata("qualifier.kt")
public void testQualifier() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/qualifier.kt");
@@ -3783,6 +3783,21 @@ public abstract class LocalInspectionTestGenerated extends AbstractLocalInspecti
runTest("testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/invalidArgument.kt");
}
@TestMetadata("javaGet.kt")
public void testJavaGet() throws Exception {
runTest("testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/javaGet.kt");
}
@TestMetadata("javaSet.kt")
public void testJavaSet() throws Exception {
runTest("testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/javaSet.kt");
}
@TestMetadata("javaSet2.kt")
public void testJavaSet2() throws Exception {
runTest("testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/javaSet2.kt");
}
@TestMetadata("missingDefaultArgument.kt")
public void testMissingDefaultArgument() throws Exception {
runTest("testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/missingDefaultArgument.kt");
@@ -3803,6 +3818,11 @@ public abstract class LocalInspectionTestGenerated extends AbstractLocalInspecti
runTest("testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/notOperator.kt");
}
@TestMetadata("overriddenSet.kt")
public void testOverriddenSet() throws Exception {
runTest("testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/overriddenSet.kt");
}
@TestMetadata("qualifier.kt")
public void testQualifier() throws Exception {
runTest("testData/inspectionsLocal/conventionNameCalls/replaceGetOrSet/qualifier.kt");
@@ -64,7 +64,7 @@
<problem>
<file>set.kt</file>
<line>8</line>
<line>9</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="set.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Explicit 'get' or 'set' call</problem_class>
@@ -79,4 +79,13 @@
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Explicit 'get' or 'set' call</problem_class>
<description>Should be replaced with indexing</description>
</problem>
<problem>
<file>overriddenSet.kt</file>
<line>19</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="overriddenSet.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Explicit 'get' or 'set' call</problem_class>
<description>Should be replaced with indexing</description>
</problem>
</problems>
@@ -0,0 +1,15 @@
public class Foo {
private int value;
public final void set(int newValue) {
value = newValue;
}
public final void set(int newValue, int oldValue) {
value = newValue;
}
public final String get(String s) {
return s;
}
}
@@ -0,0 +1,4 @@
// HIGHLIGHT: INFORMATION
fun test(foo: Foo) {
foo.get<caret>("")
}
@@ -0,0 +1,4 @@
// HIGHLIGHT: INFORMATION
fun test(foo: Foo) {
foo[""]
}
@@ -0,0 +1,15 @@
public class Foo {
private int value;
public final void set(int newValue) {
value = newValue;
}
public final void set(int newValue, int oldValue) {
value = newValue;
}
public final String get(String s) {
return s;
}
}
@@ -0,0 +1,4 @@
// PROBLEM: none
fun test(foo: Foo) {
foo.set<caret>(Int.MAX_VALUE)
}
@@ -0,0 +1,15 @@
public class Foo {
private int value;
public final void set(int newValue) {
value = newValue;
}
public final void set(int newValue, int oldValue) {
value = newValue;
}
public final String get(String s) {
return s;
}
}
@@ -0,0 +1,4 @@
// HIGHLIGHT: INFORMATION
fun test(foo: Foo) {
foo.set<caret>(Int.MAX_VALUE, Int.MAX_VALUE)
}
@@ -0,0 +1,4 @@
// HIGHLIGHT: INFORMATION
fun test(foo: Foo) {
foo[Int.MAX_VALUE] = Int.MAX_VALUE
}
@@ -0,0 +1,20 @@
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
open class A {
open operator fun set(s: String, value: Int) {}
}
open class B : A() {
override fun set(s: String, value: Int) {
super.set(s, value)
}
}
class C : B() {
override fun set(s: String, value: Int) {
super.set(s, value)
}
}
fun foo() {
C().set<caret>("x", 1)
}
@@ -0,0 +1,20 @@
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
open class A {
open operator fun set(s: String, value: Int) {}
}
open class B : A() {
override fun set(s: String, value: Int) {
super.set(s, value)
}
}
class C : B() {
override fun set(s: String, value: Int) {
super.set(s, value)
}
}
fun foo() {
C()["x"] = 1
}
@@ -1,3 +1,4 @@
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
// FIX: Replace 'set' call with indexing operator
class C {
@@ -1,3 +1,4 @@
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
// FIX: Replace 'set' call with indexing operator
class C {