[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.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));
}
}

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.
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)) {

View File

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

View File

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

View File

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

View File

@@ -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

View File

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

View File

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

View File

@@ -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) {

View File

@@ -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

View File

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

View File

@@ -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

View File

@@ -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

View File

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

View File

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

View File

@@ -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<PsiClassType> exceptions = getExceptionTypes(container, statements, factory);
DumbService.getInstance(project).runWithAlternativeResolveEnabled(() -> {
List<PsiClassType> 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<PsiClassType> getExceptionTypes(PsiElement container, PsiElement[] statements, PsiElementFactory factory) {
List<PsiClassType> exceptions = ExceptionUtil.getUnhandledExceptions(statements);
if (exceptions.isEmpty()) {

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 <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> {
boolean accept(ElementToWorkOn el);
void pass(T t);

View File

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

View File

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

View File

@@ -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

View File

@@ -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
- <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
- a:getElementsToSurround(com.intellij.psi.PsiFile,I,I):com.intellij.psi.PsiElement[]
- 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.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);
}
}