[mod-commands] IJPL-149593 ModCommand-based Surrounder API

GitOrigin-RevId: 56b1bc727db4e686afc6363326c1b079030da414
This commit is contained in:
Tagir Valeev
2024-05-10 15:46:39 +02:00
committed by intellij-monorepo-bot
parent c2791ac6f2
commit 0ea0eadc51
29 changed files with 444 additions and 317 deletions

View File

@@ -3,14 +3,12 @@ package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.generation.surroundWith.JavaWithTryCatchSurrounder; import com.intellij.codeInsight.generation.surroundWith.JavaWithTryCatchSurrounder;
import com.intellij.java.JavaBundle; import com.intellij.modcommand.ActionContext;
import com.intellij.modcommand.*; import com.intellij.modcommand.ModCommand;
import com.intellij.openapi.project.Project; import com.intellij.modcommand.ModCommandAction;
import com.intellij.openapi.util.TextRange; import com.intellij.modcommand.Presentation;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil; 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.CodeBlockSurrounder;
import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.ExpressionUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -49,30 +47,7 @@ public class SurroundWithTryCatchFix implements ModCommandAction {
@Override @Override
public @NotNull ModCommand perform(@NotNull ActionContext context) { public @NotNull ModCommand perform(@NotNull ActionContext context) {
return ModCommand.psiUpdate(myElement, (element, updater) -> invoke(context.project(), element, updater)); return ModCommand.psiUpdate(myElement, (element, updater) ->
} new JavaWithTryCatchSurrounder().doSurround(context, 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);
}
} }
} }

View File

@@ -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)));
}
}

View File

@@ -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<JavaExpressionModCommandSurrounder> 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.
* <p>
* 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);
}

View File

@@ -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. // 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; package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.lang.surroundWith.Surrounder; import com.intellij.lang.surroundWith.ModCommandSurrounder;
import com.intellij.openapi.editor.Editor; 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.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.impl.DebugUtil; import com.intellij.psi.impl.DebugUtil;
@@ -13,27 +14,27 @@ import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.CommentTracker;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
abstract class JavaStatementsSurrounder implements Surrounder { abstract class JavaStatementsModCommandSurrounder extends ModCommandSurrounder {
@Override @Override
public boolean isApplicable(PsiElement @NotNull [] elements) { public boolean isApplicable(PsiElement @NotNull [] elements) {
return ContainerUtil.find(elements, PsiSwitchLabelStatementBase.class::isInstance) == null; return ContainerUtil.find(elements, PsiSwitchLabelStatementBase.class::isInstance) == null;
} }
@Override @Override
public @Nullable TextRange surroundElements(@NotNull Project project, public final @NotNull ModCommand surroundElements(@NotNull ActionContext context, @NotNull PsiElement @NotNull [] elements) {
@NotNull Editor editor,
PsiElement @NotNull [] elements) throws IncorrectOperationException {
PsiElement container = elements[0].getParent(); PsiElement container = elements[0].getParent();
if (container == null) return null; if (container == null) return ModCommand.nop();
return surroundStatements(project, editor, container, elements); 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, protected abstract void surroundStatements(@NotNull ActionContext context,
final Editor editor, @NotNull PsiElement container,
final PsiElement container, @NotNull PsiElement @NotNull [] statements,
final PsiElement[] statements) throws IncorrectOperationException; @NotNull ModPsiUpdater updater) throws IncorrectOperationException;
protected static @NotNull PsiStatement addAfter(final PsiStatement statement, final PsiElement container, final PsiElement[] statements) { protected static @NotNull PsiStatement addAfter(final PsiStatement statement, final PsiElement container, final PsiElement[] statements) {
if (container instanceof PsiSwitchLabeledRuleStatement && !(statement instanceof PsiBlockStatement)) { if (container instanceof PsiSwitchLabeledRuleStatement && !(statement instanceof PsiBlockStatement)) {

View File

@@ -16,28 +16,34 @@
*/ */
package com.intellij.codeInsight.generation.surroundWith; 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.project.Project;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
public class JavaWithBlockSurrounder extends JavaStatementsSurrounder{ public class JavaWithBlockSurrounder extends JavaStatementsModCommandSurrounder {
@Override @Override
public String getTemplateDescription() { public String getTemplateDescription() {
return "{ }"; return "{ }";
} }
@Override @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); PsiManager manager = PsiManager.getInstance(project);
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject());
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false);
if (statements.length == 0) { if (statements.length == 0) {
return null; return;
} }
String text = "{\n}"; String text = "{\n}";
@@ -52,10 +58,9 @@ public class JavaWithBlockSurrounder extends JavaStatementsSurrounder{
container.deleteChildRange(statements[0], statements[statements.length - 1]); container.deleteChildRange(statements[0], statements[statements.length - 1]);
PsiElement firstChild = blockStatement.getFirstChild(); PsiElement firstChild = blockStatement.getFirstChild();
if (firstChild == null) { if (firstChild != null) {
return null;
}
TextRange range = firstChild.getTextRange(); TextRange range = firstChild.getTextRange();
return new TextRange(range.getEndOffset(), range.getEndOffset()); updater.moveCaretTo(range.getEndOffset());
}
} }
} }

View File

@@ -17,30 +17,33 @@
package com.intellij.codeInsight.generation.surroundWith; package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.java.JavaBundle; 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.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class JavaWithDoWhileSurrounder extends JavaStatementsSurrounder{ public class JavaWithDoWhileSurrounder extends JavaStatementsModCommandSurrounder {
@Override @Override
public String getTemplateDescription() { public String getTemplateDescription() {
return JavaBundle.message("surround.with.dowhile.template"); return JavaBundle.message("surround.with.dowhile.template");
} }
@Override @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); PsiManager manager = PsiManager.getInstance(project);
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject());
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false);
if (statements.length == 0){ if (statements.length == 0) return;
return null;
}
@NonNls String text = "do{\n}while(true);"; @NonNls String text = "do{\n}while(true);";
PsiDoWhileStatement doWhileStatement = (PsiDoWhileStatement)factory.createStatementFromText(text, null); PsiDoWhileStatement doWhileStatement = (PsiDoWhileStatement)factory.createStatementFromText(text, null);
@@ -49,15 +52,15 @@ public class JavaWithDoWhileSurrounder extends JavaStatementsSurrounder{
doWhileStatement = (PsiDoWhileStatement)addAfter(doWhileStatement, container, statements); doWhileStatement = (PsiDoWhileStatement)addAfter(doWhileStatement, container, statements);
PsiStatement body = doWhileStatement.getBody(); PsiStatement body = doWhileStatement.getBody();
if (!(body instanceof PsiBlockStatement)) { if (!(body instanceof PsiBlockStatement block)) return;
return null; PsiCodeBlock bodyBlock = block.getCodeBlock();
}
PsiCodeBlock bodyBlock = ((PsiBlockStatement)body).getCodeBlock();
SurroundWithUtil.indentCommentIfNecessary(bodyBlock, statements); SurroundWithUtil.indentCommentIfNecessary(bodyBlock, statements);
addRangeWithinContainer(bodyBlock, container, statements, false); addRangeWithinContainer(bodyBlock, container, statements, false);
container.deleteChildRange(statements[0], statements[statements.length - 1]); container.deleteChildRange(statements[0], statements[statements.length - 1]);
PsiExpression condition = doWhileStatement.getCondition(); PsiExpression condition = doWhileStatement.getCondition();
return condition == null ? null : condition.getTextRange(); if (condition != null) {
updater.select(condition);
}
} }
} }

View File

@@ -18,30 +18,33 @@ package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.java.JavaBundle; 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.project.Project;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class JavaWithForSurrounder extends JavaStatementsSurrounder{ public class JavaWithForSurrounder extends JavaStatementsModCommandSurrounder {
@Override @Override
public String getTemplateDescription() { public String getTemplateDescription() {
return JavaBundle.message("surround.with.for.template"); return JavaBundle.message("surround.with.for.template");
} }
@Override @Override
public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ protected void surroundStatements(@NotNull ActionContext context,
PsiManager manager = PsiManager.getInstance(project); @NotNull PsiElement container,
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); @NotNull PsiElement @NotNull [] statements,
@NotNull ModPsiUpdater updater) throws IncorrectOperationException {
Project project = context.project();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
statements = SurroundWithUtil.moveDeclarationsOut(container, statements, true); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, true);
if (statements.length == 0){ if (statements.length == 0) return;
return null;
}
@NonNls String text = "for(a;b;c){\n}"; @NonNls String text = "for(a;b;c){\n}";
PsiForStatement forStatement = (PsiForStatement)factory.createStatementFromText(text, null); PsiForStatement forStatement = (PsiForStatement)factory.createStatementFromText(text, null);
@@ -50,27 +53,21 @@ public class JavaWithForSurrounder extends JavaStatementsSurrounder{
forStatement = (PsiForStatement)addAfter(forStatement, container, statements); forStatement = (PsiForStatement)addAfter(forStatement, container, statements);
PsiStatement body = forStatement.getBody(); PsiStatement body = forStatement.getBody();
if (!(body instanceof PsiBlockStatement)) { if (!(body instanceof PsiBlockStatement block)) return;
return null; PsiCodeBlock bodyBlock = block.getCodeBlock();
}
PsiCodeBlock bodyBlock = ((PsiBlockStatement)body).getCodeBlock();
SurroundWithUtil.indentCommentIfNecessary(bodyBlock, statements); SurroundWithUtil.indentCommentIfNecessary(bodyBlock, statements);
addRangeWithinContainer(bodyBlock, container, statements, false); addRangeWithinContainer(bodyBlock, container, statements, false);
container.deleteChildRange(statements[0], statements[statements.length - 1]); container.deleteChildRange(statements[0], statements[statements.length - 1]);
forStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(forStatement); forStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(forStatement);
PsiStatement initialization = forStatement.getInitialization(); PsiStatement initialization = forStatement.getInitialization();
if (initialization == null) { if (initialization == null) return;
return null;
}
TextRange range1 = initialization.getTextRange(); TextRange range1 = initialization.getTextRange();
PsiStatement update = forStatement.getUpdate(); PsiStatement update = forStatement.getUpdate();
if (update == null) { if (update == null) return;
return null;
}
TextRange range3 = update.getTextRange(); TextRange range3 = update.getTextRange();
editor.getDocument().deleteString(range1.getStartOffset(), range3.getEndOffset()); update.getContainingFile().getFileDocument().deleteString(range1.getStartOffset(), range3.getEndOffset());
return new TextRange(range1.getStartOffset(), range1.getStartOffset()); updater.moveCaretTo(range1.getStartOffset());
} }
} }

View File

@@ -18,27 +18,30 @@ package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.java.JavaBundle; 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.project.Project;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public class JavaWithIfElseExpressionSurrounder extends JavaWithIfExpressionSurrounder{ public class JavaWithIfElseExpressionSurrounder extends JavaWithIfExpressionSurrounder{
@Override @Override
public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) {
PsiManager manager = expr.getManager(); Project project = context.project();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
@NonNls String text = "if(a){\nst;\n}else{\n}"; @NonNls String text = "if(a){\nst;\n}else{\n}";
PsiIfStatement ifStatement = (PsiIfStatement)factory.createStatementFromText(text, null); PsiIfStatement ifStatement = (PsiIfStatement)factory.createStatementFromText(text, null);
ifStatement = (PsiIfStatement)codeStyleManager.reformat(ifStatement); ifStatement = (PsiIfStatement)codeStyleManager.reformat(ifStatement);
ifStatement.getCondition().replace(expr); Objects.requireNonNull(ifStatement.getCondition()).replace(expr);
PsiExpressionStatement statement = (PsiExpressionStatement)expr.getParent(); PsiExpressionStatement statement = (PsiExpressionStatement)expr.getParent();
ifStatement = (PsiIfStatement)statement.replace(ifStatement); ifStatement = (PsiIfStatement)statement.replace(ifStatement);
@@ -48,8 +51,8 @@ public class JavaWithIfElseExpressionSurrounder extends JavaWithIfExpressionSurr
PsiStatement afterStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(block.getStatements()[0]); PsiStatement afterStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(block.getStatements()[0]);
TextRange range = afterStatement.getTextRange(); TextRange range = afterStatement.getTextRange();
editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset()); afterStatement.getContainingFile().getFileDocument().deleteString(range.getStartOffset(), range.getEndOffset());
return new TextRange(range.getStartOffset(), range.getStartOffset()); updater.moveCaretTo(range.getStartOffset());
} }
@Override @Override

View File

@@ -18,30 +18,33 @@ package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.CodeInsightUtilCore; 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.project.Project;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class JavaWithIfElseSurrounder extends JavaStatementsSurrounder{ public class JavaWithIfElseSurrounder extends JavaStatementsModCommandSurrounder {
@Override @Override
public String getTemplateDescription() { public String getTemplateDescription() {
return CodeInsightBundle.message("surround.with.ifelse.template"); return CodeInsightBundle.message("surround.with.ifelse.template");
} }
@Override @Override
public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ protected void surroundStatements(@NotNull ActionContext context,
PsiManager manager = PsiManager.getInstance(project); @NotNull PsiElement container,
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); @NotNull PsiElement @NotNull [] statements,
@NotNull ModPsiUpdater updater) throws IncorrectOperationException {
Project project = context.project();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false);
if (statements.length == 0){ if (statements.length == 0) return;
return null;
}
@NonNls String text = "if(a){\n}else{\n}"; @NonNls String text = "if(a){\n}else{\n}";
PsiIfStatement ifStatement = (PsiIfStatement)factory.createStatementFromText(text, null); PsiIfStatement ifStatement = (PsiIfStatement)factory.createStatementFromText(text, null);
@@ -50,20 +53,16 @@ public class JavaWithIfElseSurrounder extends JavaStatementsSurrounder{
ifStatement = (PsiIfStatement)addAfter(ifStatement, container, statements); ifStatement = (PsiIfStatement)addAfter(ifStatement, container, statements);
PsiStatement thenBranch = ifStatement.getThenBranch(); PsiStatement thenBranch = ifStatement.getThenBranch();
if (!(thenBranch instanceof PsiBlockStatement)) { if (!(thenBranch instanceof PsiBlockStatement)) return;
return null;
}
PsiCodeBlock thenBlock = ((PsiBlockStatement)thenBranch).getCodeBlock(); PsiCodeBlock thenBlock = ((PsiBlockStatement)thenBranch).getCodeBlock();
SurroundWithUtil.indentCommentIfNecessary(thenBlock, statements); SurroundWithUtil.indentCommentIfNecessary(thenBlock, statements);
addRangeWithinContainer(thenBlock, container, statements, true); addRangeWithinContainer(thenBlock, container, statements, true);
container.deleteChildRange(statements[0], statements[statements.length - 1]); container.deleteChildRange(statements[0], statements[statements.length - 1]);
ifStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(ifStatement); ifStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(ifStatement);
PsiExpression condition = ifStatement.getCondition(); PsiExpression condition = ifStatement.getCondition();
if (condition == null) { if (condition == null) return;
return null;
}
TextRange range = condition.getTextRange(); TextRange range = condition.getTextRange();
editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset()); condition.getContainingFile().getFileDocument().deleteString(range.getStartOffset(), range.getEndOffset());
return new TextRange(range.getStartOffset(), range.getStartOffset()); updater.moveCaretTo(range.getStartOffset());
} }
} }

View File

@@ -17,20 +17,21 @@ package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.CodeInsightUtilCore; 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.project.Project;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.FileTypeUtils; import com.intellij.psi.util.FileTypeUtils;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class JavaWithIfExpressionSurrounder extends JavaBooleanExpressionSurrounder { public class JavaWithIfExpressionSurrounder extends JavaExpressionModCommandSurrounder {
@Override @Override
public boolean isApplicable(PsiExpression expr) { 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; if (!expr.isPhysical()) return false;
PsiElement expressionStatement = expr.getParent(); PsiElement expressionStatement = expr.getParent();
if (!(expressionStatement instanceof PsiExpressionStatement)) return false; if (!(expressionStatement instanceof PsiExpressionStatement)) return false;
@@ -45,9 +46,9 @@ public class JavaWithIfExpressionSurrounder extends JavaBooleanExpressionSurroun
} }
@Override @Override
public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) {
PsiManager manager = expr.getManager(); Project project = context.project();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
@NonNls String text = "if(a){\nst;\n}"; @NonNls String text = "if(a){\nst;\n}";
@@ -63,14 +64,13 @@ public class JavaWithIfExpressionSurrounder extends JavaBooleanExpressionSurroun
ifStatement = (PsiIfStatement)statement.replace(ifStatement); ifStatement = (PsiIfStatement)statement.replace(ifStatement);
PsiStatement thenBranch = ifStatement.getThenBranch(); PsiStatement thenBranch = ifStatement.getThenBranch();
if (thenBranch instanceof PsiBlockStatement) { if (thenBranch instanceof PsiBlockStatement blockStatement) {
PsiCodeBlock block = ((PsiBlockStatement)thenBranch).getCodeBlock(); PsiCodeBlock block = blockStatement.getCodeBlock();
block = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(block); block = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(block);
TextRange range = block.getStatements()[0].getTextRange(); TextRange range = block.getStatements()[0].getTextRange();
editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset()); block.getContainingFile().getFileDocument().deleteString(range.getStartOffset(), range.getEndOffset());
return TextRange.from(range.getStartOffset(), 0); updater.moveCaretTo(range.getStartOffset());
} }
return TextRange.from(editor.getCaretModel().getOffset(), 0);
} }
@Override @Override
@@ -79,8 +79,8 @@ public class JavaWithIfExpressionSurrounder extends JavaBooleanExpressionSurroun
} }
private static boolean isElseBranch(@NotNull PsiExpression expression, @NotNull PsiElement statementParent) { private static boolean isElseBranch(@NotNull PsiExpression expression, @NotNull PsiElement statementParent) {
if (statementParent instanceof PsiIfStatement) { if (statementParent instanceof PsiIfStatement ifStatement) {
PsiStatement elseBranch = ((PsiIfStatement)statementParent).getElseBranch(); PsiStatement elseBranch = ifStatement.getElseBranch();
if (elseBranch != null && elseBranch.getFirstChild() == expression) { if (elseBranch != null && elseBranch.getFirstChild() == expression) {
return true; return true;
} }

View File

@@ -3,30 +3,36 @@ package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.CodeInsightUtilCore; 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.project.Project;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class JavaWithIfSurrounder extends JavaStatementsSurrounder{ public class JavaWithIfSurrounder extends JavaStatementsModCommandSurrounder {
@Override @Override
public String getTemplateDescription() { public String getTemplateDescription() {
return CodeInsightBundle.message("surround.with.if.template"); return CodeInsightBundle.message("surround.with.if.template");
} }
@Override @Override
public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) { protected void surroundStatements(@NotNull ActionContext context,
PsiIfStatement ifStatement = surroundStatements(project, container, statements, ""); @NotNull PsiElement container,
if (ifStatement == null) return null; @NotNull PsiElement @NotNull [] statements,
@NotNull ModPsiUpdater updater) throws IncorrectOperationException {
PsiIfStatement ifStatement = surroundStatements(context.project(), container, statements, "");
if (ifStatement == null) return;
ifStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(ifStatement); ifStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(ifStatement);
if (ifStatement == null) return null; if (ifStatement == null) return;
final PsiJavaToken lParenth = ifStatement.getLParenth(); final PsiJavaToken lParenth = ifStatement.getLParenth();
assert lParenth != null; assert lParenth != null;
final TextRange range = lParenth.getTextRange(); 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) { public PsiIfStatement surroundStatements(Project project, PsiElement container, PsiElement[] statements, String condition) {

View File

@@ -18,14 +18,17 @@ package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.java.JavaBundle; 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.project.Project;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; 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 @Override
public boolean isApplicable(PsiExpression expr) { public boolean isApplicable(PsiExpression expr) {
PsiType type = expr.getType(); PsiType type = expr.getType();
@@ -35,23 +38,23 @@ class JavaWithNotInstanceofSurrounder extends JavaExpressionSurrounder{
} }
@Override @Override
public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) {
PsiManager manager = expr.getManager(); Project project = context.project();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
PsiPrefixExpression prefixExpr = (PsiPrefixExpression)factory.createExpressionFromText("!(a instanceof Type)", null); PsiPrefixExpression prefixExpr = (PsiPrefixExpression)factory.createExpressionFromText("!(a instanceof Type)", null);
prefixExpr = (PsiPrefixExpression)codeStyleManager.reformat(prefixExpr); prefixExpr = (PsiPrefixExpression)codeStyleManager.reformat(prefixExpr);
PsiParenthesizedExpression parenthExpr = (PsiParenthesizedExpression)prefixExpr.getOperand(); PsiParenthesizedExpression parenthExpr = (PsiParenthesizedExpression)Objects.requireNonNull(prefixExpr.getOperand());
PsiInstanceOfExpression instanceofExpr = (PsiInstanceOfExpression)parenthExpr.getExpression(); PsiInstanceOfExpression instanceofExpr = (PsiInstanceOfExpression)Objects.requireNonNull(parenthExpr.getExpression());
instanceofExpr.getOperand().replace(expr); instanceofExpr.getOperand().replace(expr);
prefixExpr = (PsiPrefixExpression)expr.replace(prefixExpr); prefixExpr = (PsiPrefixExpression)expr.replace(prefixExpr);
parenthExpr = (PsiParenthesizedExpression)prefixExpr.getOperand(); parenthExpr = (PsiParenthesizedExpression)Objects.requireNonNull(prefixExpr.getOperand());
instanceofExpr = (PsiInstanceOfExpression)parenthExpr.getExpression(); instanceofExpr = (PsiInstanceOfExpression)Objects.requireNonNull(parenthExpr.getExpression());
instanceofExpr = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(instanceofExpr); instanceofExpr = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(instanceofExpr);
TextRange range = instanceofExpr.getCheckType().getTextRange(); TextRange range = instanceofExpr.getCheckType().getTextRange();
editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset()); instanceofExpr.getContainingFile().getFileDocument().deleteString(range.getStartOffset(), range.getEndOffset());
return new TextRange(range.getStartOffset(), range.getStartOffset()); updater.moveCaretTo(range.getStartOffset());
} }
@Override @Override

View File

@@ -17,19 +17,19 @@
package com.intellij.codeInsight.generation.surroundWith; package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.CodeInsightBundle; 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.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.refactoring.IntroduceVariableUtil; 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 @Override
public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) {
PsiManager manager = expr.getManager(); Project project = context.project();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
PsiPrefixExpression prefixExpr = (PsiPrefixExpression)factory.createExpressionFromText("!(a)", null); PsiPrefixExpression prefixExpr = (PsiPrefixExpression)factory.createExpressionFromText("!(a)", null);
@@ -37,11 +37,17 @@ public class JavaWithNotSurrounder extends JavaBooleanExpressionSurrounder {
((PsiParenthesizedExpression)prefixExpr.getOperand()).getExpression().replace(expr); ((PsiParenthesizedExpression)prefixExpr.getOperand()).getExpression().replace(expr);
expr = (PsiExpression)IntroduceVariableUtil.replace(expr, prefixExpr, project); expr = (PsiExpression)IntroduceVariableUtil.replace(expr, prefixExpr, project);
int offset = expr.getTextRange().getEndOffset(); int offset = expr.getTextRange().getEndOffset();
return new TextRange(offset, offset); updater.moveCaretTo(offset);
} }
@Override @Override
public String getTemplateDescription() { public String getTemplateDescription() {
return CodeInsightBundle.message("surround.with.not.template"); 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)));
}
} }

View File

@@ -1,4 +1,3 @@
/* /*
* Copyright 2000-2012 JetBrains s.r.o. * 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.codeInsight.CodeInsightUtilCore;
import com.intellij.java.JavaBundle; import com.intellij.java.JavaBundle;
import com.intellij.openapi.editor.Editor; import com.intellij.modcommand.ActionContext;
import com.intellij.openapi.project.Project; import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.FileTypeUtils; import com.intellij.psi.util.FileTypeUtils;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class JavaWithNullCheckSurrounder extends JavaExpressionSurrounder{ public class JavaWithNullCheckSurrounder extends JavaExpressionModCommandSurrounder{
@Override @Override
public boolean isApplicable(PsiExpression expr) { public boolean isApplicable(PsiExpression expr) {
PsiType type = expr.getType(); PsiType type = expr.getType();
@@ -43,10 +41,9 @@ public class JavaWithNullCheckSurrounder extends JavaExpressionSurrounder{
} }
@Override @Override
public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) {
PsiManager manager = expr.getManager(); PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.project());
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(context.project());
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
@NonNls String text = "if(a != null){\nst;\n}"; @NonNls String text = "if(a != null){\nst;\n}";
PsiIfStatement ifStatement = (PsiIfStatement)factory.createStatementFromText(text, null); PsiIfStatement ifStatement = (PsiIfStatement)factory.createStatementFromText(text, null);
@@ -61,7 +58,7 @@ public class JavaWithNullCheckSurrounder extends JavaExpressionSurrounder{
block = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(block); block = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(block);
PsiElement replace = block.getStatements()[0].replace(factory.createStatementFromText(oldText, block)); PsiElement replace = block.getStatements()[0].replace(factory.createStatementFromText(oldText, block));
int offset = replace.getTextRange().getEndOffset(); int offset = replace.getTextRange().getEndOffset();
return new TextRange(offset, offset); updater.moveCaretTo(offset);
} }
@Override @Override

View File

@@ -1,4 +1,3 @@
/* /*
* Copyright 2000-2009 JetBrains s.r.o. * Copyright 2000-2009 JetBrains s.r.o.
* *
@@ -17,24 +16,24 @@
package com.intellij.codeInsight.generation.surroundWith; package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.CodeInsightBundle; 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.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.refactoring.IntroduceVariableUtil; 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 @Override
public boolean isApplicable(PsiExpression expr) { public boolean isApplicable(PsiExpression expr) {
return !PsiTypes.voidType().equals(expr.getType()); return !PsiTypes.voidType().equals(expr.getType());
} }
@Override @Override
public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException { protected void surroundExpression(@NotNull ActionContext context, @NotNull PsiExpression expr, @NotNull ModPsiUpdater updater) {
PsiManager manager = expr.getManager(); Project project = context.project();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
PsiParenthesizedExpression parenthExpr = (PsiParenthesizedExpression)factory.createExpressionFromText("(a)", null); PsiParenthesizedExpression parenthExpr = (PsiParenthesizedExpression)factory.createExpressionFromText("(a)", null);
@@ -42,7 +41,7 @@ public class JavaWithParenthesesSurrounder extends JavaExpressionSurrounder{
parenthExpr.getExpression().replace(expr); parenthExpr.getExpression().replace(expr);
expr = (PsiExpression)IntroduceVariableUtil.replace(expr, parenthExpr, project); expr = (PsiExpression)IntroduceVariableUtil.replace(expr, parenthExpr, project);
int offset = expr.getTextRange().getEndOffset(); int offset = expr.getTextRange().getEndOffset();
return new TextRange(offset, offset); updater.moveCaretTo(offset);
} }
@Override @Override

View File

@@ -3,34 +3,37 @@
package com.intellij.codeInsight.generation.surroundWith; package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.java.JavaBundle; 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.project.Project;
import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Collection; import java.util.Collection;
import java.util.List;
public class JavaWithRunnableSurrounder extends JavaStatementsSurrounder{ public class JavaWithRunnableSurrounder extends JavaStatementsModCommandSurrounder {
@Override @Override
public String getTemplateDescription() { public String getTemplateDescription() {
return JavaBundle.message("surround.with.runnable.template"); return JavaBundle.message("surround.with.runnable.template");
} }
@Override @Override
public TextRange surroundStatements(Project project, final Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ protected void surroundStatements(@NotNull ActionContext context,
PsiManager manager = container.getManager(); @NotNull PsiElement container,
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); @NotNull PsiElement @NotNull [] statements,
@NotNull ModPsiUpdater updater) throws IncorrectOperationException {
Project project = context.project();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
final String baseName = "runnable"; final String baseName = "runnable";
final String uniqueName = JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName(baseName, container, false); 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]); container.deleteChildRange(statements[0], statements[statements.length - 1]);
makeVariablesFinal(body, body); makeVariablesFinal(body, body);
updater.rename(variable, List.of(uniqueName));
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;
} }
private static void makeVariablesFinal(PsiElement scope, PsiCodeBlock body) throws IncorrectOperationException{ private static void makeVariablesFinal(PsiElement scope, PsiCodeBlock body) throws IncorrectOperationException{
@@ -88,13 +69,13 @@ public class JavaWithRunnableSurrounder extends JavaStatementsSurrounder{
for (PsiElement child : children) { for (PsiElement child : children) {
makeVariablesFinal(child, body); makeVariablesFinal(child, body);
if (child instanceof PsiReferenceExpression) { if (child instanceof PsiReferenceExpression ref) {
if (child.getParent() instanceof PsiMethodCallExpression) continue; if (child.getParent() instanceof PsiMethodCallExpression) continue;
if (PsiUtil.isAccessedForWriting((PsiReferenceExpression) child)) { if (PsiUtil.isAccessedForWriting(ref)) {
continue; continue;
} }
PsiElement refElement = ((PsiReferenceExpression)child).resolve(); PsiElement refElement = ref.resolve();
if (refElement instanceof PsiLocalVariable || refElement instanceof PsiParameter) { if (refElement instanceof PsiLocalVariable || refElement instanceof PsiParameter) {
PsiVariable variable = (PsiVariable) refElement; PsiVariable variable = (PsiVariable) refElement;
final PsiModifierList modifierList = variable.getModifierList(); final PsiModifierList modifierList = variable.getModifierList();
@@ -107,8 +88,8 @@ public class JavaWithRunnableSurrounder extends JavaStatementsSurrounder{
while (parent != null) { while (parent != null) {
if (parent.equals(body)) break; if (parent.equals(body)) break;
if (parent instanceof PsiMethod) { if (parent instanceof PsiMethod method) {
enclosingMethod = (PsiMethod) parent; enclosingMethod = method;
} }
parent = parent.getParent(); parent = parent.getParent();
} }

View File

@@ -18,30 +18,33 @@ package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.java.JavaBundle; 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.project.Project;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class JavaWithSynchronizedSurrounder extends JavaStatementsSurrounder{ public class JavaWithSynchronizedSurrounder extends JavaStatementsModCommandSurrounder {
@Override @Override
public String getTemplateDescription() { public String getTemplateDescription() {
return JavaBundle.message("surround.with.synchronized.template"); return JavaBundle.message("surround.with.synchronized.template");
} }
@Override @Override
public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ protected void surroundStatements(@NotNull ActionContext context,
PsiManager manager = PsiManager.getInstance(project); @NotNull PsiElement container,
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); @NotNull PsiElement @NotNull [] statements,
@NotNull ModPsiUpdater updater) throws IncorrectOperationException {
Project project = context.project();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false);
if (statements.length == 0){ if (statements.length == 0) return;
return null;
}
@NonNls String text = "synchronized(a){\n}"; @NonNls String text = "synchronized(a){\n}";
PsiSynchronizedStatement synchronizedStatement = (PsiSynchronizedStatement)factory.createStatementFromText(text, null); PsiSynchronizedStatement synchronizedStatement = (PsiSynchronizedStatement)factory.createStatementFromText(text, null);
@@ -50,20 +53,16 @@ public class JavaWithSynchronizedSurrounder extends JavaStatementsSurrounder{
synchronizedStatement = (PsiSynchronizedStatement)addAfter(synchronizedStatement, container, statements); synchronizedStatement = (PsiSynchronizedStatement)addAfter(synchronizedStatement, container, statements);
PsiCodeBlock synchronizedBlock = synchronizedStatement.getBody(); PsiCodeBlock synchronizedBlock = synchronizedStatement.getBody();
if (synchronizedBlock == null) { if (synchronizedBlock == null) return;
return null;
}
SurroundWithUtil.indentCommentIfNecessary(synchronizedBlock, statements); SurroundWithUtil.indentCommentIfNecessary(synchronizedBlock, statements);
addRangeWithinContainer(synchronizedBlock, container, statements, true); addRangeWithinContainer(synchronizedBlock, container, statements, true);
container.deleteChildRange(statements[0], statements[statements.length - 1]); container.deleteChildRange(statements[0], statements[statements.length - 1]);
synchronizedStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(synchronizedStatement); synchronizedStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(synchronizedStatement);
PsiExpression lockExpression = synchronizedStatement.getLockExpression(); PsiExpression lockExpression = synchronizedStatement.getLockExpression();
if (lockExpression == null) { if (lockExpression == null) return;
return null;
}
TextRange range = lockExpression.getTextRange(); TextRange range = lockExpression.getTextRange();
editor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset()); lockExpression.getContainingFile().getFileDocument().deleteString(range.getStartOffset(), range.getEndOffset());
return new TextRange(range.getStartOffset(), range.getStartOffset()); updater.moveCaretTo(range.getStartOffset());
} }
} }

View File

@@ -3,25 +3,26 @@ package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInsight.ExceptionUtil;
import com.intellij.java.JavaBundle; 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.DumbService;
import com.intellij.openapi.project.Project; 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.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.util.CommonJavaRefactoringUtil;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import com.siyeh.ig.psiutils.CodeBlockSurrounder;
import com.siyeh.ig.psiutils.ExpressionUtils;
import com.siyeh.ig.psiutils.VariableNameGenerator; import com.siyeh.ig.psiutils.VariableNameGenerator;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class JavaWithTryCatchSurrounder extends JavaStatementsSurrounder { public class JavaWithTryCatchSurrounder extends JavaStatementsModCommandSurrounder {
protected boolean myGenerateFinally; protected boolean myGenerateFinally;
@Override @Override
@@ -30,29 +31,19 @@ public class JavaWithTryCatchSurrounder extends JavaStatementsSurrounder {
} }
@Override @Override
public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) protected void surroundStatements(@NotNull ActionContext context,
throws IncorrectOperationException { @NotNull PsiElement container,
try { @NotNull PsiElement @NotNull [] statements,
return doSurround(project, container, statements); @NotNull ModPsiUpdater updater) throws IncorrectOperationException {
} Project project = context.project();
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) {
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
PsiElement[] statements = SurroundWithUtil.moveDeclarationsOut(container, origStatements, true); PsiElement[] statements1 = SurroundWithUtil.moveDeclarationsOut(container, statements, true);
if (statements.length == 0) { if (statements1.length == 0) return;
return null;
}
return DumbService.getInstance(project).computeWithAlternativeResolveEnabled(() -> { DumbService.getInstance(project).runWithAlternativeResolveEnabled(() -> {
List<PsiClassType> exceptions = getExceptionTypes(container, statements, factory); List<PsiClassType> exceptions = getExceptionTypes(container, statements1, factory);
@NonNls StringBuilder buffer = new StringBuilder(); @NonNls StringBuilder buffer = new StringBuilder();
buffer.append("try{\n}"); buffer.append("try{\n}");
@@ -66,11 +57,11 @@ public class JavaWithTryCatchSurrounder extends JavaStatementsSurrounder {
PsiTryStatement tryStatement = (PsiTryStatement)factory.createStatementFromText(text, null); PsiTryStatement tryStatement = (PsiTryStatement)factory.createStatementFromText(text, null);
tryStatement = (PsiTryStatement)CodeStyleManager.getInstance(project).reformat(tryStatement); tryStatement = (PsiTryStatement)CodeStyleManager.getInstance(project).reformat(tryStatement);
tryStatement = (PsiTryStatement)addAfter(tryStatement, container, statements); tryStatement = (PsiTryStatement)addAfter(tryStatement, container, statements1);
PsiCodeBlock tryBlock = tryStatement.getTryBlock(); PsiCodeBlock tryBlock = tryStatement.getTryBlock();
SurroundWithUtil.indentCommentIfNecessary(tryBlock, statements); SurroundWithUtil.indentCommentIfNecessary(tryBlock, statements1);
addRangeWithinContainer(tryBlock, container, statements, true); addRangeWithinContainer(tryBlock, container, statements1, true);
PsiCatchSection[] catchSections = tryStatement.getCatchSections(); PsiCatchSection[] catchSections = tryStatement.getCatchSections();
@@ -85,18 +76,38 @@ public class JavaWithTryCatchSurrounder extends JavaStatementsSurrounder {
} }
String name = String name =
new VariableNameGenerator(tryBlock, VariableKind.PARAMETER).byName("e", "ex", "exc").byType(exception).generate(false); 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); catchSection = (PsiCatchSection)catchSections[i].replace(catchSection);
codeStyleManager.shortenClassReferences(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]; 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<PsiClassType> getExceptionTypes(PsiElement container, PsiElement[] statements, PsiElementFactory factory) { private static @NotNull List<PsiClassType> getExceptionTypes(PsiElement container, PsiElement[] statements, PsiElementFactory factory) {
List<PsiClassType> exceptions = ExceptionUtil.getUnhandledExceptions(statements); List<PsiClassType> exceptions = ExceptionUtil.getUnhandledExceptions(statements);
if (exceptions.isEmpty()) { if (exceptions.isEmpty()) {

View File

@@ -16,34 +16,36 @@
package com.intellij.codeInsight.generation.surroundWith; package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.CodeInsightBundle; 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.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class JavaWithTryFinallySurrounder extends JavaStatementsSurrounder{ public class JavaWithTryFinallySurrounder extends JavaStatementsModCommandSurrounder {
private static final Logger LOG = Logger.getInstance(JavaWithTryFinallySurrounder.class); @SuppressWarnings("DialogTitleCapitalization")
@Override @Override
public String getTemplateDescription() { public String getTemplateDescription() {
return CodeInsightBundle.message("surround.with.try.finally.template"); return CodeInsightBundle.message("surround.with.try.finally.template");
} }
@Override @Override
public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ protected void surroundStatements(@NotNull ActionContext context,
PsiManager manager = PsiManager.getInstance(project); @NotNull PsiElement container,
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); @NotNull PsiElement @NotNull [] statements,
@NotNull ModPsiUpdater updater) throws IncorrectOperationException {
Project project = context.project();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false);
if (statements.length == 0){ if (statements.length == 0) return;
return null;
}
@NonNls String text = "try{\n}finally{\n\n}"; @NonNls String text = "try{\n}finally{\n\n}";
PsiTryStatement tryStatement = (PsiTryStatement)factory.createStatementFromText(text, null); PsiTryStatement tryStatement = (PsiTryStatement)factory.createStatementFromText(text, null);
@@ -52,29 +54,22 @@ public class JavaWithTryFinallySurrounder extends JavaStatementsSurrounder{
tryStatement = (PsiTryStatement)addAfter(tryStatement, container, statements); tryStatement = (PsiTryStatement)addAfter(tryStatement, container, statements);
PsiCodeBlock tryBlock = tryStatement.getTryBlock(); PsiCodeBlock tryBlock = tryStatement.getTryBlock();
if (tryBlock == null) { if (tryBlock == null) return;
return null;
}
SurroundWithUtil.indentCommentIfNecessary(tryBlock, statements); SurroundWithUtil.indentCommentIfNecessary(tryBlock, statements);
addRangeWithinContainer(tryBlock, container, statements, true); addRangeWithinContainer(tryBlock, container, statements, true);
container.deleteChildRange(statements[0], statements[statements.length - 1]); container.deleteChildRange(statements[0], statements[statements.length - 1]);
PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
if (finallyBlock == null) { if (finallyBlock == null) return;
return null; moveCaretToFinallyBlock(project, updater, finallyBlock);
}
moveCaretToFinallyBlock(project, editor, finallyBlock);
return new TextRange(editor.getCaretModel().getOffset(), editor.getCaretModel().getOffset());
} }
public static void moveCaretToFinallyBlock(Project project, Editor editor, PsiCodeBlock finallyBlock) { public static void moveCaretToFinallyBlock(Project project, ModPsiNavigator navigator, PsiCodeBlock finallyBlock) {
Document document = editor.getDocument(); Document document = finallyBlock.getContainingFile().getFileDocument();
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document); PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document);
TextRange finallyBlockRange = finallyBlock.getTextRange(); TextRange finallyBlockRange = finallyBlock.getTextRange();
int newLineOffset = finallyBlockRange.getStartOffset() + 2; int newLineOffset = finallyBlockRange.getStartOffset() + 2;
editor.getCaretModel().moveToOffset(newLineOffset); navigator.moveCaretTo(CodeStyleManager.getInstance(project).adjustLineIndent(document, newLineOffset));
editor.getSelectionModel().removeSelection();
CodeStyleManager.getInstance(project).adjustLineIndent(document, newLineOffset);
PsiDocumentManager.getInstance(project).commitDocument(document); PsiDocumentManager.getInstance(project).commitDocument(document);
} }
} }

View File

@@ -17,30 +17,32 @@
package com.intellij.codeInsight.generation.surroundWith; package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.CodeInsightBundle; 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.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class JavaWithWhileSurrounder extends JavaStatementsSurrounder{ public class JavaWithWhileSurrounder extends JavaStatementsModCommandSurrounder {
@Override @Override
public String getTemplateDescription() { public String getTemplateDescription() {
return CodeInsightBundle.message("surround.with.while.template"); return CodeInsightBundle.message("surround.with.while.template");
} }
@Override @Override
public TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ protected void surroundStatements(@NotNull ActionContext context,
PsiManager manager = PsiManager.getInstance(project); @NotNull PsiElement container,
PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); @NotNull PsiElement @NotNull [] statements,
@NotNull ModPsiUpdater updater) throws IncorrectOperationException {
Project project = context.project();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
statements = SurroundWithUtil.moveDeclarationsOut(container, statements, true); statements = SurroundWithUtil.moveDeclarationsOut(container, statements, true);
if (statements.length == 0){ if (statements.length == 0) return;
return null;
}
@NonNls String text = "while(true){\n}"; @NonNls String text = "while(true){\n}";
PsiWhileStatement whileStatement = (PsiWhileStatement)factory.createStatementFromText(text, null); PsiWhileStatement whileStatement = (PsiWhileStatement)factory.createStatementFromText(text, null);
@@ -49,15 +51,15 @@ public class JavaWithWhileSurrounder extends JavaStatementsSurrounder{
whileStatement = (PsiWhileStatement)addAfter(whileStatement, container, statements); whileStatement = (PsiWhileStatement)addAfter(whileStatement, container, statements);
PsiStatement body = whileStatement.getBody(); PsiStatement body = whileStatement.getBody();
if (!(body instanceof PsiBlockStatement)) { if (!(body instanceof PsiBlockStatement block)) return;
return null; PsiCodeBlock bodyBlock = block.getCodeBlock();
}
PsiCodeBlock bodyBlock = ((PsiBlockStatement)body).getCodeBlock();
SurroundWithUtil.indentCommentIfNecessary(bodyBlock, statements); SurroundWithUtil.indentCommentIfNecessary(bodyBlock, statements);
addRangeWithinContainer(bodyBlock, container, statements, false); addRangeWithinContainer(bodyBlock, container, statements, false);
container.deleteChildRange(statements[0], statements[statements.length - 1]); container.deleteChildRange(statements[0], statements[statements.length - 1]);
PsiExpression condition = whileStatement.getCondition(); PsiExpression condition = whileStatement.getCondition();
return condition == null ? null : condition.getTextRange(); if (condition != null) {
updater.select(condition);
}
} }
} }

View File

@@ -5,12 +5,11 @@ import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.codeInsight.template.impl.ConstantNode; import com.intellij.codeInsight.template.impl.ConstantNode;
import com.intellij.java.JavaBundle; import com.intellij.java.JavaBundle;
import com.intellij.lang.java.JavaLanguage; import com.intellij.lang.java.JavaLanguage;
import com.intellij.lang.surroundWith.ModCommandSurrounder;
import com.intellij.lang.surroundWith.SurroundDescriptor; import com.intellij.lang.surroundWith.SurroundDescriptor;
import com.intellij.lang.surroundWith.Surrounder; import com.intellij.lang.surroundWith.Surrounder;
import com.intellij.modcommand.*; import com.intellij.modcommand.*;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.java.JavaFeature; import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager; 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"); 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}; private final Surrounder[] mySurrounders = {this};
@Override @Override
@@ -293,13 +292,11 @@ public final class SurroundAutoCloseableAction extends PsiUpdateModCommandAction
} }
@Override @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) { if (elements.length == 1) {
ActionContext context = ActionContext.from(editor, elements[0].getContainingFile()); return new SurroundAutoCloseableAction().perform(context, elements[0]);
ModCommand command = new SurroundAutoCloseableAction().perform(context, elements[0]);
ModCommandExecutor.getInstance().executeInteractively(context, command, editor);
} }
return null; return ModCommand.nop();
} }
} }
} }

View File

@@ -51,6 +51,7 @@ public class TryStatementPostfixTemplate extends PostfixTemplate implements Dumb
return; return;
} }
editor.getSelectionModel().removeSelection();
PsiElement element = file.findElementAt(range.getStartOffset()); PsiElement element = file.findElementAt(range.getStartOffset());
PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(element, PsiTryStatement.class); PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(element, PsiTryStatement.class);
assert tryStatement != null; assert tryStatement != null;

View File

@@ -5,6 +5,7 @@ import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.codeInsight.TargetElementUtil; import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.codeInsight.unwrap.ScopeHighlighter; import com.intellij.codeInsight.unwrap.ScopeHighlighter;
import com.intellij.java.refactoring.JavaRefactoringBundle; import com.intellij.java.refactoring.JavaRefactoringBundle;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
@@ -209,6 +210,34 @@ public final class ElementToWorkOn {
CommonRefactoringUtil.showErrorHint(project, editor, message, refactoringName, helpId); CommonRefactoringUtil.showErrorHint(project, editor, message, refactoringName, helpId);
} }
/**
* @param <E> 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 <E extends PsiElement> @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<T> { public interface ElementsProcessor<T> {
boolean accept(ElementToWorkOn el); boolean accept(ElementToWorkOn el);
void pass(T t); void pass(T t);

View File

@@ -1,6 +1,6 @@
class Test { class Test {
void foo() { void foo() {
<caret>Runnable runnable = new Runnable() { Runnable <caret>runnable = new Runnable() {
public void run() { public void run() {
// This is comment" // This is comment"
int i = 1; int i = 1;

View File

@@ -17,7 +17,7 @@ class External {
int innerLocal4 = 7; int innerLocal4 = 7;
String incorrect; String incorrect;
<caret>Runnable runnable = new Runnable() { Runnable <caret>runnable = new Runnable() {
public void run() { public void run() {
int insideRunnable1 = param1 + ((++innerLocal2) << param2); int insideRunnable1 = param1 + ((++innerLocal2) << param2);
param2 = local1 * insideRunnable1; param2 = local1 * insideRunnable1;

View File

@@ -1303,7 +1303,6 @@ surround.with.runnable.template=Runnable
surround.with.synchronized.template=synchronized surround.with.synchronized.template=synchronized
surround.with.try.catch.finally.template=try / catch / finally 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.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.try.catch.template=try / catch
surround.with.cast=Surround With Cast surround.with.cast=Surround With Cast
tab.title.entry.points=Entry points tab.title.entry.points=Entry points

View File

@@ -3464,6 +3464,12 @@ com.intellij.lang.parameterInfo.UpdateParameterInfoContext
- a:setParameterOwner(com.intellij.psi.PsiElement):V - a:setParameterOwner(com.intellij.psi.PsiElement):V
- a:setPreservedOnHintHidden(Z):V - a:setPreservedOnHintHidden(Z):V
- a:setUIComponentEnabled(I,Z):V - a:setUIComponentEnabled(I,Z):V
*a:com.intellij.lang.surroundWith.ModCommandSurrounder
- com.intellij.lang.surroundWith.Surrounder
- <init>():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 com.intellij.lang.surroundWith.SurroundDescriptor
- a:getElementsToSurround(com.intellij.psi.PsiFile,I,I):com.intellij.psi.PsiElement[] - a:getElementsToSurround(com.intellij.psi.PsiFile,I,I):com.intellij.psi.PsiElement[]
- a:getSurrounders():com.intellij.lang.surroundWith.Surrounder[] - a:getSurrounders():com.intellij.lang.surroundWith.Surrounder[]

View File

@@ -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 <em>Code | Surround With</em> action on the specified range of elements.
* <p>
* @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<ModCommand>() {
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;
}
}

View File

@@ -16,6 +16,7 @@ import com.intellij.lang.LangBundle;
import com.intellij.lang.Language; import com.intellij.lang.Language;
import com.intellij.lang.LanguageSurrounders; import com.intellij.lang.LanguageSurrounders;
import com.intellij.lang.folding.CustomFoldingSurroundDescriptor; import com.intellij.lang.folding.CustomFoldingSurroundDescriptor;
import com.intellij.lang.surroundWith.ModCommandSurrounder;
import com.intellij.lang.surroundWith.SurroundDescriptor; import com.intellij.lang.surroundWith.SurroundDescriptor;
import com.intellij.lang.surroundWith.Surrounder; import com.intellij.lang.surroundWith.Surrounder;
import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.*;
@@ -221,8 +222,11 @@ public final class SurroundWithHandler implements CodeInsightActionHandler {
); );
} else { } else {
CommandProcessor.getInstance().executeCommand(project, () -> { CommandProcessor.getInstance().executeCommand(project, () -> {
editor.getSelectionModel().removeSelection();
TextRange range = ReadAction.compute(() -> surrounder.surroundElements(project, editor, elements)); TextRange range = ReadAction.compute(() -> surrounder.surroundElements(project, editor, elements));
if (!(surrounder instanceof ModCommandSurrounder)) {
updateRange(project, editor, range, line, col); updateRange(project, editor, range, line, col);
}
}, CodeInsightBundle.message("surround.with.chooser.title"), null); }, CodeInsightBundle.message("surround.with.chooser.title"), null);
} }
} }