From 83ad94ff1f3c601b26dd4e18fb58e7b3ad364f69 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Thu, 21 Sep 2023 16:45:23 +0200 Subject: [PATCH] [mod-commands] IDEA-333040 Convert CompositeIntentionQuickFix to ModCommand GitOrigin-RevId: 67fd2853544b99e94e442566d29d874990292d9f --- .../jvm/actions/ChangeModifierRequest.java | 13 ++++ .../lang/jvm/actions/memberRequests.kt | 4 +- .../daemon/impl/quickfix/ModifierFix.java | 12 +++- .../impl/JavaElementActionsFactory.kt | 2 +- .../fix/CompositeIntentionQuickFix.kt | 54 -------------- .../fix/CompositeModCommandQuickFix.kt | 30 ++++++++ .../JUnitMalformedDeclarationInspection.kt | 65 +++++++---------- .../quickfixes/KotlinQuickFixAction.kt | 3 +- .../KotlinCrossLanguageQuickFixAction.kt | 3 +- .../idea/quickfix/MakeMemberStaticFix.kt | 72 ++++--------------- 10 files changed, 102 insertions(+), 156 deletions(-) delete mode 100644 jvm/jvm-analysis-impl/src/com/intellij/codeInspection/fix/CompositeIntentionQuickFix.kt create mode 100644 jvm/jvm-analysis-impl/src/com/intellij/codeInspection/fix/CompositeModCommandQuickFix.kt diff --git a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ChangeModifierRequest.java b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ChangeModifierRequest.java index 670b012a1e64..93b29375dfdd 100644 --- a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ChangeModifierRequest.java +++ b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ChangeModifierRequest.java @@ -6,8 +6,21 @@ import org.jetbrains.annotations.NotNull; public interface ChangeModifierRequest extends ActionRequest { + /** + * @return the modifier which should be changed + */ @NotNull JvmModifier getModifier(); + /** + * @return true if the modifier should be added, false if it should be removed + */ boolean shouldBePresent(); + + /** + * @return true if it's desired to process hierarchy when applicable (e.g., update overriding methods correspondingly) + */ + default boolean processHierarchy() { + return true; + } } diff --git a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/memberRequests.kt b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/memberRequests.kt index ae942968dded..aa6d8ca82648 100644 --- a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/memberRequests.kt +++ b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/memberRequests.kt @@ -3,8 +3,10 @@ package com.intellij.lang.jvm.actions import com.intellij.lang.jvm.JvmModifier -fun modifierRequest(modifier: JvmModifier, shouldBePresent: Boolean): ChangeModifierRequest = object : ChangeModifierRequest { +@JvmOverloads +fun modifierRequest(modifier: JvmModifier, shouldBePresent: Boolean, processHierarchy: Boolean = true): ChangeModifierRequest = object : ChangeModifierRequest { override fun isValid(): Boolean = true override fun getModifier(): JvmModifier = modifier override fun shouldBePresent(): Boolean = shouldBePresent + override fun processHierarchy(): Boolean = processHierarchy } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java index 118e107cc5e6..b421ddf5ea6a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java @@ -37,6 +37,7 @@ public class ModifierFix extends LocalQuickFixAndIntentionActionOnPsiElement imp @PsiModifier.ModifierConstant private final String myModifier; private final boolean myShouldHave; private final boolean myShowContainingClass; + private final boolean myProcessHierarchy; private volatile @IntentionName String myName; private final boolean myStartInWriteAction; @@ -49,6 +50,7 @@ public class ModifierFix extends LocalQuickFixAndIntentionActionOnPsiElement imp myShouldHave = shouldHave; myShowContainingClass = showContainingClass; myName = format(null, modifierList, myShowContainingClass); + myProcessHierarchy = true; myStartInWriteAction = !(modifierList.getParent() instanceof PsiMethod) || AccessModifier.fromPsiModifier(modifier) == null; } @@ -56,13 +58,21 @@ public class ModifierFix extends LocalQuickFixAndIntentionActionOnPsiElement imp @PsiModifier.ModifierConstant @NotNull String modifier, boolean shouldHave, boolean showContainingClass) { + this(owner, modifier, shouldHave, showContainingClass, true); + } + + public ModifierFix(@NotNull PsiModifierListOwner owner, + @PsiModifier.ModifierConstant @NotNull String modifier, + boolean shouldHave, + boolean showContainingClass, boolean processHierarchy) { super(owner); myModifier = modifier; myShouldHave = shouldHave; myShowContainingClass = showContainingClass; + myProcessHierarchy = processHierarchy; PsiVariable variable = owner instanceof PsiVariable ? (PsiVariable)owner : null; myName = format(variable, owner.getModifierList(), myShowContainingClass); - myStartInWriteAction = !(owner instanceof PsiMethod) || AccessModifier.fromPsiModifier(modifier) == null; + myStartInWriteAction = !myProcessHierarchy || !(owner instanceof PsiMethod) || AccessModifier.fromPsiModifier(modifier) == null; } private @IntentionName @NotNull String format(PsiVariable variable, PsiModifierList modifierList, boolean showContainingClass) { diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaElementActionsFactory.kt b/java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaElementActionsFactory.kt index 276428875cc0..d62f81c5f42e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaElementActionsFactory.kt +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaElementActionsFactory.kt @@ -84,7 +84,7 @@ class JavaElementActionsFactory : JvmElementActionsFactory() { internal class ChangeModifierFix(declaration: PsiModifierListOwner, @FileModifier.SafeFieldForPreview val request: ChangeModifierRequest) : - ModifierFix(declaration, request.modifier.toPsiModifier(), request.shouldBePresent(), true) { + ModifierFix(declaration, request.modifier.toPsiModifier(), request.shouldBePresent(), true, request.processHierarchy()) { override fun isAvailable(): Boolean = request.isValid && super.isAvailable() override fun isAvailable(project: Project, diff --git a/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/fix/CompositeIntentionQuickFix.kt b/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/fix/CompositeIntentionQuickFix.kt deleted file mode 100644 index 903491da040d..000000000000 --- a/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/fix/CompositeIntentionQuickFix.kt +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.codeInspection.fix - -import com.intellij.codeInsight.FileModificationService -import com.intellij.codeInsight.intention.IntentionAction -import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo -import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils -import com.intellij.codeInspection.LocalQuickFix -import com.intellij.codeInspection.ProblemDescriptor -import com.intellij.codeInspection.nonPreviewElement -import com.intellij.lang.jvm.JvmModifiersOwner -import com.intellij.openapi.application.runWriteAction -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElement -import com.intellij.psi.SmartPointerManager -import com.intellij.util.asSafely - -/** - * A quickfix that can call multiple JVM intention actions and bundle them into a single quick fix. - */ -abstract class CompositeIntentionQuickFix : LocalQuickFix { - override fun startInWriteAction(): Boolean = false - - protected fun generatePreviews(project: Project, previewDescriptor: ProblemDescriptor, element: PsiElement): IntentionPreviewInfo { - val containingFile = previewDescriptor.startElement.containingFile ?: return IntentionPreviewInfo.EMPTY - val editor = IntentionPreviewUtils.getPreviewEditor() ?: return IntentionPreviewInfo.EMPTY - val target = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(element) - getActions(project, previewDescriptor).forEach { factory -> - val actions = factory(target.element?.nonPreviewElement ?: return@forEach) - actions.forEach { action -> - action.generatePreview(project, editor, containingFile) - } - } - return IntentionPreviewInfo.DIFF - } - - protected fun applyFixes(project: Project, descriptor: ProblemDescriptor, element: PsiElement) { - val containingFile = descriptor.psiElement.containingFile ?: return - val target = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(element) - if (!FileModificationService.getInstance().prepareFileForWrite(element.containingFile)) return - getActions(project, descriptor).forEach { factory -> - val actions = factory(target.element.asSafely() ?: return@forEach) - actions.forEach { action -> - if (action.startInWriteAction()) { - runWriteAction { action.invoke(project, null, containingFile) } - } else { - action.invoke(project, null, containingFile) - } - } - } - } - - protected abstract fun getActions(project: Project, descriptor: ProblemDescriptor): List<(JvmModifiersOwner) -> List> -} \ No newline at end of file diff --git a/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/fix/CompositeModCommandQuickFix.kt b/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/fix/CompositeModCommandQuickFix.kt new file mode 100644 index 000000000000..a051e9af37e8 --- /dev/null +++ b/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/fix/CompositeModCommandQuickFix.kt @@ -0,0 +1,30 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.codeInspection.fix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.lang.jvm.JvmModifiersOwner +import com.intellij.modcommand.PsiUpdateModCommandQuickFix +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.SmartPointerManager +import com.intellij.util.asSafely + +/** + * A quickfix that can call multiple JVM intention actions and bundle them into a single quick fix. + * It's assumed that all the JVM intention actions are well-behaving: they only modify the single PSI file + * and don't do anything else like starting template. + */ +abstract class CompositeModCommandQuickFix : PsiUpdateModCommandQuickFix() { + protected fun applyFixes(project: Project, element: PsiElement, containingFile: PsiFile) { + val target = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(element) + getActions(project).forEach { factory -> + val actions = factory(target.element.asSafely() ?: return@forEach) + actions.forEach { action -> + action.invoke(project, null, containingFile) + } + } + } + + protected abstract fun getActions(project: Project): List<(JvmModifiersOwner) -> List> +} \ No newline at end of file diff --git a/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/test/junit/JUnitMalformedDeclarationInspection.kt b/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/test/junit/JUnitMalformedDeclarationInspection.kt index 527f2822dce7..6923e38aa5d0 100644 --- a/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/test/junit/JUnitMalformedDeclarationInspection.kt +++ b/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/test/junit/JUnitMalformedDeclarationInspection.kt @@ -8,10 +8,9 @@ import com.intellij.codeInsight.MetaAnnotationUtil import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil import com.intellij.codeInsight.intention.FileModifier.SafeFieldForPreview import com.intellij.codeInsight.intention.IntentionAction -import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo import com.intellij.codeInsight.options.JavaClassValidator import com.intellij.codeInspection.* -import com.intellij.codeInspection.fix.CompositeIntentionQuickFix +import com.intellij.codeInspection.fix.CompositeModCommandQuickFix import com.intellij.codeInspection.options.OptPane import com.intellij.codeInspection.options.OptPane.pane import com.intellij.codeInspection.options.OptPane.stringList @@ -24,6 +23,7 @@ import com.intellij.lang.jvm.JvmModifiersOwner import com.intellij.lang.jvm.actions.* import com.intellij.lang.jvm.types.JvmPrimitiveTypeKind import com.intellij.lang.jvm.types.JvmType +import com.intellij.modcommand.ModPsiUpdater import com.intellij.openapi.module.ModuleUtilCore import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ModuleRootManager @@ -333,8 +333,8 @@ private class JUnitMalformedSignatureVisitor( ) { override fun getName(): String = JvmAnalysisBundle.message("jvm.inspections.junit.malformed.fix.class.signature.multi") - override fun getActions(project: Project, descriptor: ProblemDescriptor): List<(JvmModifiersOwner) -> List> { - val list = super.getActions(project, descriptor).toMutableList() + override fun getActions(project: Project): List<(JvmModifiersOwner) -> List> { + val list = super.getActions(project).toMutableList() list.add { owner -> val outerClass = owner.sourceElement?.toUElementOfType()?.nestedClassHierarchy()?.last()!! val request = annotationRequest(ORG_JUNIT_RUNNER_RUN_WITH, classAttribute("value", ORG_JUNIT_EXPERIMENTAL_RUNNERS_ENCLOSED)) @@ -345,9 +345,10 @@ private class JUnitMalformedSignatureVisitor( override fun getFamilyName(): String = JvmAnalysisBundle.message("jvm.inspections.junit.malformed.fix.class.signature.multi") - override fun applyFix(project: Project, descriptor: ProblemDescriptor) { - val uClass = getUParentForIdentifier(descriptor.psiElement)?.asSafely() ?: return - applyFixes(project, descriptor, uClass.javaPsi.asSafely() ?: return) + override fun applyFix(project: Project, element: PsiElement, updater: ModPsiUpdater) { + val uClass = getUParentForIdentifier(element)?.asSafely() ?: return + applyFixes(project, uClass.javaPsi.asSafely() ?: return, + element.containingFile ?: return) } } @@ -1118,22 +1119,18 @@ private class JUnitMalformedSignatureVisitor( private val makeStatic: Boolean? = null, private val makePublic: Boolean? = null, private val annotation: String? = null - ) : CompositeIntentionQuickFix() { + ) : CompositeModCommandQuickFix() { override fun getFamilyName(): String = JvmAnalysisBundle.message("jvm.inspections.junit.malformed.fix.class.signature") override fun getName(): String = JvmAnalysisBundle.message("jvm.inspections.junit.malformed.fix.class.signature.descriptor", name) - override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo { - val javaDeclaration = getUParentForIdentifier(previewDescriptor.psiElement)?.asSafely() ?: return IntentionPreviewInfo.EMPTY - return generatePreviews(project, previewDescriptor, javaDeclaration.javaPsi.asSafely() ?: return IntentionPreviewInfo.EMPTY) + override fun applyFix(project: Project, element: PsiElement, updater: ModPsiUpdater) { + val javaDeclaration = getUParentForIdentifier(element)?.asSafely() ?: return + applyFixes(project, javaDeclaration.javaPsi.asSafely() ?: return, + element.containingFile ?: return) } - override fun applyFix(project: Project, descriptor: ProblemDescriptor) { - val javaDeclaration = getUParentForIdentifier(descriptor.psiElement)?.asSafely() ?: return - applyFixes(project, descriptor, javaDeclaration.javaPsi.asSafely() ?: return) - } - - override fun getActions(project: Project, descriptor: ProblemDescriptor): List<(JvmModifiersOwner) -> List> { + override fun getActions(project: Project): List<(JvmModifiersOwner) -> List> { val actions = mutableListOf<(JvmModifiersOwner) -> List>() if (makeStatic != null) { actions.add { jvmClass -> createModifierActions(jvmClass, modifierRequest(JvmModifier.STATIC, makeStatic)) } @@ -1152,22 +1149,17 @@ private class JUnitMalformedSignatureVisitor( private val name: @NlsSafe String, private val makeStatic: Boolean?, private val newVisibility: JvmModifier? = null - ) : CompositeIntentionQuickFix() { + ) : CompositeModCommandQuickFix() { override fun getFamilyName(): String = JvmAnalysisBundle.message("jvm.inspections.junit.malformed.fix.field.signature") override fun getName(): String = JvmAnalysisBundle.message("jvm.inspections.junit.malformed.fix.field.signature.descriptor", name) - override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo { - val javaDeclaration = getUParentForIdentifier(previewDescriptor.psiElement)?.asSafely() ?: return IntentionPreviewInfo.EMPTY - return generatePreviews(project, previewDescriptor, javaDeclaration.javaPsi ?: return IntentionPreviewInfo.EMPTY) + override fun applyFix(project: Project, element: PsiElement, updater: ModPsiUpdater) { + val javaDeclaration = getUParentForIdentifier(element)?.asSafely() ?: return + applyFixes(project, javaDeclaration.javaPsi ?: return, element.containingFile ?: return) } - override fun applyFix(project: Project, descriptor: ProblemDescriptor) { - val javaDeclaration = getUParentForIdentifier(descriptor.psiElement)?.asSafely() ?: return - applyFixes(project, descriptor, javaDeclaration.javaPsi ?: return) - } - - override fun getActions(project: Project, descriptor: ProblemDescriptor): List<(JvmModifiersOwner) -> List> { + override fun getActions(project: Project): List<(JvmModifiersOwner) -> List> { val actions = mutableListOf<(JvmModifiersOwner) -> List>() if (newVisibility != null) { actions.add { jvmField -> createModifierActions(jvmField, modifierRequest(newVisibility, true)) } @@ -1185,22 +1177,17 @@ private class JUnitMalformedSignatureVisitor( private val shouldBeVoidType: Boolean? = null, private val newVisibility: JvmModifier? = null, @SafeFieldForPreview private val inCorrectParams: Map? = null - ) : CompositeIntentionQuickFix() { + ) : CompositeModCommandQuickFix() { override fun getFamilyName(): String = JvmAnalysisBundle.message("jvm.inspections.junit.malformed.fix.method.signature") override fun getName(): String = JvmAnalysisBundle.message("jvm.inspections.junit.malformed.fix.method.signature.descriptor", name) - override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo { - val javaDeclaration = getUParentForIdentifier(previewDescriptor.psiElement)?.asSafely() ?: return IntentionPreviewInfo.EMPTY - return generatePreviews(project, previewDescriptor, javaDeclaration.javaPsi) + override fun applyFix(project: Project, element: PsiElement, updater: ModPsiUpdater) { + val javaDeclaration = getUParentForIdentifier(element)?.asSafely() ?: return + applyFixes(project, javaDeclaration.javaPsi, element.containingFile ?: return) } - override fun applyFix(project: Project, descriptor: ProblemDescriptor) { - val javaDeclaration = getUParentForIdentifier(descriptor.psiElement)?.asSafely() ?: return - applyFixes(project, descriptor, javaDeclaration.javaPsi) - } - - override fun getActions(project: Project, descriptor: ProblemDescriptor): List<(JvmModifiersOwner) -> List> { + override fun getActions(project: Project): List<(JvmModifiersOwner) -> List> { val actions = mutableListOf<(JvmModifiersOwner) -> List>() if (shouldBeVoidType == true) { actions.add { jvmMethod -> createChangeTypeActions( @@ -1209,7 +1196,7 @@ private class JUnitMalformedSignatureVisitor( ) } } if (newVisibility != null) { - actions.add { jvmMethod -> createModifierActions(jvmMethod, modifierRequest(newVisibility, true)) } + actions.add { jvmMethod -> createModifierActions(jvmMethod, modifierRequest(newVisibility, true, false)) } } if (inCorrectParams != null) { actions.add { jvmMethod -> createChangeParametersActions( @@ -1218,7 +1205,7 @@ private class JUnitMalformedSignatureVisitor( ) } } if (makeStatic != null) { - actions.add { jvmMethod -> createModifierActions(jvmMethod, modifierRequest(JvmModifier.STATIC, makeStatic)) } + actions.add { jvmMethod -> createModifierActions(jvmMethod, modifierRequest(JvmModifier.STATIC, makeStatic, false)) } } return actions } diff --git a/plugins/kotlin/code-insight/api/src/org/jetbrains/kotlin/idea/codeinsight/api/classic/quickfixes/KotlinQuickFixAction.kt b/plugins/kotlin/code-insight/api/src/org/jetbrains/kotlin/idea/codeinsight/api/classic/quickfixes/KotlinQuickFixAction.kt index e86f4c439260..e43c51d29ce6 100644 --- a/plugins/kotlin/code-insight/api/src/org/jetbrains/kotlin/idea/codeinsight/api/classic/quickfixes/KotlinQuickFixAction.kt +++ b/plugins/kotlin/code-insight/api/src/org/jetbrains/kotlin/idea/codeinsight/api/classic/quickfixes/KotlinQuickFixAction.kt @@ -20,7 +20,8 @@ abstract class KotlinQuickFixAction(element: T) : QuickFixAc final override fun invoke(project: Project, editor: Editor?, file: PsiFile) { val element = element ?: return - if (file is KtFile && IntentionPreviewUtils.prepareElementForWrite(element)) { + if (file is KtFile && + (startInWriteAction() && getElementToMakeWritable(file) == file || IntentionPreviewUtils.prepareElementForWrite(element))) { invoke(project, editor, file) } } diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/KotlinCrossLanguageQuickFixAction.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/KotlinCrossLanguageQuickFixAction.kt index 34db1905c35e..264cdb03725a 100644 --- a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/KotlinCrossLanguageQuickFixAction.kt +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/KotlinCrossLanguageQuickFixAction.kt @@ -15,7 +15,8 @@ abstract class KotlinCrossLanguageQuickFixAction(element: T) final override fun invoke(project: Project, editor: Editor?, file: PsiFile) { val element = element - if (element != null && IntentionPreviewUtils.prepareElementForWrite(element)) { + if (element != null && + (startInWriteAction() && getElementToMakeWritable(file) == file || IntentionPreviewUtils.prepareElementForWrite(element))) { invokeImpl(project, editor, file) } } diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeMemberStaticFix.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeMemberStaticFix.kt index 0b4d29eda4d9..45ea36927e0d 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeMemberStaticFix.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeMemberStaticFix.kt @@ -1,20 +1,14 @@ // 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.quickfix -import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo -import com.intellij.openapi.application.ex.ApplicationManagerEx -import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.editor.Editor +import com.intellij.openapi.progress.EmptyProgressIndicator import com.intellij.openapi.project.Project -import com.intellij.psi.PsiFile import com.intellij.psi.codeStyle.CodeStyleManager -import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.kotlin.idea.base.psi.getOrCreateCompanionObject import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.KotlinQuickFixAction import org.jetbrains.kotlin.idea.intentions.AddJvmStaticIntention import org.jetbrains.kotlin.idea.intentions.MoveMemberToCompanionObjectIntention -import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively import org.jetbrains.kotlin.idea.util.addAnnotation import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName @@ -24,61 +18,23 @@ import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject class MakeMemberStaticFix(declaration: KtNamedDeclaration) : KotlinQuickFixAction(declaration) { - override fun startInWriteAction(): Boolean = false - - override fun generatePreview(project: Project, editor: Editor, file: PsiFile): IntentionPreviewInfo { - val declaration = element ?: return IntentionPreviewInfo.EMPTY - if (declaration is KtClass) { - if (declaration.hasModifier(KtTokens.INNER_KEYWORD)) declaration.removeModifier(KtTokens.INNER_KEYWORD) - return IntentionPreviewInfo.DIFF - } - val copyDeclaration = PsiTreeUtil.findSameElementInCopy(declaration, file) - val containingClass = copyDeclaration.containingClassOrObject ?: return IntentionPreviewInfo.EMPTY - val copyDeclarationInCompanion = if (containingClass is KtClass) { - val companionObject = containingClass.getOrCreateCompanionObject() - MoveMemberToCompanionObjectIntention.Factory.removeModifiers(copyDeclaration) - val newDeclaration = companionObject.addDeclaration(copyDeclaration) - copyDeclaration.delete() - newDeclaration - } else copyDeclaration - if (AddJvmStaticIntention().applicabilityRange(copyDeclarationInCompanion) != null) { - copyDeclarationInCompanion.addAnnotation(JVM_STATIC_FQ_NAME) - CodeStyleManager.getInstance(declaration.project).reformat(copyDeclarationInCompanion, true) - } - return IntentionPreviewInfo.DIFF - } - override fun invoke(project: Project, editor: Editor?, file: KtFile) { - fun makeStaticAndReformat(declaration: KtNamedDeclaration, editor: Editor?) { - val intention = AddJvmStaticIntention() - if (intention.applicabilityRange(declaration) != null) { - intention.applyTo(declaration, editor) - runWriteAction { CodeStyleManager.getInstance(declaration.project).reformat(declaration, true) } - } - } - val declaration = element ?: return + var declaration = element ?: return if (declaration is KtClass) { if (declaration.hasModifier(KtTokens.INNER_KEYWORD)) declaration.removeModifier(KtTokens.INNER_KEYWORD) - return - } - val containingClass = declaration.containingClassOrObject ?: return - if (containingClass is KtClass) { - val moveMemberToCompanionObjectIntention = MoveMemberToCompanionObjectIntention() - val (conflicts, externalUsages, outerInstanceUsages) = - moveMemberToCompanionObjectIntention.retrieveConflictsAndUsages(project, editor, declaration, containingClass) - ?: return - - project.checkConflictsInteractively(conflicts) { - ApplicationManagerEx.getApplicationEx().runWriteActionWithNonCancellableProgressInDispatchThread( - KotlinBundle.message("making.member.static"), project, null - ) { - val movedDeclaration = moveMemberToCompanionObjectIntention.doMove( - it, declaration, externalUsages, outerInstanceUsages, editor - ) - makeStaticAndReformat(movedDeclaration, editor) - } + } else { + val containingClass = declaration.containingClassOrObject ?: return + if (containingClass is KtClass) { + val moveMemberToCompanionObjectIntention = MoveMemberToCompanionObjectIntention() + declaration = moveMemberToCompanionObjectIntention.doMove( + EmptyProgressIndicator(), declaration, listOf(), listOf(), editor + ) } - } else makeStaticAndReformat(declaration, editor) + } + if (AddJvmStaticIntention().applicabilityRange(declaration) != null) { + declaration.addAnnotation(JVM_STATIC_FQ_NAME) + CodeStyleManager.getInstance(project).reformat(declaration, true) + } } override fun getText(): String = KotlinBundle.message("make.member.static.quickfix", element?.name ?: "")