IDEA-111702 Java Rearranger illegal forward reference on fields rearrangement [CR-IC-3034]

This commit is contained in:
Yaroslav Lepenkin
2013-11-22 14:34:25 +04:00
parent 3b019b5efa
commit 5bd841b2ba
6 changed files with 132 additions and 54 deletions
@@ -1178,7 +1178,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
}
private boolean shouldEnforceIndentToChildren(@NotNull ASTNode node) {
// Filter only anonymous class instances as method call arguments
if (myNode.getElementType() != JavaElementType.EXPRESSION_LIST) {
return false;
}
@@ -1186,13 +1185,10 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
if (parent == null || parent.getElementType() != JavaElementType.METHOD_CALL_EXPRESSION) {
return false;
}
if (!isAnonymousClass(node) || !JavaFormatterUtil.hasAnonymousClassesArguments((PsiExpressionList)myNode.getPsi(), 2)) {
return false;
}
// Enforce indent only if anonymous class instance expression doesn't start new line and have anonymous class expression sibling.
ASTNode prev = node.getTreePrev();
return prev != null && !(StringUtil.containsLineBreak(prev.getChars()) && prev.getElementType() != TokenType.WHITE_SPACE);
PsiExpressionList methodParamsList = (PsiExpressionList)myNode.getPsi();
return JavaFormatterUtil.hasMultilineArguments(methodParamsList)
&& JavaFormatterUtil.isMultilineExceptArguments(methodParamsList);
}
private static boolean isAnonymousClass(@Nullable ASTNode node) {
@@ -19,10 +19,10 @@ import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiExpressionList;
import com.intellij.psi.PsiPolyadicExpression;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
@@ -75,35 +75,36 @@ public class JavaFormatterUtil {
return expression1.getOperationTokenType() == expression2.getOperationTokenType();
}
/**
* Allows to check if given expression list has given number of anonymous classes.
*
* @param count interested number of anonymous classes used at the given expression list
* @return <code>true</code> if given expression list contains given number of anonymous classes;
* <code>false</code> otherwise
*/
public static boolean hasAnonymousClassesArguments(@NotNull PsiExpressionList expressionList, int count) {
int found = 0;
for (PsiExpression expression : expressionList.getExpressions()) {
ASTNode node = expression.getNode();
if (isAnonymousClass(node)) {
found++;
}
if (found >= count) {
public static boolean hasMultilineArguments(@NotNull PsiExpressionList list) {
PsiExpression[] arguments = list.getExpressions();
for (PsiExpression argument: arguments) {
ASTNode node = argument.getNode();
if (node.textContains('\n'))
return true;
}
}
return false;
}
private static boolean isAnonymousClass(@Nullable final ASTNode node) {
if (node == null) {
return false;
public static boolean isMultilineExceptArguments(@NotNull PsiExpressionList list) {
PsiExpression[] arguments = list.getExpressions();
for (PsiExpression argument : arguments) {
ASTNode beforeArgument = argument.getNode().getTreePrev();
if (isWhiteSpaceWithLineFeed(beforeArgument))
return true;
}
ASTNode nodeToCheck = node;
if (node.getElementType() == JavaElementType.NEW_EXPRESSION) {
nodeToCheck = node.getLastChildNode();
}
return nodeToCheck != null && nodeToCheck.getElementType() == JavaElementType.ANONYMOUS_CLASS;
PsiExpression lastArgument = arguments[arguments.length - 1];
ASTNode afterLastArgument = lastArgument.getNode().getTreeNext();
return isWhiteSpaceWithLineFeed(afterLastArgument);
}
private static boolean isWhiteSpaceWithLineFeed(@NotNull ASTNode node) {
return node instanceof PsiWhiteSpace
&& node.textContains('\n');
}
}
@@ -1135,7 +1135,7 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor {
createParenthSpace(mySettings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_EMPTY_METHOD_CALL_PARENTHESES);
}
else if (myRole2 == ChildRole.RPARENTH) {
if (JavaFormatterUtil.hasAnonymousClassesArguments(list, 2)) {
if (JavaFormatterUtil.hasMultilineArguments(list) && JavaFormatterUtil.isMultilineExceptArguments(list)) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, 0);
}
else {
@@ -7,6 +7,7 @@ class Foo {
settings,
indentOptions,
child2.getTextRange(),
false);
false
);
}
}
@@ -340,10 +340,11 @@ public class JavaFormatterIndentationTest extends AbstractJavaFormatterTest {
"});",
"foo(1,\n" +
" 2, new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" }\n" +
"});"
" @Override\n" +
" public void run() {\n" +
" }\n" +
" }\n" +
");"
);
doMethodTest(
@@ -446,16 +447,95 @@ public class JavaFormatterIndentationTest extends AbstractJavaFormatterTest {
" }\n" +
" });",
"foo(new Runnable() {\n" +
" public void run() {\n" +
" }\n" +
" }, new Runnable() {\n" +
" public void run() {\n" +
" }\n" +
" public void run() {\n" +
" }\n" +
");"
"}, new Runnable() {\n" +
" public void run() {\n" +
" }\n" +
"});"
);
}
public void testAlignMultipleAnonymousClasses_PassedAsMethodParameters() throws Exception {
String text = "test(new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"AAA!\");\n" +
" }\n" +
"}, new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"BBB!\");\n" +
" }\n" +
"});\n";
doMethodTest(text, text);
}
public void testAlignmentAdditionalParamsWithMultipleAnonymousClasses_PassedAsMethodParameters() throws Exception {
String text = "foo(1221, new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"A\");\n" +
" }\n" +
"}, new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"BB\");\n" +
" }\n" +
"});";
doMethodTest(text, text);
}
public void testAlignmentMultipleParamsWithAnonymousClass_PassedAsMethodParams() throws Exception {
getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
String text = "test(1000,\n" +
" new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"BBB\");\n" +
" }\n" +
" }\n" +
");";
doMethodTest(text, text);
}
public void testAlignmentMultipleAnonymousClassesOnNewLines() throws Exception {
getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
String text = "test(1000,\n" +
" new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"BBB\");\n" +
" }\n" +
" },\n" +
" new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"BBB\");\n" +
" }\n" +
" }\n" +
");";
doMethodTest(text, text);
}
public void testEnforceChildrenIndent_OfAnonymousClasses_IfAnyOfParamsIsLocatedOnNewLine() throws Exception {
getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
String text = "test(\"Suuuuuuuuuuuuuuuuuper loooooooooooong string\",\n" +
" \"Next loooooooooooooooooooooong striiiiiiiiiiing\", new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
"\n" +
" }\n" +
" }, new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
"\n" +
" }\n" +
" }\n" +
");\n";
doMethodTest(text, text);
}
public void testPackagePrivateAnnotation() {
// Inspired by IDEA-67294
@@ -480,13 +560,12 @@ public class JavaFormatterIndentationTest extends AbstractJavaFormatterTest {
" }\n" +
" }, )",
"test(new Runnable() {\n" +
" public void run() {\n" +
" }\n" +
" }, new Runnable() {\n" +
" public void run() {\n" +
" }\n" +
" },\n" +
")"
" public void run() {\n" +
" }\n" +
"}, new Runnable() {\n" +
" public void run() {\n" +
" }\n" +
"}, )"
);
}
@@ -325,7 +325,8 @@ public class JavaFormatterWrapTest extends AbstractJavaFormatterTest {
"test(1,\n" +
" 2,\n" +
" Test.\n" +
" loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongMethod());\n" +
" loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongMethod()\n" +
");\n" +
"int i = 1;\n" +
"int j = 2;";
doMethodTest(text, text);