mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
ChainCallJoinLinesHandler: join chained calls; assignment/declaration+call
Fixes IDEA-54209 Join Lines should be able to merge multiple method calls into a chained call
This commit is contained in:
@@ -406,6 +406,7 @@
|
||||
<weigher key="proximity" implementationClass="com.intellij.psi.util.proximity.ReferenceListWeigher" id="referenceList"
|
||||
order="before samePsiMember"/>
|
||||
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.BlockJoinLinesHandler"/>
|
||||
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.ChainCallJoinLinesHandler"/>
|
||||
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.DeclarationJoinLinesHandler"/>
|
||||
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.LiteralJoinLinesHandler"/>
|
||||
<editorSmartKeysConfigurable instance="com.intellij.application.options.JavadocOptionsProvider"
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
// 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.codeInsight.PsiEquivalenceUtil;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
|
||||
public class ChainCallJoinLinesHandler 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;
|
||||
PsiExpressionStatement secondStatement = PsiTreeUtil.getParentOfType(psiFile.findElementAt(end), PsiExpressionStatement.class);
|
||||
if (secondStatement == null) return CANNOT_JOIN;
|
||||
PsiMethodCallExpression secondCall = tryCast(secondStatement.getExpression(), PsiMethodCallExpression.class);
|
||||
if (secondCall == null) return CANNOT_JOIN;
|
||||
PsiElement firstStatement = elementAtStartLineEnd.getParent();
|
||||
|
||||
boolean result = false;
|
||||
if (firstStatement instanceof PsiExpressionStatement) {
|
||||
PsiExpression firstExpression = ((PsiExpressionStatement)firstStatement).getExpression();
|
||||
if (firstExpression instanceof PsiMethodCallExpression) {
|
||||
result = joinTwoCalls((PsiMethodCallExpression)firstExpression, secondCall);
|
||||
} else if (firstExpression instanceof PsiAssignmentExpression) {
|
||||
result = joinAssignmentAndCall((PsiAssignmentExpression)firstExpression, secondCall);
|
||||
}
|
||||
}
|
||||
else if (firstStatement instanceof PsiLocalVariable) {
|
||||
PsiLocalVariable var = (PsiLocalVariable)firstStatement;
|
||||
result = joinExpressionAndCall(var, var.getInitializer(), secondCall);
|
||||
}
|
||||
if (!result) return CANNOT_JOIN;
|
||||
secondStatement.delete();
|
||||
return firstStatement.getTextRange().getEndOffset();
|
||||
}
|
||||
|
||||
private static boolean joinAssignmentAndCall(PsiAssignmentExpression assignmentExpression, PsiMethodCallExpression nextCall) {
|
||||
if (!assignmentExpression.getOperationTokenType().equals(JavaTokenType.EQ)) return false;
|
||||
PsiLocalVariable var = ExpressionUtils.resolveLocalVariable(assignmentExpression.getLExpression());
|
||||
if (var == null) return false;
|
||||
return joinExpressionAndCall(var, assignmentExpression.getRExpression(), nextCall);
|
||||
}
|
||||
|
||||
private static boolean joinExpressionAndCall(PsiLocalVariable var, PsiExpression initializer, PsiMethodCallExpression nextCall) {
|
||||
if (initializer == null) return false;
|
||||
PsiExpression qualifier = getDeepQualifier(nextCall);
|
||||
if (!ExpressionUtils.isReferenceTo(qualifier, var)) return false;
|
||||
PsiType type = nextCall.getType();
|
||||
if (type == null || !type.equals(initializer.getType())) return false;
|
||||
qualifier.replace(initializer);
|
||||
initializer.replace(nextCall);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean joinTwoCalls(PsiMethodCallExpression firstCall,
|
||||
@NotNull PsiMethodCallExpression secondCall) {
|
||||
|
||||
if (firstCall == null) return false;
|
||||
PsiExpression firstQualifier = getDeepQualifier(firstCall);
|
||||
if (firstQualifier == null) return false;
|
||||
PsiExpression secondQualifier = getDeepQualifier(secondCall);
|
||||
if (secondQualifier == null) return false;
|
||||
|
||||
if (!PsiEquivalenceUtil.areElementsEquivalent(firstQualifier, secondQualifier)) return false;
|
||||
PsiType type = firstCall.getType();
|
||||
if (type == null || !firstCall.getType().equals(firstQualifier.getType())) return false;
|
||||
|
||||
secondQualifier.replace(firstCall);
|
||||
firstCall.replace(secondCall);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiExpression getDeepQualifier(PsiMethodCallExpression firstCall) {
|
||||
PsiExpression firstQualifier = firstCall;
|
||||
while (firstQualifier instanceof PsiMethodCallExpression) {
|
||||
firstQualifier = ((PsiMethodCallExpression)firstQualifier).getMethodExpression().getQualifierExpression();
|
||||
}
|
||||
return firstQualifier;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
void test() {
|
||||
StringBuilder sb;
|
||||
<caret>sb = new StringBuilder();
|
||||
sb.append("foo");
|
||||
sb.append("bar");
|
||||
sb.append("baz");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class Foo {
|
||||
void test() {
|
||||
StringBuilder sb;
|
||||
sb = new StringBuilder().append("foo");<caret>
|
||||
sb.append("bar");
|
||||
sb.append("baz");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class Foo {
|
||||
void test() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
<caret>sb.append("foo");
|
||||
sb.append("bar");
|
||||
sb.append("baz");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
void test() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
<caret>sb.append("foo").append("bar");
|
||||
sb.append("baz");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void test() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("foo").append("bar").append("baz");<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class Foo {
|
||||
void test() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
<caret>sb.length();
|
||||
sb.append("bar");
|
||||
sb.append("baz");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
void test() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.length();<caret>sb.append("bar");
|
||||
sb.append("baz");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
void test() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("foo").append("bar");<caret>
|
||||
sb.append("baz");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class Foo {
|
||||
void test() {
|
||||
<caret>StringBuilder sb = new StringBuilder();
|
||||
sb.append("foo");
|
||||
sb.append("bar");
|
||||
sb.append("baz");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
void test() {
|
||||
StringBuilder sb = new StringBuilder().append("foo");<caret>
|
||||
sb.append("bar");
|
||||
sb.append("baz");
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,12 @@ public class JoinLinesTest extends LightCodeInsightTestCase {
|
||||
public void testStringLiteral() { doTest(); }
|
||||
public void testLiteralSCR4989() { doTest(); }
|
||||
|
||||
public void testCallChain() { doTest(); }
|
||||
public void testCallChain2() { doTest(); }
|
||||
public void testCallChainWrong() { doTest(); }
|
||||
public void testDeclarationAndCall() { doTest(); }
|
||||
public void testAssignmentAndCall() { doTest(); }
|
||||
|
||||
public void testSCR3493() {
|
||||
CommonCodeStyleSettings settings = getJavaSettings();
|
||||
boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER;
|
||||
@@ -68,7 +74,7 @@ public class JoinLinesTest extends LightCodeInsightTestCase {
|
||||
}
|
||||
public void testSCR3493b() {
|
||||
CommonCodeStyleSettings settings = getJavaSettings();
|
||||
boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER;;
|
||||
boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER;
|
||||
boolean smart_tabs = settings.getIndentOptions().SMART_TABS;
|
||||
try {
|
||||
settings.getIndentOptions().USE_TAB_CHARACTER = true;
|
||||
@@ -262,7 +268,7 @@ public class JoinLinesTest extends LightCodeInsightTestCase {
|
||||
checkResultByFile(path + getTestName(false) + "_after" + ext);
|
||||
}
|
||||
|
||||
private void performAction() {
|
||||
private static void performAction() {
|
||||
EditorActionManager actionManager = EditorActionManager.getInstance();
|
||||
EditorActionHandler actionHandler = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_JOIN_LINES);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user