Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoopur Gupta2015-04-24 11:05:42 +0000
committerDani Megert2015-04-24 11:09:06 +0000
commit3a443bf6c995853505a6d457387e6d31e34b8346 (patch)
treeeebc25d914ffe48772d593dece6c365e921402ce
parent73d8dadaa3d6b4137e8d105da35a454a1662ef2f (diff)
downloadeclipse.jdt.ui-3a443bf6c995853505a6d457387e6d31e34b8346.tar.gz
eclipse.jdt.ui-3a443bf6c995853505a6d457387e6d31e34b8346.tar.xz
eclipse.jdt.ui-3a443bf6c995853505a6d457387e6d31e34b8346.zip
Fixed bug 400670: [Save actions] Correct indentation conflicts with formatter causing staircase effect
-rw-r--r--org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/IndentActionTest.java38
-rw-r--r--org.eclipse.jdt.text.tests/testResources/indentation/bug400670_1/Before.java55
-rw-r--r--org.eclipse.jdt.text.tests/testResources/indentation/bug400670_1/Modified.java55
-rw-r--r--org.eclipse.jdt.text.tests/testResources/indentation/bug400670_2/Before.java38
-rw-r--r--org.eclipse.jdt.text.tests/testResources/indentation/bug400670_2/Modified.java38
-rw-r--r--org.eclipse.jdt.text.tests/testResources/indentation/bug424772/Modified.java2
-rw-r--r--org.eclipse.jdt.text.tests/testResources/indentation/bug458763/Before.java17
-rw-r--r--org.eclipse.jdt.text.tests/testResources/indentation/bug458763/Modified.java17
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaIndenter.java127
9 files changed, 370 insertions, 17 deletions
diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/IndentActionTest.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/IndentActionTest.java
index ff90b177f6..db54050669 100644
--- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/IndentActionTest.java
+++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/IndentActionTest.java
@@ -207,4 +207,42 @@ public class IndentActionTest extends TestCase {
selectAll();
assertIndentResult();
}
+
+ public void testBug400670_1() throws Exception {
+ // With formatter profile from https://bugs.eclipse.org/bugs/show_bug.cgi?id=400670#c0
+ String indentOnColumn= DefaultCodeFormatterConstants.createAlignmentValue(true, DefaultCodeFormatterConstants.WRAP_NEXT_PER_LINE, DefaultCodeFormatterConstants.INDENT_ON_COLUMN);
+ IJavaProject project= IndentTestSetup.getProject();
+ String value1= project.getOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ENUM_CONSTANTS, true);
+ project.setOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ENUM_CONSTANTS, indentOnColumn);
+ String value2= project.getOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION, true);
+ project.setOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION, indentOnColumn);
+ String value3= project.getOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_ARRAY_INITIALIZER, true);
+ project.setOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_ARRAY_INITIALIZER, indentOnColumn);
+ try {
+ selectAll();
+ assertIndentResult();
+ } finally {
+ project.setOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ENUM_CONSTANTS, value1);
+ project.setOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION, value2);
+ project.setOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_ARRAY_INITIALIZER, value3);
+ }
+ }
+
+ public void testBug400670_2() throws Exception {
+ // With default formatter profile
+ selectAll();
+ assertIndentResult();
+ }
+
+ public void testBug458763() throws Exception {
+ IJavaProject project= IndentTestSetup.getProject();
+ String value= project.getOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH, true);
+ project.setOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH, DefaultCodeFormatterConstants.FALSE);
+ try {
+ selectAll();
+ assertIndentResult();
+ } finally {
+ project.setOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH, value);
+ }
+ }
}
diff --git a/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_1/Before.java b/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_1/Before.java
new file mode 100644
index 0000000000..b5b0f31598
--- /dev/null
+++ b/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_1/Before.java
@@ -0,0 +1,55 @@
+package p;
+
+public enum TestEnum {
+
+ FIRST_ENUM("first type",
+ new SomeClass(),
+ new OtherEnumType[] { OtherEnumType.FOO }),
+
+ SECOND_ENUM("second type",
+ new SomeClassOtherClass(),
+ new OtherEnumType[] { OtherEnumType.BAR }),
+
+ THIRD_ENUM("third type",
+ new SomeThirdClass(),
+ new OtherEnumType[] { OtherEnumType.BAZ }),
+
+ FOURTH_ENUM("fourth type",
+ new YetAnotherClass(),
+ new OtherEnumType[] { OtherEnumType.FOOBAR,
+ OtherEnumType.FOO,
+ OtherEnumType.FOOBARBAZ,
+ OtherEnumType.LONGERFOOBARBAZ,
+ OtherEnumType.REALLYLONGFOOBARBAZ,
+ OtherEnumType.MORELETTERSINHERE });
+
+ /* data members and methods go here */
+ TestEnum(String s, Cls s1, OtherEnumType[] e) {
+ }
+}
+
+enum OtherEnumType {
+ FOOBAR,
+ FOOBARBAZ,
+ FOO,
+ LONGERFOOBARBAZ,
+ REALLYLONGFOOBARBAZ,
+ MORELETTERSINHERE,
+ BAR,
+ BAZ
+}
+
+class Cls {
+}
+
+class SomeClass extends Cls {
+}
+
+class SomeThirdClass extends Cls {
+}
+
+class SomeClassOtherClass extends Cls {
+}
+
+class YetAnotherClass extends Cls {
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_1/Modified.java b/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_1/Modified.java
new file mode 100644
index 0000000000..5973ab5a1f
--- /dev/null
+++ b/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_1/Modified.java
@@ -0,0 +1,55 @@
+package p;
+
+public enum TestEnum {
+
+ FIRST_ENUM("first type",
+ new SomeClass(),
+ new OtherEnumType[] { OtherEnumType.FOO }),
+
+ SECOND_ENUM("second type",
+ new SomeClassOtherClass(),
+ new OtherEnumType[] { OtherEnumType.BAR }),
+
+ THIRD_ENUM("third type",
+ new SomeThirdClass(),
+ new OtherEnumType[] { OtherEnumType.BAZ }),
+
+ FOURTH_ENUM("fourth type",
+ new YetAnotherClass(),
+ new OtherEnumType[] { OtherEnumType.FOOBAR,
+ OtherEnumType.FOO,
+ OtherEnumType.FOOBARBAZ,
+ OtherEnumType.LONGERFOOBARBAZ,
+ OtherEnumType.REALLYLONGFOOBARBAZ,
+ OtherEnumType.MORELETTERSINHERE });
+
+ /* data members and methods go here */
+ TestEnum(String s, Cls s1, OtherEnumType[] e) {
+ }
+}
+
+enum OtherEnumType {
+ FOOBAR,
+ FOOBARBAZ,
+ FOO,
+ LONGERFOOBARBAZ,
+ REALLYLONGFOOBARBAZ,
+ MORELETTERSINHERE,
+ BAR,
+ BAZ
+}
+
+class Cls {
+}
+
+class SomeClass extends Cls {
+}
+
+class SomeThirdClass extends Cls {
+}
+
+class SomeClassOtherClass extends Cls {
+}
+
+class YetAnotherClass extends Cls {
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_2/Before.java b/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_2/Before.java
new file mode 100644
index 0000000000..982364d6c8
--- /dev/null
+++ b/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_2/Before.java
@@ -0,0 +1,38 @@
+package p;
+
+public enum TestEnum {
+
+ FIRST_ENUM("first type", new SomeClass(), new OtherEnumType[] { OtherEnumType.FOO }),
+
+ SECOND_ENUM("second type", new SomeClassOtherClass(), new OtherEnumType[] { OtherEnumType.BAR }),
+
+ THIRD_ENUM("third type", new SomeThirdClass(), new OtherEnumType[] { OtherEnumType.BAZ }),
+
+ FOURTH_ENUM("fourth type", new YetAnotherClass(),
+ new OtherEnumType[] { OtherEnumType.FOOBAR, OtherEnumType.FOO, OtherEnumType.FOOBARBAZ,
+ OtherEnumType.LONGERFOOBARBAZ, OtherEnumType.REALLYLONGFOOBARBAZ,
+ OtherEnumType.MORELETTERSINHERE });
+
+ /* data members and methods go here */
+ TestEnum(String s, Cls s1, OtherEnumType[] e) {
+ }
+}
+
+enum OtherEnumType {
+ FOOBAR, FOOBARBAZ, FOO, LONGERFOOBARBAZ, REALLYLONGFOOBARBAZ, MORELETTERSINHERE, BAR, BAZ
+}
+
+class Cls {
+}
+
+class SomeClass extends Cls {
+}
+
+class SomeThirdClass extends Cls {
+}
+
+class SomeClassOtherClass extends Cls {
+}
+
+class YetAnotherClass extends Cls {
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_2/Modified.java b/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_2/Modified.java
new file mode 100644
index 0000000000..982364d6c8
--- /dev/null
+++ b/org.eclipse.jdt.text.tests/testResources/indentation/bug400670_2/Modified.java
@@ -0,0 +1,38 @@
+package p;
+
+public enum TestEnum {
+
+ FIRST_ENUM("first type", new SomeClass(), new OtherEnumType[] { OtherEnumType.FOO }),
+
+ SECOND_ENUM("second type", new SomeClassOtherClass(), new OtherEnumType[] { OtherEnumType.BAR }),
+
+ THIRD_ENUM("third type", new SomeThirdClass(), new OtherEnumType[] { OtherEnumType.BAZ }),
+
+ FOURTH_ENUM("fourth type", new YetAnotherClass(),
+ new OtherEnumType[] { OtherEnumType.FOOBAR, OtherEnumType.FOO, OtherEnumType.FOOBARBAZ,
+ OtherEnumType.LONGERFOOBARBAZ, OtherEnumType.REALLYLONGFOOBARBAZ,
+ OtherEnumType.MORELETTERSINHERE });
+
+ /* data members and methods go here */
+ TestEnum(String s, Cls s1, OtherEnumType[] e) {
+ }
+}
+
+enum OtherEnumType {
+ FOOBAR, FOOBARBAZ, FOO, LONGERFOOBARBAZ, REALLYLONGFOOBARBAZ, MORELETTERSINHERE, BAR, BAZ
+}
+
+class Cls {
+}
+
+class SomeClass extends Cls {
+}
+
+class SomeThirdClass extends Cls {
+}
+
+class SomeClassOtherClass extends Cls {
+}
+
+class YetAnotherClass extends Cls {
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.text.tests/testResources/indentation/bug424772/Modified.java b/org.eclipse.jdt.text.tests/testResources/indentation/bug424772/Modified.java
index 8a94591439..dcc47c6f71 100644
--- a/org.eclipse.jdt.text.tests/testResources/indentation/bug424772/Modified.java
+++ b/org.eclipse.jdt.text.tests/testResources/indentation/bug424772/Modified.java
@@ -15,7 +15,7 @@ public class Bug {
String t3(int i,
int j)
- [] []
+ [] []
{
return new String[0][0];
}
diff --git a/org.eclipse.jdt.text.tests/testResources/indentation/bug458763/Before.java b/org.eclipse.jdt.text.tests/testResources/indentation/bug458763/Before.java
new file mode 100644
index 0000000000..15eb6b50ed
--- /dev/null
+++ b/org.eclipse.jdt.text.tests/testResources/indentation/bug458763/Before.java
@@ -0,0 +1,17 @@
+package p;
+
+public enum Direction {NORTH, SOUTH, EAST, WEST; // note semicolon here
+public Direction opposite() {
+ switch (this) {
+ case NORTH:
+ return SOUTH;
+ case SOUTH:
+ return NORTH;
+ case EAST:
+ return WEST;
+ case WEST:
+ return EAST;
+ default: return null;
+ }
+}
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.text.tests/testResources/indentation/bug458763/Modified.java b/org.eclipse.jdt.text.tests/testResources/indentation/bug458763/Modified.java
new file mode 100644
index 0000000000..9c99b4d080
--- /dev/null
+++ b/org.eclipse.jdt.text.tests/testResources/indentation/bug458763/Modified.java
@@ -0,0 +1,17 @@
+package p;
+
+public enum Direction {NORTH, SOUTH, EAST, WEST; // note semicolon here
+ public Direction opposite() {
+ switch (this) {
+ case NORTH:
+ return SOUTH;
+ case SOUTH:
+ return NORTH;
+ case EAST:
+ return WEST;
+ case WEST:
+ return EAST;
+ default: return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaIndenter.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaIndenter.java
index 93942c9c4d..eca9262278 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaIndenter.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaIndenter.java
@@ -1037,10 +1037,14 @@ public final class JavaIndenter {
if (isTryWithResources()) {
fIndent= fPrefs.prefContinuationIndent;
return fPosition;
- } else {
- fPosition= pos;
- return skipToStatementStart(danglingElse, false);
}
+ fPosition= pos;
+ if (isSemicolonPartOfEnumBodyDeclaration()) {
+ fIndent= getBlockIndent(false, true);
+ return fPosition;
+ }
+ fPosition= pos;
+ return skipToStatementStart(danglingElse, false);
}
// scope introduction: special treat who special is
case Symbols.TokenLPAREN:
@@ -1537,6 +1541,8 @@ public final class JavaIndenter {
case Symbols.TokenRBRACE:
case Symbols.TokenGREATERTHAN:
skipScope();
+ startLine= fLine;
+ startPosition= fPosition;
break;
// scope introduction: special treat who special is
@@ -1687,13 +1693,16 @@ public final class JavaIndenter {
pos= fPosition; // store
// special: array initializer
- if (looksLikeArrayInitializerIntro())
- if (fPrefs.prefArrayDeepIndent)
+ if (looksLikeArrayInitializerIntro()) {
+ if (fPrefs.prefArrayDeepIndent) {
return setFirstElementAlignment(pos, bound);
- else
+ } else {
fIndent= fPrefs.prefArrayIndent;
- else
+ return pos;
+ }
+ } else {
fIndent= fPrefs.prefBlockIndent;
+ }
// normal: skip to the statement start before the scope introducer
// opening braces are often on differently ending indents than e.g. a method definition
@@ -1743,27 +1752,113 @@ public final class JavaIndenter {
/**
- * Returns <code>true</code> if the next token received after calling
- * <code>nextToken</code> is either an equal sign or an array designator ('[]').
+ * Returns <code>true</code> if the next token received after calling <code>nextToken</code> is
+ * either an equal sign or an array designator ('[]') preceded by array creation.
*
* @return <code>true</code> if the next elements look like the start of an array definition
*/
private boolean looksLikeArrayInitializerIntro() {
nextToken();
- if (fToken == Symbols.TokenEQUAL || skipBrackets()) {
+ if (fToken == Symbols.TokenEQUAL) {
return true;
}
+
+ if (!skipScope(Symbols.TokenLBRACKET, Symbols.TokenRBRACKET)) {
+ return false;
+ }
+ nextToken();
+ if (fToken == Symbols.TokenIDENT) { // type name
+ nextToken();
+ while (fToken == Symbols.TokenOTHER) { // dot of qualification
+ nextToken();
+ if (fToken != Symbols.TokenIDENT) // qualifying name
+ return false;
+ nextToken();
+ }
+ return fToken == Symbols.TokenNEW;
+ }
return false;
}
/**
- * Skips over the next <code>if</code> keyword. The current token when calling
- * this method must be an <code>else</code> keyword. Returns <code>true</code>
- * if a matching <code>if</code> could be found, <code>false</code> otherwise.
- * The cursor (<code>fPosition</code>) is set to the offset of the <code>if</code>
- * token.
+ * Returns <code>true</code> if the current position looks like a part of enum declaration
+ * header. It calls {@link #nextToken} to scan backwards.
+ *
+ * @return <code>true</code> if the current position looks like a part of enum declaration
+ * header
+ * @since 3.11
+ */
+ private boolean looksLikeEnumDeclaration() {
+ while (true) {
+ nextToken();
+ switch (fToken) {
+ case Symbols.TokenENUM:
+ return true;
+ case Symbols.TokenIDENT:
+ case Symbols.TokenCOMMA:
+ case Symbols.TokenAT:
+ break;
+ case Symbols.TokenOTHER:
+ try {
+ if (fDocument.getChar(fPosition) != '.') {
+ return false;
+ }
+ } catch (BadLocationException e) {
+ return false;
+ }
+ break;
+ case Symbols.TokenRPAREN:
+ case Symbols.TokenRBRACKET:
+ case Symbols.TokenRBRACE:
+ case Symbols.TokenGREATERTHAN:
+ skipScope();
+ break;
+ case Symbols.TokenEOF:
+ return false;
+ default:
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Checks if the semicolon at the current position is part of enum body declaration.
+ *
+ * @return returns <code>true</code> if the semicolon at the current position is part of enum
+ * body declaration
+ * @since 3.11
+ */
+ private boolean isSemicolonPartOfEnumBodyDeclaration() {
+ while (true) {
+ nextToken();
+ switch (fToken) {
+ case Symbols.TokenLBRACE:
+ return looksLikeEnumDeclaration();
+ case Symbols.TokenIDENT:
+ case Symbols.TokenCOMMA:
+ break;
+ case Symbols.TokenRPAREN:
+ case Symbols.TokenRBRACKET:
+ case Symbols.TokenRBRACE:
+ case Symbols.TokenGREATERTHAN:
+ skipScope();
+ break;
+ case Symbols.TokenEOF:
+ return false;
+ default:
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Skips over the next <code>if</code> keyword. The current token when calling this method must
+ * be an <code>else</code> keyword. Returns <code>true</code> if a matching <code>if</code>
+ * could be found, <code>false</code> otherwise. The cursor (<code>fPosition</code>) is set to
+ * the offset of the <code>if</code> token.
*
- * @return <code>true</code> if a matching <code>if</code> token was found, <code>false</code> otherwise
+ * @return <code>true</code> if a matching <code>if</code> token was found, <code>false</code>
+ * otherwise
*/
private boolean skipNextIF() {
Assert.isTrue(fToken == Symbols.TokenELSE);

Back to the top