Added "Add remaining branches with import" quick fix #KT-16033 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
2fa4c28e0f
commit
fe0f44da94
@@ -20,11 +20,11 @@ import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.conversion.copy.range
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.util.ImportDescriptorResult
|
||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
@@ -59,26 +59,33 @@ class ImportAllMembersIntention : SelfTargetingIntention<KtDotQualifiedExpressio
|
||||
}
|
||||
|
||||
override fun applyTo(element: KtDotQualifiedExpression, editor: Editor?) {
|
||||
val target = target(element)!!
|
||||
val classFqName = target.importableFqName!!.parent()
|
||||
|
||||
ImportInsertHelper.getInstance(element.project).importDescriptor(element.containingKtFile, target, forceAllUnderImport = true)
|
||||
|
||||
val qualifiedExpressions = element.containingKtFile.collectDescendantsOfType<KtDotQualifiedExpression> { qualifiedExpression ->
|
||||
val qualifierName = qualifiedExpression.receiverExpression.getQualifiedElementSelector() as? KtNameReferenceExpression
|
||||
qualifierName?.getReferencedNameAsName() == classFqName.shortName() && target(qualifiedExpression)?.importableFqName?.parent() == classFqName
|
||||
}
|
||||
|
||||
//TODO: not deep
|
||||
ShortenReferences.DEFAULT.process(qualifiedExpressions)
|
||||
element.importReceiverMembers()
|
||||
}
|
||||
|
||||
private fun target(expression: KtDotQualifiedExpression): DeclarationDescriptor? {
|
||||
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL)
|
||||
if (bindingContext[BindingContext.QUALIFIER, expression.receiverExpression] !is ClassQualifier) {
|
||||
return null
|
||||
companion object {
|
||||
fun KtDotQualifiedExpression.importReceiverMembers() {
|
||||
val target = target(this)!!
|
||||
val classFqName = target.importableFqName!!.parent()
|
||||
|
||||
ImportInsertHelper.getInstance(project).importDescriptor(containingKtFile, target, forceAllUnderImport = true)
|
||||
|
||||
val qualifiedExpressions = containingKtFile.collectDescendantsOfType<KtDotQualifiedExpression> { qualifiedExpression ->
|
||||
val qualifierName = qualifiedExpression.receiverExpression.getQualifiedElementSelector() as? KtNameReferenceExpression
|
||||
qualifierName?.getReferencedNameAsName() == classFqName.shortName() && target(qualifiedExpression)?.importableFqName?.parent() == classFqName
|
||||
}
|
||||
|
||||
//TODO: not deep
|
||||
ShortenReferences.DEFAULT.process(qualifiedExpressions)
|
||||
}
|
||||
|
||||
private fun target(expression: KtDotQualifiedExpression): DeclarationDescriptor? {
|
||||
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL)
|
||||
if (bindingContext[BindingContext.QUALIFIER, expression.receiverExpression] !is ClassQualifier) {
|
||||
return null
|
||||
}
|
||||
val selector = expression.getQualifiedElementSelector() as? KtNameReferenceExpression ?: return null
|
||||
return selector.mainReference.resolveToDescriptors(bindingContext).firstOrNull()
|
||||
}
|
||||
val selector = expression.getQualifiedElementSelector() as? KtNameReferenceExpression ?: return null
|
||||
return selector.mainReference.resolveToDescriptors(bindingContext).firstOrNull()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,25 +16,29 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.cfg.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtWhenExpression
|
||||
import org.jetbrains.kotlin.idea.intentions.ImportAllMembersIntention
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
class AddWhenRemainingBranchesFix(expression: KtWhenExpression) : KotlinQuickFixAction<KtWhenExpression>(expression) {
|
||||
class AddWhenRemainingBranchesFix(
|
||||
expression: KtWhenExpression,
|
||||
val withImport: Boolean = false
|
||||
) : KotlinQuickFixAction<KtWhenExpression>(expression) {
|
||||
|
||||
override fun getFamilyName() = "Add remaining branches"
|
||||
override fun getFamilyName() = text
|
||||
|
||||
override fun getText() = "Add remaining branches"
|
||||
override fun getText() = "Add remaining branches" + if (withImport) " with import" else ""
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
|
||||
val element = element ?: return false
|
||||
@@ -64,12 +68,37 @@ class AddWhenRemainingBranchesFix(expression: KtWhenExpression) : KotlinQuickFix
|
||||
val entry = psiFactory.createWhenEntry("$branchConditionText -> TODO()")
|
||||
element.addBefore(entry, whenCloseBrace)
|
||||
}
|
||||
|
||||
if (withImport) {
|
||||
importAllEntries(element)
|
||||
}
|
||||
}
|
||||
|
||||
companion object : KotlinSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<PsiElement>? {
|
||||
val whenExpression = diagnostic.psiElement.getNonStrictParentOfType<KtWhenExpression>() ?: return null
|
||||
return AddWhenRemainingBranchesFix(whenExpression)
|
||||
private fun importAllEntries(element: KtWhenExpression) {
|
||||
with (ImportAllMembersIntention) {
|
||||
element.entries
|
||||
.map { it.conditions.toList() }
|
||||
.flatten()
|
||||
.firstNotNullResult {
|
||||
(it as? KtWhenConditionWithExpression)?.expression as? KtDotQualifiedExpression
|
||||
}?.importReceiverMembers()
|
||||
}
|
||||
}
|
||||
|
||||
companion object : KotlinIntentionActionsFactory() {
|
||||
private fun KtWhenExpression.hasEnumSubject(): Boolean {
|
||||
val subject = subjectExpression ?: return false
|
||||
val descriptor = subject.analyze().getType(subject)?.constructor?.declarationDescriptor ?: return false
|
||||
return (descriptor as? ClassDescriptor)?.kind == ClassKind.ENUM_CLASS
|
||||
}
|
||||
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||
val whenExpression = diagnostic.psiElement.getNonStrictParentOfType<KtWhenExpression>() ?: return emptyList()
|
||||
val actions = mutableListOf(AddWhenRemainingBranchesFix(whenExpression))
|
||||
if (whenExpression.hasEnumSubject()) {
|
||||
actions += AddWhenRemainingBranchesFix(whenExpression, withImport = true)
|
||||
}
|
||||
return actions
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Add remaining branches with import" "true"
|
||||
// WITH_RUNTIME
|
||||
enum class Foo {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
class Test {
|
||||
fun foo(e: Foo) {
|
||||
when<caret> (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import Foo.*
|
||||
|
||||
// "Add remaining branches with import" "true"
|
||||
// WITH_RUNTIME
|
||||
enum class Foo {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
class Test {
|
||||
fun foo(e: Foo) {
|
||||
when<caret> (e) {
|
||||
A -> TODO()
|
||||
B -> TODO()
|
||||
C -> TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// "Add remaining branches with import" "true"
|
||||
// WITH_RUNTIME
|
||||
import Foo.*
|
||||
|
||||
enum class Foo {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
class Test {
|
||||
fun foo(e: Foo) {
|
||||
when<caret> (e) {
|
||||
A, Foo.B -> TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// "Add remaining branches with import" "true"
|
||||
// WITH_RUNTIME
|
||||
import Foo.*
|
||||
|
||||
enum class Foo {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
class Test {
|
||||
fun foo(e: Foo) {
|
||||
when<caret> (e) {
|
||||
A, B -> TODO()
|
||||
C -> TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// "Add remaining branches with import" "true"
|
||||
// WITH_RUNTIME
|
||||
import Foo.*
|
||||
|
||||
enum class Foo {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
enum class Bar {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
class Test {
|
||||
fun foo(e: Foo) {
|
||||
when (e) {
|
||||
A -> TODO()
|
||||
B -> TODO()
|
||||
C -> TODO()
|
||||
}
|
||||
}
|
||||
fun bar(e: Bar) {
|
||||
when<caret> (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// "Add remaining branches with import" "true"
|
||||
// WITH_RUNTIME
|
||||
import Foo.*
|
||||
|
||||
enum class Foo {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
enum class Bar {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
class Test {
|
||||
fun foo(e: Foo) {
|
||||
when (e) {
|
||||
A -> TODO()
|
||||
B -> TODO()
|
||||
C -> TODO()
|
||||
}
|
||||
}
|
||||
fun bar(e: Bar) {
|
||||
when<caret> (e) {
|
||||
Bar.A -> TODO()
|
||||
Bar.B -> TODO()
|
||||
Bar.C -> TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// "Add remaining branches with import" "true"
|
||||
// WITH_RUNTIME
|
||||
import Foo.*
|
||||
|
||||
enum class Foo {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
enum class Baz {
|
||||
AA, B, CC
|
||||
}
|
||||
|
||||
class Test {
|
||||
fun foo(e: Foo) {
|
||||
when (e) {
|
||||
A -> TODO()
|
||||
B -> TODO()
|
||||
C -> TODO()
|
||||
}
|
||||
}
|
||||
fun baz(e: Baz) {
|
||||
when<caret> (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// "Add remaining branches with import" "true"
|
||||
// WITH_RUNTIME
|
||||
import Baz.*
|
||||
import Foo.*
|
||||
import Foo.B
|
||||
|
||||
enum class Foo {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
enum class Baz {
|
||||
AA, B, CC
|
||||
}
|
||||
|
||||
class Test {
|
||||
fun foo(e: Foo) {
|
||||
when (e) {
|
||||
A -> TODO()
|
||||
B -> TODO()
|
||||
C -> TODO()
|
||||
}
|
||||
}
|
||||
fun baz(e: Baz) {
|
||||
when<caret> (e) {
|
||||
AA -> TODO()
|
||||
Baz.B -> TODO()
|
||||
CC -> TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11887,6 +11887,30 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("addRemainingBranchesEnumImport1.kt")
|
||||
public void testAddRemainingBranchesEnumImport1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/when/addRemainingBranchesEnumImport1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("addRemainingBranchesEnumImport2.kt")
|
||||
public void testAddRemainingBranchesEnumImport2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/when/addRemainingBranchesEnumImport2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("addRemainingBranchesEnumImport3.kt")
|
||||
public void testAddRemainingBranchesEnumImport3() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/when/addRemainingBranchesEnumImport3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("addRemainingBranchesEnumImport4.kt")
|
||||
public void testAddRemainingBranchesEnumImport4() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/when/addRemainingBranchesEnumImport4.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("addRemainingBranchesEnumStatement.kt")
|
||||
public void testAddRemainingBranchesEnumStatement() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/when/addRemainingBranchesEnumStatement.kt");
|
||||
|
||||
Reference in New Issue
Block a user