mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Java: Don't fold too complex expressions when extracting method (IDEA-175221, IDEA-167255)
This commit is contained in:
+58
-12
@@ -225,22 +225,27 @@ public class ParametersFolder {
|
||||
if (isAccessedForWriting((PsiExpression)expression)) {
|
||||
return null;
|
||||
}
|
||||
for (PsiElement scopeElement : scopeElements) {
|
||||
if (PsiTreeUtil.isAncestor(expression, scopeElement, true)) {
|
||||
expression = null;
|
||||
break;
|
||||
}
|
||||
if (isAncestor(expression, scopeElements)) {
|
||||
break;
|
||||
}
|
||||
if (dependsOnLocals(expression, inputVariables)) {
|
||||
break;
|
||||
}
|
||||
final PsiElement parent = expression.getParent();
|
||||
if (parent instanceof PsiExpressionStatement) {
|
||||
break;
|
||||
}
|
||||
if (expression == null) break;
|
||||
|
||||
final PsiType expressionType = ((PsiExpression)expression).getType();
|
||||
if (expressionType != null && !PsiType.VOID.equals(expressionType) && !(expression.getParent() instanceof PsiExpressionStatement)) {
|
||||
if (dependsOnLocals(expression, inputVariables)) {
|
||||
break;
|
||||
}
|
||||
if (expressionType == null || PsiType.VOID.equals(expressionType)) {
|
||||
break;
|
||||
}
|
||||
if (isTooLongExpressionChain(expression)) {
|
||||
break;
|
||||
}
|
||||
if (!isMethodNameExpression(expression)) {
|
||||
expressions.add((PsiExpression)expression);
|
||||
}
|
||||
expression = PsiTreeUtil.getParentOfType(expression, PsiExpression.class);
|
||||
expression = parent instanceof PsiExpression ? parent : null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -275,6 +280,47 @@ public class ParametersFolder {
|
||||
return exprWithWriteAccessInside[0] != null;
|
||||
}
|
||||
|
||||
private static boolean isAncestor(PsiElement expression, PsiElement[] scopeElements) {
|
||||
for (PsiElement scopeElement : scopeElements) {
|
||||
if (PsiTreeUtil.isAncestor(expression, scopeElement, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isTooLongExpressionChain(PsiElement expression) {
|
||||
int count = 0;
|
||||
for (PsiElement element = getInnerExpression(expression); element != null; element = getInnerExpression(element)) {
|
||||
count++;
|
||||
if (count > 1) { // expression chains like 'var.foo().bar()' and 'var.foo[i].bar()' are too long
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static PsiElement getInnerExpression(PsiElement expression) {
|
||||
if (expression instanceof PsiMethodCallExpression) {
|
||||
return ((PsiMethodCallExpression)expression).getMethodExpression().getQualifierExpression();
|
||||
}
|
||||
if (expression instanceof PsiArrayAccessExpression) {
|
||||
while (expression instanceof PsiArrayAccessExpression) {
|
||||
expression = ((PsiArrayAccessExpression)expression).getArrayExpression();
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isMethodNameExpression(@NotNull PsiElement expression) {
|
||||
final PsiElement parent = expression.getParent();
|
||||
return expression instanceof PsiReferenceExpression &&
|
||||
parent instanceof PsiMethodCallExpression &&
|
||||
((PsiReferenceExpression)expression).getReferenceNameElement() ==
|
||||
((PsiMethodCallExpression)parent).getMethodExpression().getReferenceNameElement();
|
||||
}
|
||||
|
||||
private static boolean dependsOnLocals(final PsiElement expression, final List<? extends PsiVariable> inputVariables) {
|
||||
final boolean[] localVarsUsed = new boolean[]{false};
|
||||
expression.accept(new JavaRecursiveElementWalkingVisitor(){
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
boolean bar(String[][] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
for (int j = 0; i < a[i].length; j++) {<selection>
|
||||
if (a[i][j].length() > 3 && i % 3 == 0)
|
||||
return true;
|
||||
</selection>
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
class Foo {
|
||||
boolean bar(String[][] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
for (int j = 0; i < a[i].length; j++) {
|
||||
if (newMethod(a[i][j], i)) return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean newMethod(String s, int i) {
|
||||
if (s.length() > 3 && i % 3 == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
class UseBuilder {
|
||||
void test(Builder builder, int[] arr) {
|
||||
<selection>builder.foo("xyz").bar(arr[0]).foo("abc");</selection>
|
||||
}
|
||||
|
||||
static class Builder {
|
||||
Builder foo(String s) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder bar(int x) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
class UseBuilder {
|
||||
void test(Builder builder, int[] arr) {
|
||||
<selection>builder.foo("xyz").bar(arr[0])</selection>.foo("abc");
|
||||
}
|
||||
|
||||
static class Builder {
|
||||
Builder foo(String s) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder bar(int x) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
class UseBuilder {
|
||||
void test(Builder builder, int[] arr) {
|
||||
newMethod(builder, arr[0]).foo("abc");
|
||||
}
|
||||
|
||||
private Builder newMethod(Builder builder, int x) {
|
||||
return builder.foo("xyz").bar(x);
|
||||
}
|
||||
|
||||
static class Builder {
|
||||
Builder foo(String s) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder bar(int x) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
boolean bar(String[] a) {
|
||||
for (int i = 0; i < a.length; i++) {<selection>
|
||||
if (a[i].length() > 3 && i % 3 == 0)
|
||||
return true;
|
||||
</selection>}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
class Foo {
|
||||
boolean bar(String[] a) {
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (newMethod(a[i], i)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean newMethod(String s, int i) {
|
||||
if (s.length() > 3 && i % 3 == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
class UseBuilder {
|
||||
void test(Builder builder, int[] arr) {
|
||||
newMethod(builder, arr[0]);
|
||||
}
|
||||
|
||||
private void newMethod(Builder builder, int x) {
|
||||
builder.foo("xyz").bar(x).foo("abc");
|
||||
}
|
||||
|
||||
static class Builder {
|
||||
Builder foo(String s) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder bar(int x) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class C {
|
||||
int foo(String[][] vars, int i, int j) {
|
||||
return <selection>vars[i][j].length()</selection>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class C {
|
||||
int foo(String[][] vars, int i, int j) {
|
||||
return newMethod(vars[i][j]);
|
||||
}
|
||||
|
||||
private int newMethod(String s) {
|
||||
return s.length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class C {
|
||||
int foo(String[] vars, int i) {
|
||||
return <selection>vars[i].length()</selection>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class C {
|
||||
int foo(String[] vars, int i) {
|
||||
return newMethod(vars[i]);
|
||||
}
|
||||
|
||||
private int newMethod(String var) {
|
||||
return var.length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class C {
|
||||
String[] vars;
|
||||
int foo(C c, int i) {
|
||||
return <selection>c.vars[i].length()</selection>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
class C {
|
||||
String[] vars;
|
||||
int foo(C c, int i) {
|
||||
return newMethod(c.vars[i]);
|
||||
}
|
||||
|
||||
private int newMethod(String var) {
|
||||
return var.length();
|
||||
}
|
||||
}
|
||||
@@ -974,6 +974,34 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBuilderChainWithArrayAccess() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBuilderChainWithArrayAccessExpr() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBuilderChainWithArrayAccessIf() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBuilderChainWith2DimArrayAccess() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCallOnArrayElement() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCallOn2DimArrayElement() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCallOnFieldArrayElement() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTestDisabledParam() throws PrepareFailedException {
|
||||
final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject());
|
||||
settings.ELSE_ON_NEW_LINE = true;
|
||||
|
||||
Reference in New Issue
Block a user