[kotlin] Port ReplaceWithClassJavaFix and ReplaceWithCompanionClassJavaFix to K2

These quick fixes are for the JAVA_CLASS_ON_COMPANION compiler warning.

#KTIJ-29616 Fixed
#KTIJ-29600 Fixed

GitOrigin-RevId: 956e66b0f6fc7089e83b63305282ad0f2b3b424b
This commit is contained in:
Andrey Cherkasov
2025-04-07 20:04:46 +00:00
committed by intellij-monorepo-bot
parent 1a82af9448
commit 1a6b73e52b
18 changed files with 176 additions and 15 deletions
@@ -0,0 +1,75 @@
// Copyright 2000-2025 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.fixes
import com.intellij.codeInsight.intention.PriorityAction
import com.intellij.codeInspection.util.IntentionFamilyName
import com.intellij.modcommand.ActionContext
import com.intellij.modcommand.ModPsiUpdater
import com.intellij.modcommand.Presentation
import com.intellij.modcommand.PsiUpdateModCommandAction
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KaFirDiagnostic
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KotlinQuickFixFactory
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.createExpressionByPattern
internal object JavaClassOnCompanionFixFactories {
val factory = KotlinQuickFixFactory { diagnostic: KaFirDiagnostic.JavaClassOnCompanion ->
val element = diagnostic.psi as? KtDotQualifiedExpression ?: return@KotlinQuickFixFactory emptyList()
val elementContext = (element.receiverExpression.mainReference?.resolve() as? KtObjectDeclaration)?.name
?: SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT.identifier
listOf(
ReplaceWithCompanionClassJavaFix(element, elementContext),
ReplaceWithClassJavaFix(element)
)
}
}
private class ReplaceWithCompanionClassJavaFix(
element: KtDotQualifiedExpression,
private val companionName: String,
) : PsiUpdateModCommandAction<KtDotQualifiedExpression>(element) {
override fun getFamilyName(): @IntentionFamilyName String =
KotlinBundle.message("replace.with.0", "Companion::class.java")
override fun getPresentation(context: ActionContext, element: KtDotQualifiedExpression): Presentation =
Presentation.of(KotlinBundle.message("replace.with.0", "$companionName::class.java"))
override fun invoke(
actionContext: ActionContext,
element: KtDotQualifiedExpression,
updater: ModPsiUpdater,
) {
val psiFactory = KtPsiFactory(actionContext.project)
element.replace(
psiFactory.createExpressionByPattern("$0.$companionName::class.java", element.receiverExpression)
)
}
}
private class ReplaceWithClassJavaFix(
element: KtDotQualifiedExpression,
) : PsiUpdateModCommandAction<KtDotQualifiedExpression>(element) {
override fun getFamilyName(): @IntentionFamilyName String =
KotlinBundle.message("replace.with.0", "::class.java")
override fun getPresentation(context: ActionContext, element: KtDotQualifiedExpression): Presentation =
Presentation.of(familyName).withPriority(PriorityAction.Priority.LOW)
override fun invoke(
context: ActionContext,
element: KtDotQualifiedExpression,
updater: ModPsiUpdater,
) {
val psiFactory = KtPsiFactory(context.project)
element.replace(
psiFactory.createExpressionByPattern("$0::class.java", element.receiverExpression)
)
}
}
@@ -185,6 +185,7 @@ class KotlinK2QuickFixRegistrar : KotlinQuickFixRegistrar() {
registerFactory(AddSemicolonBeforeLambdaExpressionFixFactory.addSemicolonBeforeLambdaExpressionFixFactory)
registerFactory(AbstractSuperCallFixFactories.errorFixFactory)
registerFactory(AbstractSuperCallFixFactories.warningFactory)
registerFactory(JavaClassOnCompanionFixFactories.factory)
}
private val addAbstract = KtQuickFixesListBuilder.registerPsiQuickFix {
@@ -10845,7 +10845,72 @@ public abstract class HighLevelQuickFixTestGenerated extends AbstractHighLevelQu
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../../idea/tests/testData/quickfix/javaClassOnCompanion")
public abstract static class JavaClassOnCompanion extends AbstractHighLevelQuickFixTest {
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../../idea/tests/testData/quickfix/javaClassOnCompanion/replaceWithClassJava")
public static class ReplaceWithClassJava extends AbstractHighLevelQuickFixTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K2;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("hasType.kt")
public void testHasType() throws Exception {
runTest("../../../idea/tests/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/hasType.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("../../../idea/tests/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/simple.kt");
}
@TestMetadata("withName.kt")
public void testWithName() throws Exception {
runTest("../../../idea/tests/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/withName.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../../idea/tests/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava")
public static class ReplaceWithCompanionClassJava extends AbstractHighLevelQuickFixTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K2;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("hasType.kt")
public void testHasType() throws Exception {
runTest("../../../idea/tests/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/hasType.kt");
}
@TestMetadata("namedCompanion.kt")
public void testNamedCompanion() throws Exception {
runTest("../../../idea/tests/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/namedCompanion.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("../../../idea/tests/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/simple.kt");
}
@TestMetadata("withName.kt")
public void testWithName() throws Exception {
runTest("../../../idea/tests/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/withName.kt");
}
}
}
@@ -1,7 +1,9 @@
// "Replace with '::class.java'" "true"
// WITH_STDLIB
// PRIORITY: LOW
// DISABLE_ERRORS
fun main() {
val c: Class<Int.Companion> = Int.javaClass<caret>
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithClassJavaFix
@@ -1,7 +1,9 @@
// "Replace with '::class.java'" "true"
// WITH_STDLIB
// PRIORITY: LOW
// DISABLE_ERRORS
fun main() {
val c: Class<Int.Companion> = Int::class.java
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithClassJavaFix
@@ -1,6 +1,8 @@
// "Replace with '::class.java'" "true"
// WITH_STDLIB
// PRIORITY: LOW
fun main() {
val c = Int.javaClass<caret>
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithClassJavaFix
@@ -1,6 +1,8 @@
// "Replace with '::class.java'" "true"
// WITH_STDLIB
// PRIORITY: LOW
fun main() {
val c = Int::class.java
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithClassJavaFix
@@ -1,6 +1,8 @@
// "Replace with '::class.java'" "true"
// WITH_STDLIB
// PRIORITY: LOW
fun main() {
val name = Int.javaClass<caret>.name
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithClassJavaFix
@@ -1,6 +1,8 @@
// "Replace with '::class.java'" "true"
// WITH_STDLIB
// PRIORITY: LOW
fun main() {
val name = Int::class.java.name
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithClassJavaFix
@@ -3,4 +3,5 @@
fun main() {
val c: Class<Int.Companion> = Int.javaClass<caret>
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithCompanionClassJavaFix
@@ -3,4 +3,5 @@
fun main() {
val c: Class<Int.Companion> = Int.Companion::class.java
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithCompanionClassJavaFix
@@ -7,4 +7,5 @@ class Foo {
fun test() {
Foo.javaClass<caret>
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithCompanionClassJavaFix
@@ -7,4 +7,5 @@ class Foo {
fun test() {
Foo.Bar::class.java
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithCompanionClassJavaFix
@@ -3,4 +3,5 @@
fun main() {
val c = Int.javaClass<caret>
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithCompanionClassJavaFix
@@ -3,4 +3,5 @@
fun main() {
val c = Int.Companion::class.java
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithCompanionClassJavaFix
@@ -3,4 +3,5 @@
fun main() {
val name = Int.javaClass<caret>.name
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithCompanionClassJavaFix
@@ -3,4 +3,5 @@
fun main() {
val name = Int.Companion::class.java.name
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceWithCompanionClassJavaFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ReplaceWithCompanionClassJavaFix
@@ -138,7 +138,7 @@ internal fun MutableTWorkspace.generateK2FixTests() {
model("$idea/quickfix/inlineTypeParameterFix", pattern = pattern)
model("$idea/quickfix/insertDelegationCall", pattern = pattern)
model("$idea/quickfix/isEnumEntry", pattern = pattern)
model("$idea/quickfix/javaClassOnCompanion", pattern = pattern, isIgnored = true)
model("$idea/quickfix/javaClassOnCompanion", pattern = pattern)
model("$idea/quickfix/kdocMissingDocumentation", pattern = pattern, isIgnored = true)
model("$idea/quickfix/leakingThis", pattern = pattern, isIgnored = true)
model("$idea/quickfix/libraries", pattern = pattern)