From 0ea0eadc51b76abf6c6b05dd7cae5d32bd27d277 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 10 May 2024 15:46:39 +0200 Subject: [PATCH] [mod-commands] IJPL-149593 ModCommand-based Surrounder API GitOrigin-RevId: 56b1bc727db4e686afc6363326c1b079030da414 --- .../quickfix/SurroundWithTryCatchFix.java | 37 ++-------- .../JavaBooleanExpressionSurrounder.java | 15 ---- .../JavaExpressionModCommandSurrounder.java | 53 ++++++++++++++ ...> JavaStatementsModCommandSurrounder.java} | 29 ++++---- .../surroundWith/JavaWithBlockSurrounder.java | 23 +++--- .../JavaWithDoWhileSurrounder.java | 27 +++---- .../surroundWith/JavaWithForSurrounder.java | 37 +++++----- .../JavaWithIfElseExpressionSurrounder.java | 19 ++--- .../JavaWithIfElseSurrounder.java | 31 ++++---- .../JavaWithIfExpressionSurrounder.java | 28 ++++---- .../surroundWith/JavaWithIfSurrounder.java | 20 ++++-- .../JavaWithNotInstanceofSurrounder.java | 27 +++---- .../surroundWith/JavaWithNotSurrounder.java | 22 +++--- .../JavaWithNullCheckSurrounder.java | 19 +++-- .../JavaWithParenthesesSurrounder.java | 17 +++-- .../JavaWithRunnableSurrounder.java | 51 +++++-------- .../JavaWithSynchronizedSurrounder.java | 31 ++++---- .../JavaWithTryCatchSurrounder.java | 71 +++++++++++-------- .../JavaWithTryFinallySurrounder.java | 43 +++++------ .../surroundWith/JavaWithWhileSurrounder.java | 30 ++++---- .../impl/SurroundAutoCloseableAction.java | 13 ++-- .../TryStatementPostfixTemplate.java | 1 + .../introduceField/ElementToWorkOn.java | 29 ++++++++ ...sFirstRunnableSurroundStatement_after.java | 2 +- .../surroundWith/Runnable_after.java | 2 +- .../resources/messages/JavaBundle.properties | 1 - platform/lang-api/api-dump-unreviewed.txt | 6 ++ .../surroundWith/ModCommandSurrounder.java | 71 +++++++++++++++++++ .../surroundWith/SurroundWithHandler.java | 6 +- 29 files changed, 444 insertions(+), 317 deletions(-) delete mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaBooleanExpressionSurrounder.java create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaExpressionModCommandSurrounder.java rename java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/{JavaStatementsSurrounder.java => JavaStatementsModCommandSurrounder.java} (79%) create mode 100644 platform/lang-api/src/com/intellij/lang/surroundWith/ModCommandSurrounder.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SurroundWithTryCatchFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SurroundWithTryCatchFix.java index 604dbbc1854e..1ec6989a29a9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SurroundWithTryCatchFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SurroundWithTryCatchFix.java @@ -3,14 +3,12 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInsight.generation.surroundWith.JavaWithTryCatchSurrounder; -import com.intellij.java.JavaBundle; -import com.intellij.modcommand.*; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModCommandAction; +import com.intellij.modcommand.Presentation; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.CommonJavaRefactoringUtil; -import com.intellij.util.IncorrectOperationException; import com.siyeh.ig.psiutils.CodeBlockSurrounder; import com.siyeh.ig.psiutils.ExpressionUtils; import org.jetbrains.annotations.NotNull; @@ -49,30 +47,7 @@ public class SurroundWithTryCatchFix implements ModCommandAction { @Override public @NotNull ModCommand perform(@NotNull ActionContext context) { - return ModCommand.psiUpdate(myElement, (element, updater) -> invoke(context.project(), element, updater)); - } - - private static void invoke(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) { - if (element instanceof PsiExpression expression) { - CodeBlockSurrounder surrounder = CodeBlockSurrounder.forExpression(ExpressionUtils.getTopLevelExpression(expression)); - if (surrounder == null) return; - element = surrounder.surround().getAnchor(); - } else { - element = CommonJavaRefactoringUtil.getParentStatement(element, false); - if (element == null) return; - } - - TextRange range = null; - - try{ - JavaWithTryCatchSurrounder handler = new JavaWithTryCatchSurrounder(); - range = handler.doSurround(project, element.getParent(), new PsiElement[]{element}); - } - catch(IncorrectOperationException e){ - updater.cancel(JavaBundle.message("surround.with.try.catch.incorrect.template.message")); - } - if (range != null) { - updater.select(range); - } + return ModCommand.psiUpdate(myElement, (element, updater) -> + new JavaWithTryCatchSurrounder().doSurround(context, element, updater)); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaBooleanExpressionSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaBooleanExpressionSurrounder.java deleted file mode 100644 index 10743c8823ee..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaBooleanExpressionSurrounder.java +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.codeInsight.generation.surroundWith; - -import com.intellij.psi.PsiExpression; -import com.intellij.psi.PsiPrimitiveType; -import com.intellij.psi.PsiType; -import com.intellij.psi.PsiTypes; - -public abstract class JavaBooleanExpressionSurrounder extends JavaExpressionSurrounder { - @Override - public boolean isApplicable(PsiExpression expr) { - PsiType type = expr.getType(); - return type != null && (PsiTypes.booleanType().equals(type) || PsiTypes.booleanType().equals(PsiPrimitiveType.getUnboxedType(type))); - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaExpressionModCommandSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaExpressionModCommandSurrounder.java new file mode 100644 index 000000000000..6a99cf6afeae --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaExpressionModCommandSurrounder.java @@ -0,0 +1,53 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.codeInsight.generation.surroundWith; + +import com.intellij.lang.surroundWith.ModCommandSurrounder; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModPsiUpdater; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.project.DumbService; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; +import com.intellij.refactoring.introduceField.ElementToWorkOn; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +/** + * Allows implementing conveniently surrounders (Surround With) when it was called on java expression. + */ +public abstract class JavaExpressionModCommandSurrounder extends ModCommandSurrounder { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.javaExpressionSurrounder"); + + @Override + public boolean isApplicable(PsiElement @NotNull [] elements) { + return elements.length == 1 && + elements[0] instanceof PsiExpression expr && + DumbService.getInstance(expr.getProject()).computeWithAlternativeResolveEnabled(() -> isApplicable(expr)); + } + + /** + * @return true iff the expression can be surrounded using this instance. + */ + public abstract boolean isApplicable(PsiExpression expr); + + @Override + public final @NotNull ModCommand surroundElements(@NotNull ActionContext context, @NotNull PsiElement @NotNull [] elements) { + if (elements.length != 1 || !(elements[0] instanceof PsiExpression expr)) { + throw new IllegalArgumentException(Arrays.toString(elements)); + } + return ModCommand.psiUpdate(context, updater -> surroundExpression(context, ElementToWorkOn.getWritable(expr, updater), updater)); + } + + /** + * Performs the surrounding on non-physical copy, replacing some parent nodes. + *

+ * It is guaranteed that {@link JavaExpressionModCommandSurrounder#isApplicable)} is called and returned true before calling this method. + * + * @param context action context + * @param expr expression on which the action was called + * @param updater updater to use if necessary + */ + protected abstract void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater); +} diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaStatementsSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaStatementsModCommandSurrounder.java similarity index 79% rename from java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaStatementsSurrounder.java rename to java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaStatementsModCommandSurrounder.java index a7ed963b01a9..2b37ad4e39c7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaStatementsSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaStatementsModCommandSurrounder.java @@ -2,10 +2,11 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.generation.surroundWith; -import com.intellij.lang.surroundWith.Surrounder; -import com.intellij.openapi.editor.Editor; +import com.intellij.lang.surroundWith.ModCommandSurrounder; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.DebugUtil; @@ -13,27 +14,27 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import com.siyeh.ig.psiutils.CommentTracker; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -abstract class JavaStatementsSurrounder implements Surrounder { +abstract class JavaStatementsModCommandSurrounder extends ModCommandSurrounder { @Override public boolean isApplicable(PsiElement @NotNull [] elements) { return ContainerUtil.find(elements, PsiSwitchLabelStatementBase.class::isInstance) == null; } @Override - public @Nullable TextRange surroundElements(@NotNull Project project, - @NotNull Editor editor, - PsiElement @NotNull [] elements) throws IncorrectOperationException { + public final @NotNull ModCommand surroundElements(@NotNull ActionContext context, @NotNull PsiElement @NotNull [] elements) { PsiElement container = elements[0].getParent(); - if (container == null) return null; - return surroundStatements(project, editor, container, elements); + if (container == null) return ModCommand.nop(); + return ModCommand.psiUpdate(context, updater -> surroundStatements( + context, updater.getWritable(container), + ContainerUtil.map2Array(elements, PsiElement.EMPTY_ARRAY, updater::getWritable), + updater)); } - protected abstract @Nullable TextRange surroundStatements(final Project project, - final Editor editor, - final PsiElement container, - final PsiElement[] statements) throws IncorrectOperationException; + protected abstract void surroundStatements(@NotNull ActionContext context, + @NotNull PsiElement container, + @NotNull PsiElement @NotNull [] statements, + @NotNull ModPsiUpdater updater) throws IncorrectOperationException; protected static @NotNull PsiStatement addAfter(final PsiStatement statement, final PsiElement container, final PsiElement[] statements) { if (container instanceof PsiSwitchLabeledRuleStatement && !(statement instanceof PsiBlockStatement)) { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithBlockSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithBlockSurrounder.java index 1b57cb0938c6..23053483c233 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithBlockSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithBlockSurrounder.java @@ -16,28 +16,34 @@ */ package com.intellij.codeInsight.generation.surroundWith; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; -public class JavaWithBlockSurrounder extends JavaStatementsSurrounder{ +public class JavaWithBlockSurrounder extends JavaStatementsModCommandSurrounder { @Override public String getTemplateDescription() { return "{ }"; } @Override - public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ + protected void surroundStatements(@NotNull ActionContext context, + @NotNull PsiElement container, + @NotNull PsiElement @NotNull [] statements, + @NotNull ModPsiUpdater updater) throws IncorrectOperationException { + Project project = context.project(); PsiManager manager = PsiManager.getInstance(project); PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false); - if (statements.length == 0){ - return null; + if (statements.length == 0) { + return; } String text = "{\n}"; @@ -52,10 +58,9 @@ public class JavaWithBlockSurrounder extends JavaStatementsSurrounder{ container.deleteChildRange(statements[0], statements[statements.length - 1]); PsiElement firstChild = blockStatement.getFirstChild(); - if (firstChild == null) { - return null; + if (firstChild != null) { + TextRange range = firstChild.getTextRange(); + updater.moveCaretTo(range.getEndOffset()); } - TextRange range = firstChild.getTextRange(); - return new TextRange(range.getEndOffset(), range.getEndOffset()); } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithDoWhileSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithDoWhileSurrounder.java index c3488ce0c416..6c821728b159 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithDoWhileSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithDoWhileSurrounder.java @@ -17,30 +17,33 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; -public class JavaWithDoWhileSurrounder extends JavaStatementsSurrounder{ +public class JavaWithDoWhileSurrounder extends JavaStatementsModCommandSurrounder { @Override public String getTemplateDescription() { return JavaBundle.message("surround.with.dowhile.template"); } @Override - public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ + protected void surroundStatements(@NotNull ActionContext context, + @NotNull PsiElement container, + @NotNull PsiElement @NotNull [] statements, + @NotNull ModPsiUpdater updater) throws IncorrectOperationException { + Project project = context.project(); PsiManager manager = PsiManager.getInstance(project); PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false); - if (statements.length == 0){ - return null; - } + if (statements.length == 0) return; @NonNls String text = "do{\n}while(true);"; PsiDoWhileStatement doWhileStatement = (PsiDoWhileStatement)factory.createStatementFromText(text, null); @@ -49,15 +52,15 @@ public class JavaWithDoWhileSurrounder extends JavaStatementsSurrounder{ doWhileStatement = (PsiDoWhileStatement)addAfter(doWhileStatement, container, statements); PsiStatement body = doWhileStatement.getBody(); - if (!(body instanceof PsiBlockStatement)) { - return null; - } - PsiCodeBlock bodyBlock = ((PsiBlockStatement)body).getCodeBlock(); + if (!(body instanceof PsiBlockStatement block)) return; + PsiCodeBlock bodyBlock = block.getCodeBlock(); SurroundWithUtil.indentCommentIfNecessary(bodyBlock, statements); addRangeWithinContainer(bodyBlock, container, statements, false); container.deleteChildRange(statements[0], statements[statements.length - 1]); PsiExpression condition = doWhileStatement.getCondition(); - return condition == null ? null : condition.getTextRange(); + if (condition != null) { + updater.select(condition); + } } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithForSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithForSurrounder.java index cb0fa9fbd79b..ce9fb5482c2d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithForSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithForSurrounder.java @@ -18,30 +18,33 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; -public class JavaWithForSurrounder extends JavaStatementsSurrounder{ +public class JavaWithForSurrounder extends JavaStatementsModCommandSurrounder { @Override public String getTemplateDescription() { return JavaBundle.message("surround.with.for.template"); } @Override - public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ - PsiManager manager = PsiManager.getInstance(project); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); + protected void surroundStatements(@NotNull ActionContext context, + @NotNull PsiElement container, + @NotNull PsiElement @NotNull [] statements, + @NotNull ModPsiUpdater updater) throws IncorrectOperationException { + Project project = context.project(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, true); - if (statements.length == 0){ - return null; - } + if (statements.length == 0) return; @NonNls String text = "for(a;b;c){\n}"; PsiForStatement forStatement = (PsiForStatement)factory.createStatementFromText(text, null); @@ -50,27 +53,21 @@ public class JavaWithForSurrounder extends JavaStatementsSurrounder{ forStatement = (PsiForStatement)addAfter(forStatement, container, statements); PsiStatement body = forStatement.getBody(); - if (!(body instanceof PsiBlockStatement)) { - return null; - } - PsiCodeBlock bodyBlock = ((PsiBlockStatement)body).getCodeBlock(); + if (!(body instanceof PsiBlockStatement block)) return; + PsiCodeBlock bodyBlock = block.getCodeBlock(); SurroundWithUtil.indentCommentIfNecessary(bodyBlock, statements); addRangeWithinContainer(bodyBlock, container, statements, false); container.deleteChildRange(statements[0], statements[statements.length - 1]); forStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(forStatement); PsiStatement initialization = forStatement.getInitialization(); - if (initialization == null) { - return null; - } + if (initialization == null) return; TextRange range1 = initialization.getTextRange(); PsiStatement update = forStatement.getUpdate(); - if (update == null) { - return null; - } + if (update == null) return; TextRange range3 = update.getTextRange(); - editor.getDocument().deleteString(range1.getStartOffset(), range3.getEndOffset()); - return new TextRange(range1.getStartOffset(), range1.getStartOffset()); + update.getContainingFile().getFileDocument().deleteString(range1.getStartOffset(), range3.getEndOffset()); + updater.moveCaretTo(range1.getStartOffset()); } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfElseExpressionSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfElseExpressionSurrounder.java index 80365458cd10..980b4ba597d1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfElseExpressionSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfElseExpressionSurrounder.java @@ -18,27 +18,30 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; public class JavaWithIfElseExpressionSurrounder extends JavaWithIfExpressionSurrounder{ @Override - public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { - PsiManager manager = expr.getManager(); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); + protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) { + Project project = context.project(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); @NonNls String text = "if(a){\nst;\n}else{\n}"; PsiIfStatement ifStatement = (PsiIfStatement)factory.createStatementFromText(text, null); ifStatement = (PsiIfStatement)codeStyleManager.reformat(ifStatement); - ifStatement.getCondition().replace(expr); + Objects.requireNonNull(ifStatement.getCondition()).replace(expr); PsiExpressionStatement statement = (PsiExpressionStatement)expr.getParent(); ifStatement = (PsiIfStatement)statement.replace(ifStatement); @@ -48,8 +51,8 @@ public class JavaWithIfElseExpressionSurrounder extends JavaWithIfExpressionSurr PsiStatement afterStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(block.getStatements()[0]); TextRange range = afterStatement.getTextRange(); - editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset()); - return new TextRange(range.getStartOffset(), range.getStartOffset()); + afterStatement.getContainingFile().getFileDocument().deleteString(range.getStartOffset(), range.getEndOffset()); + updater.moveCaretTo(range.getStartOffset()); } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfElseSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfElseSurrounder.java index fe4407dce3da..293404d8fc62 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfElseSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfElseSurrounder.java @@ -18,30 +18,33 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.CodeInsightUtilCore; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; -public class JavaWithIfElseSurrounder extends JavaStatementsSurrounder{ +public class JavaWithIfElseSurrounder extends JavaStatementsModCommandSurrounder { @Override public String getTemplateDescription() { return CodeInsightBundle.message("surround.with.ifelse.template"); } @Override - public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ - PsiManager manager = PsiManager.getInstance(project); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); + protected void surroundStatements(@NotNull ActionContext context, + @NotNull PsiElement container, + @NotNull PsiElement @NotNull [] statements, + @NotNull ModPsiUpdater updater) throws IncorrectOperationException { + Project project = context.project(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false); - if (statements.length == 0){ - return null; - } + if (statements.length == 0) return; @NonNls String text = "if(a){\n}else{\n}"; PsiIfStatement ifStatement = (PsiIfStatement)factory.createStatementFromText(text, null); @@ -50,20 +53,16 @@ public class JavaWithIfElseSurrounder extends JavaStatementsSurrounder{ ifStatement = (PsiIfStatement)addAfter(ifStatement, container, statements); PsiStatement thenBranch = ifStatement.getThenBranch(); - if (!(thenBranch instanceof PsiBlockStatement)) { - return null; - } + if (!(thenBranch instanceof PsiBlockStatement)) return; PsiCodeBlock thenBlock = ((PsiBlockStatement)thenBranch).getCodeBlock(); SurroundWithUtil.indentCommentIfNecessary(thenBlock, statements); addRangeWithinContainer(thenBlock, container, statements, true); container.deleteChildRange(statements[0], statements[statements.length - 1]); ifStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(ifStatement); PsiExpression condition = ifStatement.getCondition(); - if (condition == null) { - return null; - } + if (condition == null) return; TextRange range = condition.getTextRange(); - editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset()); - return new TextRange(range.getStartOffset(), range.getStartOffset()); + condition.getContainingFile().getFileDocument().deleteString(range.getStartOffset(), range.getEndOffset()); + updater.moveCaretTo(range.getStartOffset()); } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfExpressionSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfExpressionSurrounder.java index 4ed00ea895cd..fcc62faa0f31 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfExpressionSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfExpressionSurrounder.java @@ -17,20 +17,21 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.CodeInsightUtilCore; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.util.FileTypeUtils; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -public class JavaWithIfExpressionSurrounder extends JavaBooleanExpressionSurrounder { +public class JavaWithIfExpressionSurrounder extends JavaExpressionModCommandSurrounder { @Override public boolean isApplicable(PsiExpression expr) { - if (!super.isApplicable(expr)) return false; + PsiType type = expr.getType(); + if (!(type != null && (PsiTypes.booleanType().equals(type) || PsiTypes.booleanType().equals(PsiPrimitiveType.getUnboxedType(type))))) return false; if (!expr.isPhysical()) return false; PsiElement expressionStatement = expr.getParent(); if (!(expressionStatement instanceof PsiExpressionStatement)) return false; @@ -45,9 +46,9 @@ public class JavaWithIfExpressionSurrounder extends JavaBooleanExpressionSurroun } @Override - public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { - PsiManager manager = expr.getManager(); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); + protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) { + Project project = context.project(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); @NonNls String text = "if(a){\nst;\n}"; @@ -63,14 +64,13 @@ public class JavaWithIfExpressionSurrounder extends JavaBooleanExpressionSurroun ifStatement = (PsiIfStatement)statement.replace(ifStatement); PsiStatement thenBranch = ifStatement.getThenBranch(); - if (thenBranch instanceof PsiBlockStatement) { - PsiCodeBlock block = ((PsiBlockStatement)thenBranch).getCodeBlock(); + if (thenBranch instanceof PsiBlockStatement blockStatement) { + PsiCodeBlock block = blockStatement.getCodeBlock(); block = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(block); TextRange range = block.getStatements()[0].getTextRange(); - editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset()); - return TextRange.from(range.getStartOffset(), 0); + block.getContainingFile().getFileDocument().deleteString(range.getStartOffset(), range.getEndOffset()); + updater.moveCaretTo(range.getStartOffset()); } - return TextRange.from(editor.getCaretModel().getOffset(), 0); } @Override @@ -79,8 +79,8 @@ public class JavaWithIfExpressionSurrounder extends JavaBooleanExpressionSurroun } private static boolean isElseBranch(@NotNull PsiExpression expression, @NotNull PsiElement statementParent) { - if (statementParent instanceof PsiIfStatement) { - PsiStatement elseBranch = ((PsiIfStatement)statementParent).getElseBranch(); + if (statementParent instanceof PsiIfStatement ifStatement) { + PsiStatement elseBranch = ifStatement.getElseBranch(); if (elseBranch != null && elseBranch.getFirstChild() == expression) { return true; } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfSurrounder.java index 884adc77c45d..bf83dd6bd31a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithIfSurrounder.java @@ -3,30 +3,36 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.CodeInsightUtilCore; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; -public class JavaWithIfSurrounder extends JavaStatementsSurrounder{ +public class JavaWithIfSurrounder extends JavaStatementsModCommandSurrounder { @Override public String getTemplateDescription() { return CodeInsightBundle.message("surround.with.if.template"); } @Override - public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) { - PsiIfStatement ifStatement = surroundStatements(project, container, statements, ""); - if (ifStatement == null) return null; + protected void surroundStatements(@NotNull ActionContext context, + @NotNull PsiElement container, + @NotNull PsiElement @NotNull [] statements, + @NotNull ModPsiUpdater updater) throws IncorrectOperationException { + PsiIfStatement ifStatement = surroundStatements(context.project(), container, statements, ""); + if (ifStatement == null) return; ifStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(ifStatement); - if (ifStatement == null) return null; + if (ifStatement == null) return; final PsiJavaToken lParenth = ifStatement.getLParenth(); assert lParenth != null; final TextRange range = lParenth.getTextRange(); - return new TextRange(range.getEndOffset(), range.getEndOffset()); + updater.moveCaretTo(range.getEndOffset()); } public PsiIfStatement surroundStatements(Project project, PsiElement container, PsiElement[] statements, String condition) { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNotInstanceofSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNotInstanceofSurrounder.java index 1ad5ea272d09..e97ac5fac8c8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNotInstanceofSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNotInstanceofSurrounder.java @@ -18,14 +18,17 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; -class JavaWithNotInstanceofSurrounder extends JavaExpressionSurrounder{ +import java.util.Objects; + +class JavaWithNotInstanceofSurrounder extends JavaExpressionModCommandSurrounder { @Override public boolean isApplicable(PsiExpression expr) { PsiType type = expr.getType(); @@ -35,23 +38,23 @@ class JavaWithNotInstanceofSurrounder extends JavaExpressionSurrounder{ } @Override - public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { - PsiManager manager = expr.getManager(); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); + protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) { + Project project = context.project(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); PsiPrefixExpression prefixExpr = (PsiPrefixExpression)factory.createExpressionFromText("!(a instanceof Type)", null); prefixExpr = (PsiPrefixExpression)codeStyleManager.reformat(prefixExpr); - PsiParenthesizedExpression parenthExpr = (PsiParenthesizedExpression)prefixExpr.getOperand(); - PsiInstanceOfExpression instanceofExpr = (PsiInstanceOfExpression)parenthExpr.getExpression(); + PsiParenthesizedExpression parenthExpr = (PsiParenthesizedExpression)Objects.requireNonNull(prefixExpr.getOperand()); + PsiInstanceOfExpression instanceofExpr = (PsiInstanceOfExpression)Objects.requireNonNull(parenthExpr.getExpression()); instanceofExpr.getOperand().replace(expr); prefixExpr = (PsiPrefixExpression)expr.replace(prefixExpr); - parenthExpr = (PsiParenthesizedExpression)prefixExpr.getOperand(); - instanceofExpr = (PsiInstanceOfExpression)parenthExpr.getExpression(); + parenthExpr = (PsiParenthesizedExpression)Objects.requireNonNull(prefixExpr.getOperand()); + instanceofExpr = (PsiInstanceOfExpression)Objects.requireNonNull(parenthExpr.getExpression()); instanceofExpr = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(instanceofExpr); TextRange range = instanceofExpr.getCheckType().getTextRange(); - editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset()); - return new TextRange(range.getStartOffset(), range.getStartOffset()); + instanceofExpr.getContainingFile().getFileDocument().deleteString(range.getStartOffset(), range.getEndOffset()); + updater.moveCaretTo(range.getStartOffset()); } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNotSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNotSurrounder.java index 32ac9b03ca6e..a2912c13367f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNotSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNotSurrounder.java @@ -17,19 +17,19 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.refactoring.IntroduceVariableUtil; -import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; -public class JavaWithNotSurrounder extends JavaBooleanExpressionSurrounder { +public class JavaWithNotSurrounder extends JavaExpressionModCommandSurrounder { @Override - public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { - PsiManager manager = expr.getManager(); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); + protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) { + Project project = context.project(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); PsiPrefixExpression prefixExpr = (PsiPrefixExpression)factory.createExpressionFromText("!(a)", null); @@ -37,11 +37,17 @@ public class JavaWithNotSurrounder extends JavaBooleanExpressionSurrounder { ((PsiParenthesizedExpression)prefixExpr.getOperand()).getExpression().replace(expr); expr = (PsiExpression)IntroduceVariableUtil.replace(expr, prefixExpr, project); int offset = expr.getTextRange().getEndOffset(); - return new TextRange(offset, offset); + updater.moveCaretTo(offset); } @Override public String getTemplateDescription() { return CodeInsightBundle.message("surround.with.not.template"); } + + @Override + public boolean isApplicable(PsiExpression expr) { + PsiType type = expr.getType(); + return type != null && (PsiTypes.booleanType().equals(type) || PsiTypes.booleanType().equals(PsiPrimitiveType.getUnboxedType(type))); + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNullCheckSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNullCheckSurrounder.java index 757dd816fab8..bf7a50e5ad2c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNullCheckSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithNullCheckSurrounder.java @@ -1,4 +1,3 @@ - /* * Copyright 2000-2012 JetBrains s.r.o. * @@ -18,17 +17,16 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.util.FileTypeUtils; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; -public class JavaWithNullCheckSurrounder extends JavaExpressionSurrounder{ +public class JavaWithNullCheckSurrounder extends JavaExpressionModCommandSurrounder{ @Override public boolean isApplicable(PsiExpression expr) { PsiType type = expr.getType(); @@ -43,10 +41,9 @@ public class JavaWithNullCheckSurrounder extends JavaExpressionSurrounder{ } @Override - public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { - PsiManager manager = expr.getManager(); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); - CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); + protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) { + PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.project()); + CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(context.project()); @NonNls String text = "if(a != null){\nst;\n}"; PsiIfStatement ifStatement = (PsiIfStatement)factory.createStatementFromText(text, null); @@ -61,7 +58,7 @@ public class JavaWithNullCheckSurrounder extends JavaExpressionSurrounder{ block = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(block); PsiElement replace = block.getStatements()[0].replace(factory.createStatementFromText(oldText, block)); int offset = replace.getTextRange().getEndOffset(); - return new TextRange(offset, offset); + updater.moveCaretTo(offset); } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithParenthesesSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithParenthesesSurrounder.java index 7301cae0db1d..81466d07afd6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithParenthesesSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithParenthesesSurrounder.java @@ -1,4 +1,3 @@ - /* * Copyright 2000-2009 JetBrains s.r.o. * @@ -17,24 +16,24 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.refactoring.IntroduceVariableUtil; -import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; -public class JavaWithParenthesesSurrounder extends JavaExpressionSurrounder{ +public class JavaWithParenthesesSurrounder extends JavaExpressionModCommandSurrounder{ @Override public boolean isApplicable(PsiExpression expr) { return !PsiTypes.voidType().equals(expr.getType()); } @Override - public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { - PsiManager manager = expr.getManager(); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); + protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) { + Project project = context.project(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); PsiParenthesizedExpression parenthExpr = (PsiParenthesizedExpression)factory.createExpressionFromText("(a)", null); @@ -42,7 +41,7 @@ public class JavaWithParenthesesSurrounder extends JavaExpressionSurrounder{ parenthExpr.getExpression().replace(expr); expr = (PsiExpression)IntroduceVariableUtil.replace(expr, parenthExpr, project); int offset = expr.getTextRange().getEndOffset(); - return new TextRange(offset, offset); + updater.moveCaretTo(offset); } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithRunnableSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithRunnableSurrounder.java index 83911a1bf0ef..06928029555f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithRunnableSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithRunnableSurrounder.java @@ -3,34 +3,37 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiUtil; -import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; +import java.util.List; -public class JavaWithRunnableSurrounder extends JavaStatementsSurrounder{ +public class JavaWithRunnableSurrounder extends JavaStatementsModCommandSurrounder { @Override public String getTemplateDescription() { return JavaBundle.message("surround.with.runnable.template"); } @Override - public TextRange surroundStatements(Project project, final Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ - PsiManager manager = container.getManager(); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); + protected void surroundStatements(@NotNull ActionContext context, + @NotNull PsiElement container, + @NotNull PsiElement @NotNull [] statements, + @NotNull ModPsiUpdater updater) throws IncorrectOperationException { + Project project = context.project(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); final String baseName = "runnable"; final String uniqueName = JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName(baseName, container, false); @@ -56,29 +59,7 @@ public class JavaWithRunnableSurrounder extends JavaStatementsSurrounder{ container.deleteChildRange(statements[0], statements[statements.length - 1]); makeVariablesFinal(body, body); - - PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); - final int textOffset = variable.getNameIdentifier().getTextOffset(); - editor.getCaretModel().moveToOffset(textOffset); - editor.getSelectionModel().removeSelection(); - new VariableInplaceRenamer(variable, editor){ - @Override - protected boolean shouldSelectAll() { - return true; - } - - @Override - protected void moveOffsetAfter(boolean success) { - super.moveOffsetAfter(success); - if (success) { - final PsiNamedElement renamedVariable = getVariable(); - if (renamedVariable != null) { - editor.getCaretModel().moveToOffset(renamedVariable.getTextRange().getEndOffset()); - } - } - } - }.performInplaceRename(); - return null; + updater.rename(variable, List.of(uniqueName)); } private static void makeVariablesFinal(PsiElement scope, PsiCodeBlock body) throws IncorrectOperationException{ @@ -88,13 +69,13 @@ public class JavaWithRunnableSurrounder extends JavaStatementsSurrounder{ for (PsiElement child : children) { makeVariablesFinal(child, body); - if (child instanceof PsiReferenceExpression) { + if (child instanceof PsiReferenceExpression ref) { if (child.getParent() instanceof PsiMethodCallExpression) continue; - if (PsiUtil.isAccessedForWriting((PsiReferenceExpression) child)) { + if (PsiUtil.isAccessedForWriting(ref)) { continue; } - PsiElement refElement = ((PsiReferenceExpression)child).resolve(); + PsiElement refElement = ref.resolve(); if (refElement instanceof PsiLocalVariable || refElement instanceof PsiParameter) { PsiVariable variable = (PsiVariable) refElement; final PsiModifierList modifierList = variable.getModifierList(); @@ -107,8 +88,8 @@ public class JavaWithRunnableSurrounder extends JavaStatementsSurrounder{ while (parent != null) { if (parent.equals(body)) break; - if (parent instanceof PsiMethod) { - enclosingMethod = (PsiMethod) parent; + if (parent instanceof PsiMethod method) { + enclosingMethod = method; } parent = parent.getParent(); } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithSynchronizedSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithSynchronizedSurrounder.java index 418c9a2e8c4c..21c6a3e19cca 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithSynchronizedSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithSynchronizedSurrounder.java @@ -18,30 +18,33 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; -public class JavaWithSynchronizedSurrounder extends JavaStatementsSurrounder{ +public class JavaWithSynchronizedSurrounder extends JavaStatementsModCommandSurrounder { @Override public String getTemplateDescription() { return JavaBundle.message("surround.with.synchronized.template"); } @Override - public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ - PsiManager manager = PsiManager.getInstance(project); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); + protected void surroundStatements(@NotNull ActionContext context, + @NotNull PsiElement container, + @NotNull PsiElement @NotNull [] statements, + @NotNull ModPsiUpdater updater) throws IncorrectOperationException { + Project project = context.project(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false); - if (statements.length == 0){ - return null; - } + if (statements.length == 0) return; @NonNls String text = "synchronized(a){\n}"; PsiSynchronizedStatement synchronizedStatement = (PsiSynchronizedStatement)factory.createStatementFromText(text, null); @@ -50,20 +53,16 @@ public class JavaWithSynchronizedSurrounder extends JavaStatementsSurrounder{ synchronizedStatement = (PsiSynchronizedStatement)addAfter(synchronizedStatement, container, statements); PsiCodeBlock synchronizedBlock = synchronizedStatement.getBody(); - if (synchronizedBlock == null) { - return null; - } + if (synchronizedBlock == null) return; SurroundWithUtil.indentCommentIfNecessary(synchronizedBlock, statements); addRangeWithinContainer(synchronizedBlock, container, statements, true); container.deleteChildRange(statements[0], statements[statements.length - 1]); synchronizedStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(synchronizedStatement); PsiExpression lockExpression = synchronizedStatement.getLockExpression(); - if (lockExpression == null) { - return null; - } + if (lockExpression == null) return; TextRange range = lockExpression.getTextRange(); - editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset()); - return new TextRange(range.getStartOffset(), range.getStartOffset()); + lockExpression.getContainingFile().getFileDocument().deleteString(range.getStartOffset(), range.getEndOffset()); + updater.moveCaretTo(range.getStartOffset()); } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryCatchSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryCatchSurrounder.java index 1b70be3910e0..212764b5fe58 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryCatchSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryCatchSurrounder.java @@ -3,25 +3,26 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.ExceptionUtil; import com.intellij.java.JavaBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.util.CommonJavaRefactoringUtil; import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.psiutils.CodeBlockSurrounder; +import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.VariableNameGenerator; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Collections; import java.util.List; -public class JavaWithTryCatchSurrounder extends JavaStatementsSurrounder { +public class JavaWithTryCatchSurrounder extends JavaStatementsModCommandSurrounder { protected boolean myGenerateFinally; @Override @@ -30,29 +31,19 @@ public class JavaWithTryCatchSurrounder extends JavaStatementsSurrounder { } @Override - public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) - throws IncorrectOperationException { - try { - return doSurround(project, container, statements); - } - catch (IncorrectOperationException e) { - Messages.showErrorDialog(project, JavaBundle.message("surround.with.try.catch.incorrect.template.message"), - JavaBundle.message("surround.with.try.catch.incorrect.template.title")); - return null; - } - } - - public @Nullable TextRange doSurround(Project project, PsiElement container, PsiElement[] origStatements) { + protected void surroundStatements(@NotNull ActionContext context, + @NotNull PsiElement container, + @NotNull PsiElement @NotNull [] statements, + @NotNull ModPsiUpdater updater) throws IncorrectOperationException { + Project project = context.project(); PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); - PsiElement[] statements = SurroundWithUtil.moveDeclarationsOut(container, origStatements, true); - if (statements.length == 0) { - return null; - } + PsiElement[] statements1 = SurroundWithUtil.moveDeclarationsOut(container, statements, true); + if (statements1.length == 0) return; - return DumbService.getInstance(project).computeWithAlternativeResolveEnabled(() -> { - List exceptions = getExceptionTypes(container, statements, factory); + DumbService.getInstance(project).runWithAlternativeResolveEnabled(() -> { + List exceptions = getExceptionTypes(container, statements1, factory); @NonNls StringBuilder buffer = new StringBuilder(); buffer.append("try{\n}"); @@ -66,11 +57,11 @@ public class JavaWithTryCatchSurrounder extends JavaStatementsSurrounder { PsiTryStatement tryStatement = (PsiTryStatement)factory.createStatementFromText(text, null); tryStatement = (PsiTryStatement)CodeStyleManager.getInstance(project).reformat(tryStatement); - tryStatement = (PsiTryStatement)addAfter(tryStatement, container, statements); + tryStatement = (PsiTryStatement)addAfter(tryStatement, container, statements1); PsiCodeBlock tryBlock = tryStatement.getTryBlock(); - SurroundWithUtil.indentCommentIfNecessary(tryBlock, statements); - addRangeWithinContainer(tryBlock, container, statements, true); + SurroundWithUtil.indentCommentIfNecessary(tryBlock, statements1); + addRangeWithinContainer(tryBlock, container, statements1, true); PsiCatchSection[] catchSections = tryStatement.getCatchSections(); @@ -85,18 +76,38 @@ public class JavaWithTryCatchSurrounder extends JavaStatementsSurrounder { } String name = new VariableNameGenerator(tryBlock, VariableKind.PARAMETER).byName("e", "ex", "exc").byType(exception).generate(false); - PsiCatchSection catchSection = factory.createCatchSection(exception, name, tryBlock); + PsiCatchSection catchSection; + try { + catchSection = factory.createCatchSection(exception, name, tryBlock); + } + catch (IncorrectOperationException e) { + updater.cancel(JavaBundle.message("surround.with.try.catch.incorrect.template.message")); + return; + } catchSection = (PsiCatchSection)catchSections[i].replace(catchSection); codeStyleManager.shortenClassReferences(catchSection); } - container.deleteChildRange(statements[0], statements[statements.length - 1]); + container.deleteChildRange(statements1[0], statements1[statements1.length - 1]); PsiCodeBlock firstCatch = tryStatement.getCatchBlocks()[0]; - return SurroundWithUtil.getRangeToSelect(firstCatch); + + updater.select(SurroundWithUtil.getRangeToSelect(firstCatch)); }); } + public void doSurround(ActionContext context, PsiElement element, ModPsiUpdater updater) { + if (element instanceof PsiExpression expression) { + CodeBlockSurrounder surrounder = CodeBlockSurrounder.forExpression(ExpressionUtils.getTopLevelExpression(expression)); + if (surrounder == null) return; + element = surrounder.surround().getAnchor(); + } else { + element = CommonJavaRefactoringUtil.getParentStatement(element, false); + if (element == null) return; + } + surroundStatements(context, element.getParent(), new PsiElement[]{element}, updater); + } + private static @NotNull List getExceptionTypes(PsiElement container, PsiElement[] statements, PsiElementFactory factory) { List exceptions = ExceptionUtil.getUnhandledExceptions(statements); if (exceptions.isEmpty()) { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java index 33731fdd0b59..45f2a6645c21 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java @@ -16,34 +16,36 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.openapi.diagnostic.Logger; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiNavigator; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; -public class JavaWithTryFinallySurrounder extends JavaStatementsSurrounder{ - private static final Logger LOG = Logger.getInstance(JavaWithTryFinallySurrounder.class); - +public class JavaWithTryFinallySurrounder extends JavaStatementsModCommandSurrounder { + @SuppressWarnings("DialogTitleCapitalization") @Override public String getTemplateDescription() { return CodeInsightBundle.message("surround.with.try.finally.template"); } @Override - public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ - PsiManager manager = PsiManager.getInstance(project); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); + protected void surroundStatements(@NotNull ActionContext context, + @NotNull PsiElement container, + @NotNull PsiElement @NotNull [] statements, + @NotNull ModPsiUpdater updater) throws IncorrectOperationException { + Project project = context.project(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false); - if (statements.length == 0){ - return null; - } + if (statements.length == 0) return; @NonNls String text = "try{\n}finally{\n\n}"; PsiTryStatement tryStatement = (PsiTryStatement)factory.createStatementFromText(text, null); @@ -52,29 +54,22 @@ public class JavaWithTryFinallySurrounder extends JavaStatementsSurrounder{ tryStatement = (PsiTryStatement)addAfter(tryStatement, container, statements); PsiCodeBlock tryBlock = tryStatement.getTryBlock(); - if (tryBlock == null) { - return null; - } + if (tryBlock == null) return; SurroundWithUtil.indentCommentIfNecessary(tryBlock, statements); addRangeWithinContainer(tryBlock, container, statements, true); container.deleteChildRange(statements[0], statements[statements.length - 1]); PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); - if (finallyBlock == null) { - return null; - } - moveCaretToFinallyBlock(project, editor, finallyBlock); - return new TextRange(editor.getCaretModel().getOffset(), editor.getCaretModel().getOffset()); + if (finallyBlock == null) return; + moveCaretToFinallyBlock(project, updater, finallyBlock); } - public static void moveCaretToFinallyBlock(Project project, Editor editor, PsiCodeBlock finallyBlock) { - Document document = editor.getDocument(); + public static void moveCaretToFinallyBlock(Project project, ModPsiNavigator navigator, PsiCodeBlock finallyBlock) { + Document document = finallyBlock.getContainingFile().getFileDocument(); PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document); TextRange finallyBlockRange = finallyBlock.getTextRange(); int newLineOffset = finallyBlockRange.getStartOffset() + 2; - editor.getCaretModel().moveToOffset(newLineOffset); - editor.getSelectionModel().removeSelection(); - CodeStyleManager.getInstance(project).adjustLineIndent(document, newLineOffset); + navigator.moveCaretTo(CodeStyleManager.getInstance(project).adjustLineIndent(document, newLineOffset)); PsiDocumentManager.getInstance(project).commitDocument(document); } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithWhileSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithWhileSurrounder.java index 1058cc31bda8..f4aa645b9515 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithWhileSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithWhileSurrounder.java @@ -17,30 +17,32 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.openapi.editor.Editor; +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; -public class JavaWithWhileSurrounder extends JavaStatementsSurrounder{ +public class JavaWithWhileSurrounder extends JavaStatementsModCommandSurrounder { @Override public String getTemplateDescription() { return CodeInsightBundle.message("surround.with.while.template"); } @Override - public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ - PsiManager manager = PsiManager.getInstance(project); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); + protected void surroundStatements(@NotNull ActionContext context, + @NotNull PsiElement container, + @NotNull PsiElement @NotNull [] statements, + @NotNull ModPsiUpdater updater) throws IncorrectOperationException { + Project project = context.project(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, true); - if (statements.length == 0){ - return null; - } + if (statements.length == 0) return; @NonNls String text = "while(true){\n}"; PsiWhileStatement whileStatement = (PsiWhileStatement)factory.createStatementFromText(text, null); @@ -49,15 +51,15 @@ public class JavaWithWhileSurrounder extends JavaStatementsSurrounder{ whileStatement = (PsiWhileStatement)addAfter(whileStatement, container, statements); PsiStatement body = whileStatement.getBody(); - if (!(body instanceof PsiBlockStatement)) { - return null; - } - PsiCodeBlock bodyBlock = ((PsiBlockStatement)body).getCodeBlock(); + if (!(body instanceof PsiBlockStatement block)) return; + PsiCodeBlock bodyBlock = block.getCodeBlock(); SurroundWithUtil.indentCommentIfNecessary(bodyBlock, statements); addRangeWithinContainer(bodyBlock, container, statements, false); container.deleteChildRange(statements[0], statements[statements.length - 1]); PsiExpression condition = whileStatement.getCondition(); - return condition == null ? null : condition.getTextRange(); + if (condition != null) { + updater.select(condition); + } } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SurroundAutoCloseableAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SurroundAutoCloseableAction.java index d8fb121ec9b1..cb218601fc5a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SurroundAutoCloseableAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SurroundAutoCloseableAction.java @@ -5,12 +5,11 @@ import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.codeInsight.template.impl.ConstantNode; import com.intellij.java.JavaBundle; import com.intellij.lang.java.JavaLanguage; +import com.intellij.lang.surroundWith.ModCommandSurrounder; import com.intellij.lang.surroundWith.SurroundDescriptor; import com.intellij.lang.surroundWith.Surrounder; import com.intellij.modcommand.*; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; import com.intellij.pom.java.JavaFeature; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; @@ -258,7 +257,7 @@ public final class SurroundAutoCloseableAction extends PsiUpdateModCommandAction return JavaBundle.message("intention.surround.resource.with.ARM.block"); } - public static final class Template implements SurroundDescriptor, Surrounder { + public static final class Template extends ModCommandSurrounder implements SurroundDescriptor { private final Surrounder[] mySurrounders = {this}; @Override @@ -293,13 +292,11 @@ public final class SurroundAutoCloseableAction extends PsiUpdateModCommandAction } @Override - public @Nullable TextRange surroundElements(@NotNull Project project, @NotNull Editor editor, PsiElement @NotNull [] elements) { + public @NotNull ModCommand surroundElements(@NotNull ActionContext context, @NotNull PsiElement @NotNull [] elements) { if (elements.length == 1) { - ActionContext context = ActionContext.from(editor, elements[0].getContainingFile()); - ModCommand command = new SurroundAutoCloseableAction().perform(context, elements[0]); - ModCommandExecutor.getInstance().executeInteractively(context, command, editor); + return new SurroundAutoCloseableAction().perform(context, elements[0]); } - return null; + return ModCommand.nop(); } } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java index db4305813272..7c0c69731b12 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java @@ -51,6 +51,7 @@ public class TryStatementPostfixTemplate extends PostfixTemplate implements Dumb return; } + editor.getSelectionModel().removeSelection(); PsiElement element = file.findElementAt(range.getStartOffset()); PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(element, PsiTryStatement.class); assert tryStatement != null; diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/ElementToWorkOn.java b/java/java-impl/src/com/intellij/refactoring/introduceField/ElementToWorkOn.java index e2ca1c6153da..b083f9424a0c 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/ElementToWorkOn.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/ElementToWorkOn.java @@ -5,6 +5,7 @@ import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.codeInsight.TargetElementUtil; import com.intellij.codeInsight.unwrap.ScopeHighlighter; import com.intellij.java.refactoring.JavaRefactoringBundle; +import com.intellij.modcommand.ModPsiUpdater; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.project.Project; @@ -209,6 +210,34 @@ public final class ElementToWorkOn { CommonRefactoringUtil.showErrorHint(project, editor, message, refactoringName, helpId); } + /** + * @param type of the element + * @param element either a physical element, or a non-physical copy returned from + * {@link IntroduceVariableUtil#getSelectedExpression(Project, PsiFile, int, int)} or a similar method + * (with ElementToWorkOn metadata set). + * @param updater an updater for current {@link com.intellij.modcommand.ModCommand} session + * @return a copy of the original element suitable for subsequent processing within the ModCommand. + */ + public static @NotNull E getWritable(@NotNull E element, @NotNull ModPsiUpdater updater) { + PsiElement parent = element.getUserData(PARENT); + if (parent != null) { + PsiElement writableParent = updater.getWritable(parent); + @SuppressWarnings("unchecked") E copy = (E)element.copy(); + copy.putUserData(PARENT, writableParent); + copy.putUserData(PREFIX, element.getUserData(PREFIX)); + copy.putUserData(SUFFIX, element.getUserData(SUFFIX)); + copy.putUserData(EXPR_RANGE, element.getUserData(EXPR_RANGE)); + RangeMarker marker = element.getUserData(TEXT_RANGE); + if (marker != null) { + copy.putUserData(TEXT_RANGE, writableParent.getContainingFile().getFileDocument().createRangeMarker(marker.getTextRange())); + } + return copy; + } + E writable = updater.getWritable(element); + writable.putUserData(REPLACE_NON_PHYSICAL, true); + return writable; + } + public interface ElementsProcessor { boolean accept(ElementToWorkOn el); void pass(T t); diff --git a/java/java-tests/testData/codeInsight/generation/surroundWith/java/CommentAsFirstRunnableSurroundStatement_after.java b/java/java-tests/testData/codeInsight/generation/surroundWith/java/CommentAsFirstRunnableSurroundStatement_after.java index 30ae98a335fc..dbe5843a32aa 100644 --- a/java/java-tests/testData/codeInsight/generation/surroundWith/java/CommentAsFirstRunnableSurroundStatement_after.java +++ b/java/java-tests/testData/codeInsight/generation/surroundWith/java/CommentAsFirstRunnableSurroundStatement_after.java @@ -1,6 +1,6 @@ class Test { void foo() { - Runnable runnable = new Runnable() { + Runnable runnable = new Runnable() { public void run() { // This is comment" int i = 1; diff --git a/java/java-tests/testData/codeInsight/surroundWith/Runnable_after.java b/java/java-tests/testData/codeInsight/surroundWith/Runnable_after.java index 35837c5082d1..f3a9feca1a42 100644 --- a/java/java-tests/testData/codeInsight/surroundWith/Runnable_after.java +++ b/java/java-tests/testData/codeInsight/surroundWith/Runnable_after.java @@ -17,7 +17,7 @@ class External { int innerLocal4 = 7; String incorrect; - Runnable runnable = new Runnable() { + Runnable runnable = new Runnable() { public void run() { int insideRunnable1 = param1 + ((++innerLocal2) << param2); param2 = local1 * insideRunnable1; diff --git a/java/openapi/resources/messages/JavaBundle.properties b/java/openapi/resources/messages/JavaBundle.properties index 81f095039ec5..61e92f2dcbb7 100644 --- a/java/openapi/resources/messages/JavaBundle.properties +++ b/java/openapi/resources/messages/JavaBundle.properties @@ -1303,7 +1303,6 @@ surround.with.runnable.template=Runnable surround.with.synchronized.template=synchronized surround.with.try.catch.finally.template=try / catch / finally surround.with.try.catch.incorrect.template.message=Invalid file template for catch body -surround.with.try.catch.incorrect.template.title=Surround With Try / Catch surround.with.try.catch.template=try / catch surround.with.cast=Surround With Cast tab.title.entry.points=Entry points diff --git a/platform/lang-api/api-dump-unreviewed.txt b/platform/lang-api/api-dump-unreviewed.txt index a533362764c5..893129773c6c 100644 --- a/platform/lang-api/api-dump-unreviewed.txt +++ b/platform/lang-api/api-dump-unreviewed.txt @@ -3464,6 +3464,12 @@ com.intellij.lang.parameterInfo.UpdateParameterInfoContext - a:setParameterOwner(com.intellij.psi.PsiElement):V - a:setPreservedOnHintHidden(Z):V - a:setUIComponentEnabled(I,Z):V +*a:com.intellij.lang.surroundWith.ModCommandSurrounder +- com.intellij.lang.surroundWith.Surrounder +- ():V +- f:startInWriteAction():Z +- a:surroundElements(com.intellij.modcommand.ActionContext,com.intellij.psi.PsiElement[]):com.intellij.modcommand.ModCommand +- f:surroundElements(com.intellij.openapi.project.Project,com.intellij.openapi.editor.Editor,com.intellij.psi.PsiElement[]):com.intellij.openapi.util.TextRange com.intellij.lang.surroundWith.SurroundDescriptor - a:getElementsToSurround(com.intellij.psi.PsiFile,I,I):com.intellij.psi.PsiElement[] - a:getSurrounders():com.intellij.lang.surroundWith.Surrounder[] diff --git a/platform/lang-api/src/com/intellij/lang/surroundWith/ModCommandSurrounder.java b/platform/lang-api/src/com/intellij/lang/surroundWith/ModCommandSurrounder.java new file mode 100644 index 000000000000..38c5e4421eb4 --- /dev/null +++ b/platform/lang-api/src/com/intellij/lang/surroundWith/ModCommandSurrounder.java @@ -0,0 +1,71 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.lang.surroundWith; + +import com.intellij.modcommand.ActionContext; +import com.intellij.modcommand.ModCommand; +import com.intellij.modcommand.ModCommandExecutor; +import com.intellij.modcommand.ModNavigate; +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +/** + * A surrounder that generates {@link ModCommand} instead of execution the action directly + */ +@ApiStatus.Experimental +public abstract class ModCommandSurrounder implements Surrounder { + @Override + public final boolean startInWriteAction() { + return false; + } + + /** + * Generates the {@link ModCommand} for the Code | Surround With action on the specified range of elements. + *

+ * @param elements the elements to be surrounded + * @return ModCommand, which when executed, will perform the surrounding. It may also modify the caret position. + */ + public abstract @NotNull ModCommand surroundElements(@NotNull ActionContext context, @NotNull PsiElement @NotNull [] elements); + + @Override + public final @Nullable TextRange surroundElements(@NotNull Project project, @NotNull Editor editor, PsiElement @NotNull [] elements) + throws IncorrectOperationException { + if (elements.length == 0) { + return null; + } + PsiDocumentManager manager = PsiDocumentManager.getInstance(project); + Document document = editor.getDocument(); + PsiFile file = manager.getPsiFile(document); + if (file == null) return null; + WriteAction.run(() -> manager.doPostponedOperationsAndUnblockDocument(document)); + ActionContext context = ActionContext.from(editor, file); + var commandSupplier = new Supplier() { + TextRange range; + + @Override + public ModCommand get() { + ModCommand command = ModCommandSurrounder.this.surroundElements(context, elements); + ModNavigate navigate = ContainerUtil.findInstance(command.unpack(), ModNavigate.class); + if (navigate != null) { + range = TextRange.create(navigate.selectionStart(), navigate.selectionEnd()); + } + return command; + } + }; + String title = getTemplateDescription(); + ModCommandExecutor.executeInteractively(context, title, editor, commandSupplier); + return commandSupplier.range; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java index 62f6bf533aeb..d1060eaa349c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java @@ -16,6 +16,7 @@ import com.intellij.lang.LangBundle; import com.intellij.lang.Language; import com.intellij.lang.LanguageSurrounders; import com.intellij.lang.folding.CustomFoldingSurroundDescriptor; +import com.intellij.lang.surroundWith.ModCommandSurrounder; import com.intellij.lang.surroundWith.SurroundDescriptor; import com.intellij.lang.surroundWith.Surrounder; import com.intellij.openapi.actionSystem.*; @@ -221,8 +222,11 @@ public final class SurroundWithHandler implements CodeInsightActionHandler { ); } else { CommandProcessor.getInstance().executeCommand(project, () -> { + editor.getSelectionModel().removeSelection(); TextRange range = ReadAction.compute(() -> surrounder.surroundElements(project, editor, elements)); - updateRange(project, editor, range, line, col); + if (!(surrounder instanceof ModCommandSurrounder)) { + updateRange(project, editor, range, line, col); + } }, CodeInsightBundle.message("surround.with.chooser.title"), null); } }