diff options
| author | Noopur Gupta | 2015-04-24 11:05:42 +0000 |
|---|---|---|
| committer | Dani Megert | 2015-04-24 11:09:06 +0000 |
| commit | 3a443bf6c995853505a6d457387e6d31e34b8346 (patch) | |
| tree | eebc25d914ffe48772d593dece6c365e921402ce | |
| parent | 73d8dadaa3d6b4137e8d105da35a454a1662ef2f (diff) | |
| download | eclipse.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
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); |
