mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] ABSTRACT_SUPER_CALL quickfix: Add an import directive if needed
^KTIJ-23057 Fixed closes https://github.com/JetBrains/intellij-community/pull/2177 GitOrigin-RevId: a7d7e7e861dfd8a94d0e086142cd007cbd52f9ee
This commit is contained in:
committed by
intellij-monorepo-bot
parent
10f8b83aa5
commit
af0c587b68
+33
-20
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.actions.generate.KotlinGenerateEqualsAndHashcodeAction
|
||||
import org.jetbrains.kotlin.idea.actions.generate.KotlinGenerateEqualsAndHashcodeAction.Info
|
||||
import org.jetbrains.kotlin.idea.actions.generate.KotlinGenerateToStringAction
|
||||
import org.jetbrains.kotlin.idea.base.psi.replaced
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.KotlinPsiOnlyQuickFixAction
|
||||
@@ -21,8 +22,10 @@ import org.jetbrains.kotlin.idea.intentions.conventionNameCalls.isAnyEquals
|
||||
import org.jetbrains.kotlin.idea.intentions.conventionNameCalls.isAnyHashCode
|
||||
import org.jetbrains.kotlin.idea.intentions.conventionNameCalls.isAnyToString
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
private const val EQUALS = "equals"
|
||||
@@ -40,7 +43,7 @@ class AbstractSuperCallFix(element: KtNameReferenceExpression) : KotlinPsiOnlyQu
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean {
|
||||
val expression = element ?: return false
|
||||
return getSuperClassNameToReferTo(expression) != null
|
||||
return getSuperClassFqNameToReferTo(expression) != null
|
||||
}
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
@@ -70,18 +73,11 @@ class AbstractSuperCallFix(element: KtNameReferenceExpression) : KotlinPsiOnlyQu
|
||||
functionDescriptor.isAnyHashCode() -> replaceIfNotInObject()
|
||||
functionDescriptor.isAnyToString() -> replaceIfNotInObject()
|
||||
else -> {
|
||||
getSuperClassNameToReferTo(expression)?.let { superClassName ->
|
||||
expression.parentOfType<KtDotQualifiedExpression>()
|
||||
?.receiverExpression
|
||||
?.safeAs<KtSuperExpression>()
|
||||
?.specifySuperType(superClassName)
|
||||
|
||||
KtPsiFactory(containingClass).createSuperTypeEntry(superClassName)
|
||||
}?.let {
|
||||
val alreadyExists = containingClass.superTypeListEntries.any { entry -> entry.text == it.text }
|
||||
if (!alreadyExists) {
|
||||
containingClass.addSuperTypeListEntry(it)
|
||||
}
|
||||
val superExpression = expression.getParentSuperExpression()
|
||||
val superClassFqName = getSuperClassFqNameToReferTo(expression)
|
||||
if (superExpression != null && superClassFqName != null) {
|
||||
superExpression.specifySuperType(superClassFqName)
|
||||
containingClass.addSuperTypeListEntryIfNotExists(superClassFqName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,8 +90,8 @@ class AbstractSuperCallFix(element: KtNameReferenceExpression) : KotlinPsiOnlyQu
|
||||
EQUALS -> KotlinBundle.message("equals.text")
|
||||
TO_STRING -> KotlinBundle.message("action.generate.tostring.name")
|
||||
else -> {
|
||||
val nameToReferTo = getSuperClassNameToReferTo(expression) ?: error("isAvailable() was supposed to prevent null")
|
||||
KotlinBundle.message("specify.super.type", nameToReferTo)
|
||||
val nameToReferTo = getSuperClassFqNameToReferTo(expression) ?: error("isAvailable() was supposed to prevent null")
|
||||
KotlinBundle.message("specify.super.type", nameToReferTo.shortName().asString())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,12 +135,26 @@ private fun Info.adjust(
|
||||
needEqualsActually, needHashCodeActually, this.classDescriptor, this.variablesForEquals, this.variablesForHashCode
|
||||
)
|
||||
|
||||
private fun KtSuperExpression.specifySuperType(superType: String) {
|
||||
private fun KtSuperExpression.specifySuperType(superType: FqName) {
|
||||
val label = labelQualifier?.text ?: ""
|
||||
replace(KtPsiFactory(this).createExpression("super<$superType>$label"))
|
||||
val replaced = replaced(KtPsiFactory(this).createExpression("super<${superType.asString()}>$label"))
|
||||
ShortenReferences.DEFAULT.process(replaced)
|
||||
}
|
||||
|
||||
private fun getSuperClassNameToReferTo(expression: KtNameReferenceExpression): String? {
|
||||
private fun KtClassOrObject.addSuperTypeListEntryIfNotExists(superType: FqName) {
|
||||
val superTypeFullName = superType.asString()
|
||||
val superTypeShortName = superType.shortName().asString()
|
||||
val superTypeNames = setOf(superTypeShortName, superTypeFullName)
|
||||
val superTypeListEntry = superTypeListEntries.firstOrNull { it.text in superTypeNames }
|
||||
if (superTypeListEntry == null) {
|
||||
val added = addSuperTypeListEntry(KtPsiFactory(this).createSuperTypeEntry(superTypeFullName))
|
||||
ShortenReferences.DEFAULT.process(added)
|
||||
} else if (superTypeListEntry.text == superTypeFullName) {
|
||||
ShortenReferences.DEFAULT.process(superTypeListEntry)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSuperClassFqNameToReferTo(expression: KtNameReferenceExpression): FqName? {
|
||||
fun tryViaCalledFunction(): CallableDescriptor? = expression.resolveToCall()?.resultingDescriptor
|
||||
?.overriddenDescriptors
|
||||
?.find { it.safeAs<SimpleFunctionDescriptor>()?.modality != Modality.ABSTRACT }
|
||||
@@ -157,5 +167,8 @@ private fun getSuperClassNameToReferTo(expression: KtNameReferenceExpression): S
|
||||
?: tryViaContainingFunction()
|
||||
?: return null
|
||||
|
||||
return callableToUseInstead.containingDeclaration.name.asString()
|
||||
}
|
||||
return callableToUseInstead.containingDeclaration.fqNameOrNull()
|
||||
}
|
||||
|
||||
private fun KtNameReferenceExpression.getParentSuperExpression(): KtSuperExpression? =
|
||||
parentOfType<KtDotQualifiedExpression>()?.receiverExpression?.safeAs<KtSuperExpression>()
|
||||
|
||||
+18
@@ -2172,6 +2172,24 @@ public abstract class QuickFixMultiFileTestGenerated extends AbstractQuickFixMul
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("testData/quickfix/specifySuperExplicitly")
|
||||
public static class SpecifySuperExplicitly extends AbstractQuickFixMultiFileTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTestWithExtraFile, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("abstractSuperCall4.before.Main.kt")
|
||||
public void testAbstractSuperCall4() throws Exception {
|
||||
runTest("testData/quickfix/specifySuperExplicitly/abstractSuperCall4.before.Main.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("abstractSuperCallWithExplicitSuper3.before.Main.kt")
|
||||
public void testAbstractSuperCallWithExplicitSuper3() throws Exception {
|
||||
runTest("testData/quickfix/specifySuperExplicitly/abstractSuperCallWithExplicitSuper3.before.Main.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("testData/quickfix/surroundWithNullCheck")
|
||||
public static class SurroundWithNullCheck extends AbstractQuickFixMultiFileTest {
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Specify super type 'Foo' explicitly" "true"
|
||||
package three
|
||||
|
||||
import one.Foo
|
||||
import two.Derived
|
||||
|
||||
class Derived3 : Derived(), Foo {
|
||||
|
||||
override fun check(): String {
|
||||
return super<Foo>.check()
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package one
|
||||
|
||||
interface Foo {
|
||||
fun check(): String = "OK"
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package two
|
||||
|
||||
import one.Foo
|
||||
|
||||
abstract class Base {
|
||||
abstract fun check(): String
|
||||
}
|
||||
|
||||
abstract class Derived : Base(), Foo
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Specify super type 'Foo' explicitly" "true"
|
||||
package three
|
||||
|
||||
import two.Derived
|
||||
|
||||
class Derived3 : Derived() {
|
||||
|
||||
override fun check(): String {
|
||||
return super.<caret>check()
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Specify super type 'Foo' explicitly" "true"
|
||||
package three
|
||||
|
||||
import one.Foo
|
||||
import two.Derived
|
||||
|
||||
class Derived3 : Derived(), Foo {
|
||||
|
||||
override fun check(): String {
|
||||
return super<Foo>.check()
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package one
|
||||
|
||||
interface Foo {
|
||||
fun check(): String = "OK"
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package two
|
||||
|
||||
import one.Foo
|
||||
|
||||
abstract class Base {
|
||||
abstract fun check(): String
|
||||
}
|
||||
|
||||
abstract class Derived : Base(), Foo
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Specify super type 'Foo' explicitly" "true"
|
||||
package three
|
||||
|
||||
import two.Derived
|
||||
|
||||
class Derived3 : Derived(), one.Foo {
|
||||
|
||||
override fun check(): String {
|
||||
return super<Derived>.<caret>check()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user