diff options
9 files changed, 410 insertions, 60 deletions
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java index fd60744ffb..266b0ee01f 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java @@ -15220,4 +15220,20 @@ public void testBug421492d() throws JavaModelException { this.formatterPrefs.blank_lines_after_code_block = ~0; formatSourceInWorkspace("test421492", "in.java", "D_out.java"); } +/** + * https://bugs.eclipse.org/390720 - [formatter] Add setting for blank line between case blocks (after break) for switch statement + */ +public void testBug390720a() throws JavaModelException { + setComplianceLevel(CompilerOptions.VERSION_12); + this.formatterPrefs.blank_lines_between_statement_groups_in_switch = 2; + formatSourceInWorkspace("test390720", "in.java", "A_out.java"); +} +/** + * https://bugs.eclipse.org/390720 - [formatter] Add setting for blank line between case blocks (after break) for switch statement + */ +public void testBug390720b() throws JavaModelException { + setComplianceLevel(CompilerOptions.VERSION_12); + this.formatterPrefs.blank_lines_between_statement_groups_in_switch = ~0; + formatSourceInWorkspace("test390720", "in.java", "B_out.java"); +} } diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test212867/D_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test212867/D_out.java index b199a84fce..41838f98ce 100644 --- a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test212867/D_out.java +++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test212867/D_out.java @@ -43,7 +43,9 @@ class Example { } if (8 == 8) { // comment + statement(); + // comment } if (33 == 33) { @@ -65,7 +67,9 @@ class Example { } if (88 == 88) { /* comment */ + statement(); + /* comment */ } for (int i = 0; i < 10; i++) { diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test390720/A_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test390720/A_out.java new file mode 100644 index 0000000000..683eafb167 --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test390720/A_out.java @@ -0,0 +1,128 @@ +package test; + +public class MyTest { + + void f(int a, int b) { + switch (a) { + case 1: + doSomething(); + break; + + + case 2: + case 3: + doSomeOtherThing(); + break; + + + case 4: { + // break missing, oh well... + } + + + case 5: { + doSomething(55); + break; + } + + + default: + doNothing(); + break; + } + + int c = switch (b) { + case 444: + break a + b; + + + case 555: + case 666: + doSoemthing(); + break 777; + + + default: + doSomeOtherSomething(); + return; + + }; + + int d = switch (c) { + case 1 -> 6; + case 2 -> { + int f = a + b; + break f * f; + } + default -> 55; + }; + + while (true) { + switch (a + b + c + d) { + case 9: + doSomething(); + continue; + + + case 10: + doNothing(); + throw new RuntimeException(); + + + case 11: + case 12: + doSomething(33); + //$FALL-THROUGH$ + case 13: + fallThrougAgain(); + case 14: + doSomething(switch (a * b * c * d) { + case 888: + aaa(); + break bbb(); + + + // comment + case 999: + aaa(); + break bbb(); + // comment + + + case 101010: + aaa(); + break bbb(); + + + // comment + case 111111: + aaa(); + break bbb(); + + // comment + + + case 121212: + aaa(); + break bbb(); + + // comment + + // comment + + + case 131313: + aaa(); + break bbb(); + + + // comment + // comment + default: + aaa(); + break bbb(); + }); + } + } + } +}
\ No newline at end of file diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test390720/B_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test390720/B_out.java new file mode 100644 index 0000000000..b428dfcccd --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test390720/B_out.java @@ -0,0 +1,101 @@ +package test; + +public class MyTest { + + void f(int a, int b) { + switch (a) { + case 1: + doSomething(); + break; + case 2: + case 3: + doSomeOtherThing(); + break; + case 4: { + // break missing, oh well... + } + case 5: { + doSomething(55); + break; + } + default: + doNothing(); + break; + } + + int c = switch (b) { + case 444: + break a + b; + case 555: + case 666: + doSoemthing(); + break 777; + default: + doSomeOtherSomething(); + return; + + }; + + int d = switch (c) { + case 1 -> 6; + case 2 -> { + int f = a + b; + break f * f; + } + default -> 55; + }; + + while (true) { + switch (a + b + c + d) { + case 9: + doSomething(); + continue; + case 10: + doNothing(); + throw new RuntimeException(); + case 11: + case 12: + doSomething(33); + //$FALL-THROUGH$ + case 13: + fallThrougAgain(); + case 14: + doSomething(switch (a * b * c * d) { + case 888: + aaa(); + break bbb(); + // comment + case 999: + aaa(); + break bbb(); + // comment + case 101010: + aaa(); + break bbb(); + + // comment + case 111111: + aaa(); + break bbb(); + + // comment + case 121212: + aaa(); + break bbb(); + + // comment + + // comment + case 131313: + aaa(); + break bbb(); + // comment + // comment + default: + aaa(); + break bbb(); + }); + } + } + } +}
\ No newline at end of file diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test390720/in.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test390720/in.java new file mode 100644 index 0000000000..6072466362 --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test390720/in.java @@ -0,0 +1,107 @@ +package test; + +public class MyTest { + + void f(int a, int b) { + switch (a) { + case 1: + doSomething(); + break; + + case 2: + case 3: + doSomeOtherThing(); + break; + case 4: { + // break missing, oh well... + } + + case 5: { + doSomething(55); + break; + } + default: + doNothing(); + break; + } + + int c = switch (b) { + case 444: + break a + b; + + case 555: + case 666: + doSoemthing(); + break 777; + default: + doSomeOtherSomething(); + return; + + }; + + int d = switch (c) { + case 1 -> 6; + case 2 -> { + int f = a + b; + break f * f; + } + default -> 55; + }; + + while (true) { + switch (a + b + c + d) { + case 9: + doSomething(); + continue; + case 10: + doNothing(); + throw new RuntimeException(); + case 11: + case 12: + doSomething(33); + //$FALL-THROUGH$ + case 13: + fallThrougAgain(); + case 14: + doSomething(switch (a * b * c * d) { + case 888: + aaa(); + break bbb(); + // comment + case 999: + aaa(); + break bbb(); + // comment + + case 101010: + aaa(); + break bbb(); + + // comment + case 111111: + aaa(); + break bbb(); + + // comment + + case 121212: + aaa(); + break bbb(); + + // comment + + // comment + + case 131313: + aaa(); + break bbb(); + // comment + // comment + default: + aaa(); + break bbb(); + }); + } + } + } +}
\ No newline at end of file diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java index 19b427e3d2..1481eac39f 100644 --- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java +++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java @@ -785,6 +785,18 @@ public class DefaultCodeFormatterConstants { public static final String FORMATTER_BLANK_LINES_BETWEEN_TYPE_DECLARATIONS = JavaCore.PLUGIN_ID + ".formatter.blank_lines_between_type_declarations"; //$NON-NLS-1$ /** * <pre> + * FORMATTER / Option to add or remove blank lines between statement groups in switch + * - option id: "org.eclipse.jdt.core.formatter.blank_lines_between_statement_groups_in_switch" + * - possible values: "<n>", where n is an integer. If n is negative, the actual number of + * blank lines is ~n and any excess blank lines are deleted, overriding the + * {@link #FORMATTER_NUMBER_OF_EMPTY_LINES_TO_PRESERVE} option + * - default: "0" + * </pre> + * @since 3.19 + */ + public static final String FORMATTER_BLANK_LINES_BETWEEN_STATEMENT_GROUPS_IN_SWITCH = JavaCore.PLUGIN_ID + ".formatter.blank_lines_between_statement_group_in_switch"; //$NON-NLS-1$ + /** + * <pre> * FORMATTER / Option to position the braces of an annotation type declaration * - option id: "org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" * - possible values: { END_OF_LINE, NEXT_LINE, NEXT_LINE_SHIFTED, NEXT_LINE_ON_WRAP } diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java index 9496be12b9..85d047ec6e 100644 --- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java +++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java @@ -443,8 +443,7 @@ public class CommentsPreparator extends ASTVisitor { } if (existingBreaksBefore < existingBreaksAfter && previous != null) { - if (previous.isPreserveLineBreaksAfter() || existingBreaksAfter < 2 || next == null - || (next.tokenType != TokenNameCOMMENT_LINE && next.tokenType != TokenNameCOMMENT_BLOCK)) { + if (previous.isPreserveLineBreaksAfter() || previous.getLineBreaksAfter() >= 2 || existingBreaksAfter < 2) { commentToken.putLineBreaksAfter(previous.getLineBreaksAfter()); commentToken.setPreserveLineBreaksAfter(previous.isPreserveLineBreaksAfter()); previous.clearLineBreaksAfter(); @@ -452,8 +451,7 @@ public class CommentsPreparator extends ASTVisitor { } } else if (existingBreaksAfter < 2 && existingBreaksAfter <= existingBreaksBefore && next != null && next.tokenType != TokenNamepackage /* doesn't apply to a comment before the package declaration */) { - if (next.isPreserveLineBreaksBefore() || existingBreaksBefore < 2 || previous == null - || (previous.tokenType != TokenNameCOMMENT_LINE && previous.tokenType != TokenNameCOMMENT_BLOCK)) { + if (next.isPreserveLineBreaksBefore() || next.getLineBreaksBefore() >= 2 || existingBreaksBefore < 2) { commentToken.putLineBreaksBefore(next.getLineBreaksBefore()); commentToken.setPreserveLineBreaksBefore(next.isPreserveLineBreaksBefore()); next.clearLineBreaksBefore(); diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java index 84de5d1407..2139264563 100644 --- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java +++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java @@ -208,6 +208,7 @@ public class DefaultCodeFormatterOptions { public int blank_lines_at_end_of_code_block; public int blank_lines_before_code_block; public int blank_lines_after_code_block; + public int blank_lines_between_statement_groups_in_switch; public boolean comment_clear_blank_lines_in_javadoc_comment; public boolean comment_clear_blank_lines_in_block_comment; @@ -621,6 +622,7 @@ public class DefaultCodeFormatterOptions { options.put(DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_AT_END_OF_CODE_BLOCK, Integer.toString(this.blank_lines_at_end_of_code_block)); options.put(DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_BEFORE_CODE_BLOCK, Integer.toString(this.blank_lines_before_code_block)); options.put(DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_AFTER_CODE_BLOCK, Integer.toString(this.blank_lines_after_code_block)); + options.put(DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_BETWEEN_STATEMENT_GROUPS_IN_SWITCH, Integer.toString(this.blank_lines_between_statement_groups_in_switch)); options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_STATEMENTS_COMPARE_TO_BLOCK, this.indent_statements_compare_to_block ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE); options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_STATEMENTS_COMPARE_TO_BODY, this.indent_statements_compare_to_body ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE); options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_ANNOTATION_DECLARATION_HEADER, this.indent_body_declarations_compare_to_annotation_declaration_header ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE); @@ -1397,6 +1399,8 @@ public class DefaultCodeFormatterOptions { v -> this.blank_lines_before_code_block = v); setInt(settings, DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_AFTER_CODE_BLOCK, v -> this.blank_lines_after_code_block = v); + setInt(settings, DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_BETWEEN_STATEMENT_GROUPS_IN_SWITCH, + v -> this.blank_lines_between_statement_groups_in_switch = v); final Object insertNewLineAfterTypeAnnotationOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_TYPE_ANNOTATION); if (insertNewLineAfterTypeAnnotationOption != null) { this.insert_new_line_after_type_annotation = JavaCore.INSERT.equals(insertNewLineAfterTypeAnnotationOption); @@ -2843,6 +2847,7 @@ public class DefaultCodeFormatterOptions { this.blank_lines_at_end_of_code_block = 0; this.blank_lines_before_code_block = 0; this.blank_lines_after_code_block = 0; + this.blank_lines_between_statement_groups_in_switch = 0; this.indent_statements_compare_to_block = true; this.indent_statements_compare_to_body = true; this.indent_body_declarations_compare_to_annotation_declaration_header = true; @@ -3205,6 +3210,7 @@ public class DefaultCodeFormatterOptions { this.blank_lines_at_end_of_code_block = 0; this.blank_lines_before_code_block = 0; this.blank_lines_after_code_block = 0; + this.blank_lines_between_statement_groups_in_switch = 0; this.indent_statements_compare_to_block = true; this.indent_statements_compare_to_body = true; this.indent_body_declarations_compare_to_annotation_declaration_header = true; diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java index 2f6574fc96..231cf3a86f 100644 --- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java +++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java @@ -68,6 +68,7 @@ import org.eclipse.jdt.core.dom.Statement; import org.eclipse.jdt.core.dom.SwitchCase; import org.eclipse.jdt.core.dom.SwitchExpression; import org.eclipse.jdt.core.dom.SwitchStatement; +import org.eclipse.jdt.core.dom.ThrowStatement; import org.eclipse.jdt.core.dom.TryStatement; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; @@ -357,47 +358,8 @@ public class LineBreaksPreparator extends ASTVisitor { this.options.indent_switchstatements_compare_to_switch); List<Statement> statements = node.statements(); - if (this.options.indent_switchstatements_compare_to_cases) { - int nonBreakStatementEnd = -1; - for (Statement statement : statements) { - boolean isBreaking = statement instanceof BreakStatement || statement instanceof ReturnStatement - || statement instanceof ContinueStatement || statement instanceof Block; - if (isBreaking && !(statement instanceof Block)) - adjustEmptyLineAfter(this.tm.lastIndexIn(statement, -1), -1); - if (statement instanceof SwitchCase) { - if (nonBreakStatementEnd >= 0) { - // indent only comments between previous and current statement - this.tm.get(nonBreakStatementEnd + 1).indent(); - this.tm.firstTokenIn(statement, -1).unindent(); - } - } else if (!(statement instanceof BreakStatement || statement instanceof Block)) { - indent(statement); - } - nonBreakStatementEnd = isBreaking ? -1 : this.tm.lastIndexIn(statement, -1); - } - if (nonBreakStatementEnd >= 0) { - // indent comments between last statement and closing brace - this.tm.get(nonBreakStatementEnd + 1).indent(); - this.tm.lastTokenIn(node, TokenNameRBRACE).unindent(); - } - } - if (this.options.indent_breaks_compare_to_cases) { - for (Statement statement : statements) { - if (statement instanceof BreakStatement) - indent(statement); - } - } - - boolean arrowMode = statements.stream() - .anyMatch(s -> s instanceof SwitchCase && ((SwitchCase) s).isSwitchLabeledRule()); - for (Statement statement : statements) { - if (statement instanceof Block) - continue; // will add break in visit(Block) if necessary - if (arrowMode && !(statement instanceof SwitchCase)) - continue; - if (this.options.put_empty_statement_on_new_line || !(statement instanceof EmptyStatement)) - breakLineBefore(statement); - } + doSwitchStatementsIndentation(node, statements); + doSwitchStatementsLineBreaks(statements); putBlankLinesAfter(this.tm.firstTokenAfter(node.getExpression(), TokenNameLBRACE), this.options.blank_lines_at_beginning_of_code_block); @@ -414,11 +376,21 @@ public class LineBreaksPreparator extends ASTVisitor { this.options.indent_switchstatements_compare_to_switch); List<Statement> statements = node.statements(); + doSwitchStatementsIndentation(node, statements); + doSwitchStatementsLineBreaks(statements); + + putBlankLinesAfter(this.tm.firstTokenAfter(node.getExpression(), TokenNameLBRACE), + this.options.blank_lines_at_beginning_of_code_block); + putBlankLinesBeforeCloseBrace(node, this.options.blank_lines_at_end_of_code_block); + + return true; + } + + private void doSwitchStatementsIndentation(ASTNode switchNode, List<Statement> statements) { if (this.options.indent_switchstatements_compare_to_cases) { int nonBreakStatementEnd = -1; for (Statement statement : statements) { - boolean isBreaking = statement instanceof BreakStatement || statement instanceof ReturnStatement - || statement instanceof ContinueStatement || statement instanceof Block; + boolean isBreaking = isSwitchBreakingStatement(statement); if (isBreaking && !(statement instanceof Block)) adjustEmptyLineAfter(this.tm.lastIndexIn(statement, -1), -1); if (statement instanceof SwitchCase) { @@ -433,9 +405,9 @@ public class LineBreaksPreparator extends ASTVisitor { nonBreakStatementEnd = isBreaking ? -1 : this.tm.lastIndexIn(statement, -1); } if (nonBreakStatementEnd >= 0) { - // indent comments between last statement and closing brace + // indent comments between last statement and closing brace this.tm.get(nonBreakStatementEnd + 1).indent(); - this.tm.lastTokenIn(node, TokenNameRBRACE).unindent(); + this.tm.lastTokenIn(switchNode, TokenNameRBRACE).unindent(); } } if (this.options.indent_breaks_compare_to_cases) { @@ -444,23 +416,29 @@ public class LineBreaksPreparator extends ASTVisitor { indent(statement); } } + } + private void doSwitchStatementsLineBreaks(List<Statement> statements) { boolean arrowMode = statements.stream() .anyMatch(s -> s instanceof SwitchCase && ((SwitchCase) s).isSwitchLabeledRule()); + Statement previous = null; for (Statement statement : statements) { - if (statement instanceof Block) - continue; // will add break in visit(Block) if necessary - if (arrowMode && !(statement instanceof SwitchCase)) - continue; - if (this.options.put_empty_statement_on_new_line || !(statement instanceof EmptyStatement)) - breakLineBefore(statement); + boolean skip = statement instanceof Block // will add break in visit(Block) if necessary + || (arrowMode && !(statement instanceof SwitchCase)) + || (statement instanceof EmptyStatement && !this.options.put_empty_statement_on_new_line); + if (!skip) { + boolean newGroup = !arrowMode && statement instanceof SwitchCase && isSwitchBreakingStatement(previous); + int blankLines = newGroup ? this.options.blank_lines_between_statement_groups_in_switch : 0; + putBlankLinesBefore(statement, blankLines); + } + previous = statement; } + } - putBlankLinesAfter(this.tm.firstTokenAfter(node.getExpression(), TokenNameLBRACE), - this.options.blank_lines_at_beginning_of_code_block); - putBlankLinesBeforeCloseBrace(node, this.options.blank_lines_at_end_of_code_block); - - return true; + private boolean isSwitchBreakingStatement(Statement statement) { + return statement instanceof BreakStatement || statement instanceof ReturnStatement + || statement instanceof ContinueStatement || statement instanceof ThrowStatement + || statement instanceof Block; } @Override |