IDEA-190558 Join lines: smart concatenation of assignment and the subsequent reassignment with the method call

This commit is contained in:
Tagir Valeev
2018-04-19 15:48:39 +07:00
parent 279c952a11
commit 5f34c4c223
8 changed files with 106 additions and 1 deletions

View File

@@ -408,6 +408,7 @@
order="before samePsiMember"/>
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.BlockJoinLinesHandler"/>
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.ChainCallJoinLinesHandler"/>
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.AssignmentSequenceJoinLinesHandler"/>
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.DeclarationJoinLinesHandler"/>
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.LiteralJoinLinesHandler"/>
<editorSmartKeysConfigurable instance="com.intellij.application.options.JavadocOptionsProvider"

View File

@@ -0,0 +1,55 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight.editorActions;
import com.intellij.openapi.editor.Document;
import com.intellij.psi.*;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.ig.psiutils.ExpressionUtils;
import org.jetbrains.annotations.NotNull;
import static com.intellij.util.ObjectUtils.tryCast;
/**
* <pre>{@code
* x = ...;
* x = x.a().b().c();
* =>
* x = (...).a().b().c();}</pre>
*/
public class AssignmentSequenceJoinLinesHandler implements JoinLinesHandlerDelegate {
@Override
public int tryJoinLines(@NotNull final Document document, @NotNull final PsiFile psiFile, final int start, final int end) {
PsiJavaToken elementAtStartLineEnd = tryCast(psiFile.findElementAt(start), PsiJavaToken.class);
if (elementAtStartLineEnd == null) return CANNOT_JOIN;
PsiElement firstElement = elementAtStartLineEnd.getParent();
PsiExpression firstValue = null;
PsiVariable variable = null;
if (firstElement instanceof PsiExpressionStatement) {
PsiExpressionStatement firstStatement = (PsiExpressionStatement)firstElement;
PsiAssignmentExpression firstAssignment = ExpressionUtils.getAssignment(firstStatement);
if (firstAssignment == null) return CANNOT_JOIN;
PsiReferenceExpression ref = tryCast(PsiUtil.skipParenthesizedExprDown(firstAssignment.getLExpression()), PsiReferenceExpression.class);
if (ref == null) return CANNOT_JOIN;
variable = tryCast(ref.resolve(), PsiVariable.class);
firstValue = firstAssignment.getRExpression();
} else if (firstElement instanceof PsiLocalVariable) {
variable = (PsiLocalVariable)firstElement;
firstValue = variable.getInitializer();
}
if (firstValue == null || !(variable instanceof PsiLocalVariable) && !(variable instanceof PsiParameter)) return CANNOT_JOIN;
PsiExpressionStatement secondStatement = PsiTreeUtil.getParentOfType(psiFile.findElementAt(end), PsiExpressionStatement.class);
PsiExpression secondValue = ExpressionUtils.getAssignmentTo(secondStatement, variable);
if (!(secondValue instanceof PsiMethodCallExpression)) return CANNOT_JOIN;
PsiExpression qualifier = ChainCallJoinLinesHandler.getDeepQualifier((PsiMethodCallExpression)secondValue);
if (!ExpressionUtils.isReferenceTo(qualifier, variable)) return CANNOT_JOIN;
if (ReferencesSearch.search(variable, new LocalSearchScope(secondValue)).findAll().size() > 1) return CANNOT_JOIN;
qualifier.replace(firstValue);
firstValue.replace(secondValue);
secondStatement.delete();
return firstElement.getTextRange().getEndOffset();
}
}

View File

@@ -13,6 +13,14 @@ import org.jetbrains.annotations.Nullable;
import static com.intellij.util.ObjectUtils.tryCast;
/**
* <pre>{@code
* sb.append(a);
* sb.append(b);
* =>
* sb.append(a).append(b);
* }</pre>
*/
public class ChainCallJoinLinesHandler implements JoinLinesHandlerDelegate {
@Override
public int tryJoinLines(@NotNull final Document document, @NotNull final PsiFile psiFile, final int start, final int end) {
@@ -80,7 +88,7 @@ public class ChainCallJoinLinesHandler implements JoinLinesHandlerDelegate {
}
@Nullable
private static PsiExpression getDeepQualifier(PsiMethodCallExpression firstCall) {
static PsiExpression getDeepQualifier(PsiMethodCallExpression firstCall) {
PsiExpression firstQualifier = firstCall;
while (firstQualifier instanceof PsiMethodCallExpression) {
firstQualifier = ((PsiMethodCallExpression)firstQualifier).getMethodExpression().getQualifierExpression();

View File

@@ -0,0 +1,10 @@
class Foo {
interface X {
X getParent();
}
void test(X x) {
<caret>x = x.getParent();
x = x.getParent();
}
}

View File

@@ -0,0 +1,9 @@
class Foo {
interface X {
X getParent();
}
void test(X x) {
x = x.getParent().getParent();<caret>
}
}

View File

@@ -0,0 +1,10 @@
class Foo {
interface X {
X getParent();
}
void test(X x1, X x2, boolean b) {
<caret>X x = b ? x1 : x2;
x = x.getParent();
}
}

View File

@@ -0,0 +1,9 @@
class Foo {
interface X {
X getParent();
}
void test(X x1, X x2, boolean b) {
X x = (b ? x1 : x2).getParent();<caret>
}
}

View File

@@ -47,6 +47,9 @@ public class JoinLinesTest extends LightCodeInsightTestCase {
public void testDeclarationAndCallSelfRef() { doTest(); }
public void testAssignmentAndCall() { doTest(); }
public void testDeclarationAndReassignmentWithCall() { doTest(); }
public void testAssignmentAndReassignmentWithCall() { doTest(); }
public void testSCR3493() {
CommonCodeStyleSettings settings = getJavaSettings();
boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER;