[java-refactoring] IDEA-235656 Automatically expand composite assignment when inlining variable

GitOrigin-RevId: 797f4121214eadfe1df74aadae0c2299dc178a02
This commit is contained in:
Tagir Valeev
2023-11-03 17:09:36 +01:00
committed by intellij-monorepo-bot
parent d5d5b86b21
commit fcd92a7fcd
8 changed files with 57 additions and 23 deletions

View File

@@ -150,7 +150,7 @@ public final class PsiReplacementUtil {
}
}
public static @NotNull PsiElement replaceOperatorAssignmentWithAssignmentExpression(@NotNull PsiAssignmentExpression assignmentExpression) {
public static @NotNull PsiAssignmentExpression replaceOperatorAssignmentWithAssignmentExpression(@NotNull PsiAssignmentExpression assignmentExpression) {
CommentTracker tracker = new CommentTracker();
final PsiJavaToken sign = assignmentExpression.getOperationSign();
final PsiExpression lhs = assignmentExpression.getLExpression();
@@ -178,7 +178,7 @@ public final class PsiReplacementUtil {
}
final Project project = assignmentExpression.getProject();
final PsiElement replacementExpression = tracker.replaceAndRestoreComments(assignmentExpression, newExpression.toString());
return CodeStyleManager.getInstance(project).reformat(replacementExpression);
return (PsiAssignmentExpression)CodeStyleManager.getInstance(project).reformat(replacementExpression);
}
private static String getCastString(PsiExpression lhs, PsiExpression rhs) {

View File

@@ -32,8 +32,10 @@ import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.CommonJavaRefactoringUtil;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.PsiReplacementUtil;
import com.siyeh.ig.psiutils.CommentTracker;
import com.siyeh.ig.psiutils.VariableAccessUtils;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -140,9 +142,8 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
boolean inlineAll = mode == InlineMode.INLINE_ALL_AND_DELETE;
return ModCommand.psiUpdate(context, updater -> {
PsiPatternVariable writablePattern = updater.getWritable(pattern);
List<SmartPsiElementPointer<PsiExpression>> pointers =
inlineOccurrences(project, writablePattern, defToInline,
ContainerUtil.map2Array(refsToInline, PsiElement.EMPTY_ARRAY, updater::getWritable));
List<SmartPsiElementPointer<PsiExpression>> pointers = inlineOccurrences(project, writablePattern, defToInline,
ContainerUtil.map(refsToInline, updater::getWritable));
if (inlineAll) {
writablePattern.delete();
}
@@ -288,7 +289,9 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
}
final PsiElement writeAccess = checkRefsInAugmentedAssignmentOrUnaryModified(refsToInline, defToInline);
if (writeAccess != null) {
if (writeAccess != null && !
(writeAccess.getParent() instanceof PsiAssignmentExpression assignment && assignment.getLExpression() == writeAccess &&
ArrayUtil.contains(writeAccess, refsToInline))) {
String message =
RefactoringBundle.getCannotRefactorMessage(JavaRefactoringBundle.message("variable.is.accessed.for.writing", localName));
return ModCommand.highlight(EditorColors.WRITE_SEARCH_RESULT_ATTRIBUTES, writeAccess)
@@ -305,9 +308,16 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
return ModCommand.psiUpdate(context, updater -> {
PsiExpression writableDef = updater.getWritable(defToInline);
PsiLocalVariable writableLocal = updater.getWritable(local);
PsiElement[] writableRefs = ContainerUtil.map2Array(refsToInline, PsiElement.EMPTY_ARRAY, updater::getWritable);
List<PsiElement> writableRefs = StreamEx.of(refsToInline).without(writeAccess).map(updater::getWritable).toList();
PsiElement writableWrite = updater.getWritable(writeAccess);
List<SmartPsiElementPointer<PsiExpression>> pointers = inlineOccurrences(project, writableLocal, writableDef, writableRefs);
if (writableWrite != null && writableWrite.isValid()) {
PsiAssignmentExpression newAssignment =
PsiReplacementUtil.replaceOperatorAssignmentWithAssignmentExpression((PsiAssignmentExpression)writableWrite.getParent());
for (PsiReferenceExpression ref : VariableAccessUtils.getVariableReferences(writableLocal, newAssignment.getRExpression())) {
pointers.add(SmartPointerManager.createPointer(InlineUtil.inlineVariable(local, defToInline, ref)));
}
}
if (inlineAll) {
if (!isInliningVariableInitializer(writableDef)) {
deleteInitializer(writableDef);
@@ -356,10 +366,10 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
}
@NotNull
static List<SmartPsiElementPointer<PsiExpression>> inlineOccurrences(@NotNull Project project,
@NotNull PsiVariable local,
PsiExpression defToInline,
PsiElement[] refsToInline) {
private static List<SmartPsiElementPointer<PsiExpression>> inlineOccurrences(@NotNull Project project,
@NotNull PsiVariable local,
PsiExpression defToInline,
@NotNull List<PsiElement> refsToInline) {
List<SmartPsiElementPointer<PsiExpression>> pointers = new ArrayList<>();
final SmartPointerManager pointerManager = SmartPointerManager.getInstance(project);
for (PsiElement element : refsToInline) {

View File

@@ -1,7 +1,7 @@
class AugmentedAssignment {
public static String x() {
String te<caret>xt = "";
text += "something";
String text;
text = "" + "something";
return text;
}
}

View File

@@ -0,0 +1,7 @@
public class CompositeAssignment {
public static String foo(String portalName, String itemName) {
String <caret>redirectPath = "/portals/" + portalName + "/widgets/";
redirectPath += itemName;
return redirectPath.toUpperCase();
}
}

View File

@@ -0,0 +1,7 @@
public class CompositeAssignment {
public static String foo(String portalName, String itemName) {
String redirectPath;
redirectPath = "/portals/" + portalName + "/widgets/" + itemName;
return redirectPath.toUpperCase();
}
}

View File

@@ -0,0 +1,7 @@
public class CompositeAssignmentCast {
public static int foo() {
int <caret>d = 4;
d *= 1.5;
return d;
}
}

View File

@@ -0,0 +1,7 @@
public class CompositeAssignmentCast {
public static int foo() {
int d;
d = (int) (4 * 1.5);
return d;
}
}

View File

@@ -92,15 +92,7 @@ public class InlineLocalTest extends LightJavaCodeInsightTestCase {
}
public void testAugmentedAssignment() {
String exception = null;
try {
doTest();
}
catch (RuntimeException ex) {
exception = ex.getMessage();
}
String error = RefactoringBundle.getCannotRefactorMessage(JavaRefactoringBundle.message("variable.is.accessed.for.writing", "text"));
assertEquals(error, exception);
doTest();
}
public void testUsedInInnerClass() { // IDEADEV-28786
@@ -355,6 +347,10 @@ public class InlineLocalTest extends LightJavaCodeInsightTestCase {
public void testEolComment() {
doTest();
}
public void testCompositeAssignment() { doTest(); }
public void testCompositeAssignmentCast() { doTest(); }
private void doTest(String conflictMessage) {
try {