Bug 131292 - [format] align assignments in columns
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 7640b4b..4784d9b 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
@@ -14309,4 +14309,64 @@
String input = getCompilationUnit("Formatter", "", "test530756", "in.java").getSource();
formatSource(input, getCompilationUnit("Formatter", "", "test530756", "E_out.java").getSource());
}
+
+/**
+ * https://bugs.eclipse.org/131292 - [format] align assignments in columns
+ */
+public void testBug131292a() throws JavaModelException {
+ this.formatterPrefs.align_type_members_on_columns = true;
+ String input = getCompilationUnit("Formatter", "", "test131292", "in.java").getSource();
+ formatSource(input, getCompilationUnit("Formatter", "", "test131292", "A_out.java").getSource());
+}
+/**
+ * https://bugs.eclipse.org/131292 - [format] align assignments in columns
+ */
+public void testBug131292b() throws JavaModelException {
+ this.formatterPrefs.align_variable_declarations_on_columns = true;
+ String input = getCompilationUnit("Formatter", "", "test131292", "in.java").getSource();
+ formatSource(input, getCompilationUnit("Formatter", "", "test131292", "B_out.java").getSource());
+}
+/**
+ * https://bugs.eclipse.org/131292 - [format] align assignments in columns
+ */
+public void testBug131292c() throws JavaModelException {
+ this.formatterPrefs.align_assignment_statements_on_columns = true;
+ String input = getCompilationUnit("Formatter", "", "test131292", "in.java").getSource();
+ formatSource(input, getCompilationUnit("Formatter", "", "test131292", "C_out.java").getSource());
+}
+/**
+ * https://bugs.eclipse.org/131292 - [format] align assignments in columns
+ */
+public void testBug131292d() throws JavaModelException {
+ this.formatterPrefs.align_type_members_on_columns = true;
+ this.formatterPrefs.align_variable_declarations_on_columns = true;
+ this.formatterPrefs.align_assignment_statements_on_columns = true;
+ this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.SPACE;
+ String input = getCompilationUnit("Formatter", "", "test131292", "in.java").getSource();
+ formatSource(input, getCompilationUnit("Formatter", "", "test131292", "D_out.java").getSource());
+}
+/**
+ * https://bugs.eclipse.org/131292 - [format] align assignments in columns
+ */
+public void testBug131292e() throws JavaModelException {
+ this.formatterPrefs.align_type_members_on_columns = true;
+ this.formatterPrefs.align_variable_declarations_on_columns = true;
+ this.formatterPrefs.align_assignment_statements_on_columns = true;
+ this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.MIXED;
+ this.formatterPrefs.align_fields_grouping_blank_lines = 1;
+ String input = getCompilationUnit("Formatter", "", "test131292", "in.java").getSource();
+ formatSource(input, getCompilationUnit("Formatter", "", "test131292", "E_out.java").getSource());
+}
+/**
+ * https://bugs.eclipse.org/131292 - [format] align assignments in columns
+ */
+public void testBug131292f() throws JavaModelException {
+ this.formatterPrefs.align_type_members_on_columns = true;
+ this.formatterPrefs.align_variable_declarations_on_columns = true;
+ this.formatterPrefs.align_assignment_statements_on_columns = true;
+ this.formatterPrefs.align_with_spaces = true;
+ this.formatterPrefs.align_fields_grouping_blank_lines = 2;
+ String input = getCompilationUnit("Formatter", "", "test131292", "in.java").getSource();
+ formatSource(input, getCompilationUnit("Formatter", "", "test131292", "F_out.java").getSource());
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/A_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/A_out.java
new file mode 100644
index 0000000..ff98217
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/A_out.java
@@ -0,0 +1,177 @@
+class Example {
+
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ private String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ private final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ void variables() {
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesReordered() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ a b;
+ }
+
+ void variablesGaps() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ // big gap
+
+ int i;
+ a b;
+ }
+
+ void variablesComments() {
+ a /* c1 */ b; // c1
+ a /* c123 */ b /* c123 */ = /* c123 */ c; // c123
+ int /* */ i; /* */
+ int j = 5; /* */
+ String /* c */ someLongString /* c */ = /* c */ "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890" + "12345678901234567890";
+ /* ... */ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesAnnotations() {
+ @SuppressWarnings
+ a b = c;
+ @Target
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ @Deprecated
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ @Test
+ a b;
+ }
+
+ void assignments() {
+ b = c;
+ j = 5;
+ myInteger = 56436345;
+ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void assignmentsReordered() {
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ b = c;
+ myInteger = 56436345;
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+ }
+
+ void assignmentsGaps() {
+ b = c;
+ myInteger = 56436345;
+
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+
+ // big gap
+
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ }
+
+ void assignmentsComments() {
+ /* c1 */ b /* c1 */ = /* c1 */c;// c1
+ j /* */ = /* c12345 */5; // c12345
+ myInteger /* */ = 56436345;
+ /* */ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890"; /* ... */
+ someObjetc = /* !!! */ new Object() { // !!!
+ @Override
+ public String toString() {
+ return super.toString(); // !!!
+ }
+ };
+ }
+
+ void mixed() {
+ a b;
+ a b = c;
+ int i;
+ j = 5;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/B_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/B_out.java
new file mode 100644
index 0000000..cc1c279
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/B_out.java
@@ -0,0 +1,177 @@
+class Example {
+
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ private String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ private final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ void variables() {
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesReordered() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ a b;
+ }
+
+ void variablesGaps() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ // big gap
+
+ int i;
+ a b;
+ }
+
+ void variablesComments() {
+ a /* c1 */ b; // c1
+ a /* c123 */ b /* c123 */ = /* c123 */ c; // c123
+ int /* */ i; /* */
+ int j = 5; /* */
+ String /* c */ someLongString /* c */ = /* c */ "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890" + "12345678901234567890";
+ /* ... */ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesAnnotations() {
+ @SuppressWarnings
+ a b = c;
+ @Target
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ @Deprecated
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ @Test
+ a b;
+ }
+
+ void assignments() {
+ b = c;
+ j = 5;
+ myInteger = 56436345;
+ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void assignmentsReordered() {
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ b = c;
+ myInteger = 56436345;
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+ }
+
+ void assignmentsGaps() {
+ b = c;
+ myInteger = 56436345;
+
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+
+ // big gap
+
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ }
+
+ void assignmentsComments() {
+ /* c1 */ b /* c1 */ = /* c1 */c;// c1
+ j /* */ = /* c12345 */5; // c12345
+ myInteger /* */ = 56436345;
+ /* */ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890"; /* ... */
+ someObjetc = /* !!! */ new Object() { // !!!
+ @Override
+ public String toString() {
+ return super.toString(); // !!!
+ }
+ };
+ }
+
+ void mixed() {
+ a b;
+ a b = c;
+ int i;
+ j = 5;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/C_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/C_out.java
new file mode 100644
index 0000000..a84c6d0
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/C_out.java
@@ -0,0 +1,177 @@
+class Example {
+
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ private String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ private final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ void variables() {
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesReordered() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ a b;
+ }
+
+ void variablesGaps() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ // big gap
+
+ int i;
+ a b;
+ }
+
+ void variablesComments() {
+ a /* c1 */ b; // c1
+ a /* c123 */ b /* c123 */ = /* c123 */ c; // c123
+ int /* */ i; /* */
+ int j = 5; /* */
+ String /* c */ someLongString /* c */ = /* c */ "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890" + "12345678901234567890";
+ /* ... */ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesAnnotations() {
+ @SuppressWarnings
+ a b = c;
+ @Target
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ @Deprecated
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ @Test
+ a b;
+ }
+
+ void assignments() {
+ b = c;
+ j = 5;
+ myInteger = 56436345;
+ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void assignmentsReordered() {
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ b = c;
+ myInteger = 56436345;
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+ }
+
+ void assignmentsGaps() {
+ b = c;
+ myInteger = 56436345;
+
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+
+ // big gap
+
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ }
+
+ void assignmentsComments() {
+ /* c1 */ b /* c1 */ = /* c1 */c; // c1
+ j /* */ = /* c12345 */5; // c12345
+ myInteger /* */ = 56436345;
+ /* */ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890"; /* ... */
+ someObjetc = /* !!! */ new Object() { // !!!
+ @Override
+ public String toString() {
+ return super.toString(); // !!!
+ }
+ };
+ }
+
+ void mixed() {
+ a b;
+ a b = c;
+ int i;
+ j = 5;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/D_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/D_out.java
new file mode 100644
index 0000000..7358615
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/D_out.java
@@ -0,0 +1,177 @@
+class Example {
+
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ private String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ private final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ void variables() {
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesReordered() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ a b;
+ }
+
+ void variablesGaps() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ // big gap
+
+ int i;
+ a b;
+ }
+
+ void variablesComments() {
+ a /* c1 */ b; // c1
+ a /* c123 */ b /* c123 */ = /* c123 */ c; // c123
+ int /* */ i; /* */
+ int j = 5; /* */
+ String /* c */ someLongString /* c */ = /* c */ "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890" + "12345678901234567890";
+ /* ... */ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesAnnotations() {
+ @SuppressWarnings
+ a b = c;
+ @Target
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ @Deprecated
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ @Test
+ a b;
+ }
+
+ void assignments() {
+ b = c;
+ j = 5;
+ myInteger = 56436345;
+ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void assignmentsReordered() {
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ b = c;
+ myInteger = 56436345;
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+ }
+
+ void assignmentsGaps() {
+ b = c;
+ myInteger = 56436345;
+
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+
+ // big gap
+
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ }
+
+ void assignmentsComments() {
+ /* c1 */ b /* c1 */ = /* c1 */c; // c1
+ j /* */ = /* c12345 */5; // c12345
+ myInteger /* */ = 56436345;
+ /* */ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890"; /* ... */
+ someObjetc = /* !!! */ new Object() { // !!!
+ @Override
+ public String toString() {
+ return super.toString(); // !!!
+ }
+ };
+ }
+
+ void mixed() {
+ a b;
+ a b = c;
+ int i;
+ j = 5;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/E_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/E_out.java
new file mode 100644
index 0000000..29b1900
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/E_out.java
@@ -0,0 +1,177 @@
+class Example {
+
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ private String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ private final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ void variables() {
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesReordered() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ a b;
+ }
+
+ void variablesGaps() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ // big gap
+
+ int i;
+ a b;
+ }
+
+ void variablesComments() {
+ a /* c1 */ b; // c1
+ a /* c123 */ b /* c123 */ = /* c123 */ c; // c123
+ int /* */ i; /* */
+ int j = 5; /* */
+ String /* c */ someLongString /* c */ = /* c */ "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890" + "12345678901234567890";
+ /* ... */ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesAnnotations() {
+ @SuppressWarnings
+ a b = c;
+ @Target
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ @Deprecated
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ @Test
+ a b;
+ }
+
+ void assignments() {
+ b = c;
+ j = 5;
+ myInteger = 56436345;
+ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void assignmentsReordered() {
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ b = c;
+ myInteger = 56436345;
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+ }
+
+ void assignmentsGaps() {
+ b = c;
+ myInteger = 56436345;
+
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+
+ // big gap
+
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ }
+
+ void assignmentsComments() {
+ /* c1 */ b /* c1 */ = /* c1 */c; // c1
+ j /* */ = /* c12345 */5; // c12345
+ myInteger /* */ = 56436345;
+ /* */ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890"; /* ... */
+ someObjetc = /* !!! */ new Object() { // !!!
+ @Override
+ public String toString() {
+ return super.toString(); // !!!
+ }
+ };
+ }
+
+ void mixed() {
+ a b;
+ a b = c;
+ int i;
+ j = 5;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/F_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/F_out.java
new file mode 100644
index 0000000..8f70457
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/F_out.java
@@ -0,0 +1,177 @@
+class Example {
+
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ private String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ private final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ void variables() {
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesReordered() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ a b;
+ }
+
+ void variablesGaps() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ // big gap
+
+ int i;
+ a b;
+ }
+
+ void variablesComments() {
+ a /* c1 */ b; // c1
+ a /* c123 */ b /* c123 */ = /* c123 */ c; // c123
+ int /* */ i; /* */
+ int j = 5; /* */
+ String /* c */ someLongString /* c */ = /* c */ "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890" + "12345678901234567890";
+ /* ... */ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesAnnotations() {
+ @SuppressWarnings
+ a b = c;
+ @Target
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ int j = 5;
+ @Deprecated
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ @Test
+ a b;
+ }
+
+ void assignments() {
+ b = c;
+ j = 5;
+ myInteger = 56436345;
+ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void assignmentsReordered() {
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ b = c;
+ myInteger = 56436345;
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+ }
+
+ void assignmentsGaps() {
+ b = c;
+ myInteger = 56436345;
+
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+
+ // big gap
+
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ }
+
+ void assignmentsComments() {
+ /* c1 */ b /* c1 */ = /* c1 */c; // c1
+ j /* */ = /* c12345 */5; // c12345
+ myInteger /* */ = 56436345;
+ /* */ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890"; /* ... */
+ someObjetc = /* !!! */ new Object() { // !!!
+ @Override
+ public String toString() {
+ return super.toString(); // !!!
+ }
+ };
+ }
+
+ void mixed() {
+ a b;
+ a b = c;
+ int i;
+ j = 5;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/in.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/in.java
new file mode 100644
index 0000000..58f3b88
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test131292/in.java
@@ -0,0 +1,166 @@
+class Example {
+
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ private String someLongString = "12345678901234567890"
+ + "12345678901234567890" + "12345678901234567890"
+ + "12345678901234567890";
+ private final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ void variables() {
+ a b;
+ a b = c;
+ int i;
+ int j = 5;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890" + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesReordered() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890" + "12345678901234567890";
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ a b;
+ }
+
+ void variablesGaps() {
+ a b = c;
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890" + "12345678901234567890";
+
+ int j = 5;
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+
+ // big gap
+
+ int i;
+ a b;
+ }
+
+ void variablesComments() {
+ a /* c1 */ b; // c1
+ a /* c123 */b /* c123 */ = /* c123 */ c; // c123
+ int /* */i; /* */
+ int j = 5; /* */
+ String /* c */ someLongString /* c */ = /* c */ "12345678901234567890" + "12345678901234567890" + "12345678901234567890" + "12345678901234567890";
+ /* ... */ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void variablesAnnotations() {
+ @SuppressWarnings
+ a b = c;
+ @Target
+ String someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890" + "12345678901234567890";
+ int j = 5;
+ @Deprecated
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ int i;
+ @Test
+ a b;
+ }
+
+ void assignments() {
+ b = c;
+ j = 5;
+ myInteger = 56436345;
+ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890" + "12345678901234567890";
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+
+ void assignmentsReordered() {
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890" + "12345678901234567890";
+ b = c;
+ myInteger = 56436345;
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+ }
+ void assignmentsGaps() {
+ b = c;
+ myInteger = 56436345;
+
+ myOtehrInteger >>= 35534525543;
+ j = 5;
+
+ // big gap
+
+ someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890" + "12345678901234567890";
+ }
+ void assignmentsComments() {
+ /* c1 */ b /* c1 */= /* c1 */c;// c1
+ j /* */= /* c12345 */5; // c12345
+ myInteger /* */ = 56436345;
+ /* */ myOtehrInteger >>= 35534525543;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890" + "12345678901234567890"; /* ... */
+ someObjetc = /* !!! */ new Object() { // !!!
+ @Override
+ public String toString() {
+ return super.toString(); // !!!
+ }
+ };
+ }
+
+ void mixed() {
+ a b;
+ a b = c;
+ int i;
+ j = 5;
+ someLongString = "12345678901234567890" + "12345678901234567890" + "12345678901234567890" + "12345678901234567890";
+ final Object someObjetc = new Object() {
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ };
+ }
+}
\ 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 1bf0cd4..92f38d6 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
@@ -70,6 +70,32 @@
/**
* <pre>
+ * FORMATTER / Option to align variable declarations on column
+ * - option id: "org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns"
+ * - possible values: { TRUE, FALSE }
+ * - default: FALSE
+ * </pre>
+ * @see #TRUE
+ * @see #FALSE
+ * @since 3.15
+ */
+ public static final String FORMATTER_ALIGN_VARIABLE_DECLARATIONS_ON_COLUMNS = JavaCore.PLUGIN_ID + ".formatter.align_variable_declarations_on_columns"; //$NON-NLS-1$
+
+ /**
+ * <pre>
+ * FORMATTER / Option to align assignment statements on column
+ * - option id: "org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns"
+ * - possible values: { TRUE, FALSE }
+ * - default: FALSE
+ * </pre>
+ * @see #TRUE
+ * @see #FALSE
+ * @since 3.15
+ */
+ public static final String FORMATTER_ALIGN_ASSIGNMENT_STATEMENTS_ON_COLUMNS = JavaCore.PLUGIN_ID + ".formatter.align_assignment_statements_on_columns"; //$NON-NLS-1$
+
+ /**
+ * <pre>
* FORMATTER / Option to use spaces when aligning members, independent of selected tabulation character
* - option id: "org.eclipse.jdt.core.formatter.align_with_spaces"
* - possible values: { TRUE, FALSE }
@@ -83,7 +109,10 @@
/**
* <pre>
- * FORMATTER / Option to align groups of members independently if they are separated by a certain number of blank lines
+ * FORMATTER / Option to affect aligning on columns: groups of items are aligned independently
+ * if they are separated by at least the selected number of blank lines.
+ * Note: since 3.15 the 'fields' part is a (potentially misleading) residue as this option
+ * affects other types of aligning on columns as well.
* - option id: "org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines"
* - possible values: "<n>", where n is a positive integer
* - default: {@code Integer.MAX_VALUE}
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 5f416ea..92f65e9 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
@@ -143,6 +143,8 @@
public int alignment_for_union_type_in_multicatch;
public boolean align_type_members_on_columns;
+ public boolean align_variable_declarations_on_columns;
+ public boolean align_assignment_statements_on_columns;
public boolean align_with_spaces;
public int align_fields_grouping_blank_lines;
@@ -485,6 +487,8 @@
options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_TYPE_PARAMETERS, getAlignment(this.alignment_for_type_parameters));
options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_UNION_TYPE_IN_MULTICATCH, getAlignment(this.alignment_for_union_type_in_multicatch));
options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_TYPE_MEMBERS_ON_COLUMNS, this.align_type_members_on_columns ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
+ options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_VARIABLE_DECLARATIONS_ON_COLUMNS, this.align_variable_declarations_on_columns ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
+ options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_ASSIGNMENT_STATEMENTS_ON_COLUMNS, this.align_assignment_statements_on_columns ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_FIELDS_GROUPING_BLANK_LINES, Integer.toString(this.align_fields_grouping_blank_lines));
options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_WITH_SPACES, this.align_with_spaces ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_ANNOTATION_TYPE_DECLARATION, this.brace_position_for_annotation_type_declaration);
@@ -1047,6 +1051,14 @@
if (alignTypeMembersOnColumnsOption != null) {
this.align_type_members_on_columns = DefaultCodeFormatterConstants.TRUE.equals(alignTypeMembersOnColumnsOption);
}
+ final Object alignVariableDeclarationsOnColumnsOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGN_VARIABLE_DECLARATIONS_ON_COLUMNS);
+ if (alignVariableDeclarationsOnColumnsOption != null) {
+ this.align_variable_declarations_on_columns = DefaultCodeFormatterConstants.TRUE.equals(alignVariableDeclarationsOnColumnsOption);
+ }
+ final Object alignAssignmentStatementsOnColumnsOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGN_ASSIGNMENT_STATEMENTS_ON_COLUMNS);
+ if (alignAssignmentStatementsOnColumnsOption != null) {
+ this.align_assignment_statements_on_columns = DefaultCodeFormatterConstants.TRUE.equals(alignAssignmentStatementsOnColumnsOption);
+ }
final Object alignGroupSepartionBlankLinesOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGN_FIELDS_GROUPING_BLANK_LINES);
if (alignTypeMembersOnColumnsOption != null) {
try {
@@ -2495,6 +2507,8 @@
this.alignment_for_type_parameters = Alignment.M_NO_ALIGNMENT;
this.alignment_for_union_type_in_multicatch = Alignment.M_COMPACT_SPLIT;
this.align_type_members_on_columns = false;
+ this.align_variable_declarations_on_columns = false;
+ this.align_assignment_statements_on_columns = false;
this.align_with_spaces = false;
this.align_fields_grouping_blank_lines = Integer.MAX_VALUE;
this.brace_position_for_annotation_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
@@ -2813,6 +2827,8 @@
this.alignment_for_type_parameters = Alignment.M_NO_ALIGNMENT;
this.alignment_for_union_type_in_multicatch = Alignment.M_COMPACT_SPLIT;
this.align_type_members_on_columns = false;
+ this.align_variable_declarations_on_columns = false;
+ this.align_assignment_statements_on_columns = false;
this.align_with_spaces = false;
this.align_fields_grouping_blank_lines = Integer.MAX_VALUE;
this.brace_position_for_annotation_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/Aligner.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/Aligner.java
new file mode 100644
index 0000000..47d3357
--- /dev/null
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/Aligner.java
@@ -0,0 +1,281 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2018 Mateusz Matela and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mateusz Matela <mateusz.matela@gmail.com> - [formatter] Formatter does not format Java code correctly, especially when max line width is set - https://bugs.eclipse.org/303519
+ * Lars Vogel <Lars.Vogel@vogella.com> - Contributions for
+ * Bug 473178
+ *******************************************************************************/
+package org.eclipse.jdt.internal.formatter.linewrap;
+
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_BLOCK;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_LINE;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameEQUAL;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameIdentifier;
+import static java.util.stream.Collectors.toList;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.OptionalInt;
+import java.util.function.Function;
+import java.util.stream.IntStream;
+
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.Assignment;
+import org.eclipse.jdt.core.dom.Block;
+import org.eclipse.jdt.core.dom.BodyDeclaration;
+import org.eclipse.jdt.core.dom.ExpressionStatement;
+import org.eclipse.jdt.core.dom.FieldDeclaration;
+import org.eclipse.jdt.core.dom.Statement;
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
+import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
+import org.eclipse.jdt.internal.formatter.Token;
+import org.eclipse.jdt.internal.formatter.TokenManager;
+import org.eclipse.jdt.internal.formatter.TokenTraverser;
+
+/** Implementation of the "Align items on columns" feature */
+public class Aligner {
+ private class PositionCounter extends TokenTraverser {
+ int stoppingIndex;
+ int maxPosition;
+
+ public PositionCounter() {
+ // nothing to do
+ }
+
+ @Override
+ protected boolean token(Token token, int index) {
+ if (index == this.stoppingIndex)
+ return false;
+ if (getLineBreaksBefore() > 0)
+ this.counter = Aligner.this.tm.getPositionInLine(index);
+ if (token.getAlign() > 0)
+ this.counter = token.getAlign();
+ this.counter += Aligner.this.tm.getLength(token, this.counter);
+ if (isSpaceAfter() && getLineBreaksAfter() == 0)
+ this.counter++;
+ this.maxPosition = Math.max(this.maxPosition, this.counter);
+ return true;
+ }
+
+ public int findMaxPosition(int fromIndex, int toIndex) {
+ this.counter = Aligner.this.tm.getPositionInLine(fromIndex);
+ this.stoppingIndex = toIndex;
+ this.maxPosition = 0;
+ Aligner.this.tm.traverse(fromIndex, this);
+ return this.maxPosition;
+ }
+ }
+
+ @FunctionalInterface
+ private interface AlignIndexFinder<N extends ASTNode> {
+ Optional<Integer> findIndex(N node);
+ }
+
+ private final List<List<? extends ASTNode>> alignGroups = new ArrayList<>();
+
+ private final DefaultCodeFormatterOptions options;
+
+ final TokenManager tm;
+
+ public Aligner(TokenManager tokenManager, DefaultCodeFormatterOptions options) {
+ this.tm = tokenManager;
+ this.options = options;
+ }
+
+ public void handleAlign(List<BodyDeclaration> bodyDeclarations) {
+ if (!this.options.align_type_members_on_columns)
+ return;
+ List<List<FieldDeclaration>> fieldGroups = toAlignGroups(bodyDeclarations,
+ n -> optionalCast(n, FieldDeclaration.class));
+ this.alignGroups.addAll(fieldGroups);
+
+ AlignIndexFinder<FieldDeclaration> nameFinder = fd -> findName(
+ (VariableDeclarationFragment) fd.fragments().get(0));
+ fieldGroups.forEach(fg -> alignNodes(fg, nameFinder));
+
+ AlignIndexFinder<FieldDeclaration> assignFinder = fd -> findAssign(
+ (VariableDeclarationFragment) fd.fragments().get(0));
+ fieldGroups.forEach(fg -> alignNodes(fg, assignFinder));
+ }
+
+ public void handleAlign(Block block) {
+ List<Statement> statements = block.statements();
+ if (this.options.align_variable_declarations_on_columns)
+ alignDeclarations(statements);
+ if (this.options.align_assignment_statements_on_columns)
+ alignAssignmentStatements(statements);
+ }
+
+ private void alignDeclarations(List<Statement> statements) {
+ List<List<VariableDeclarationStatement>> variableGroups = toAlignGroups(statements,
+ n -> optionalCast(n, VariableDeclarationStatement.class));
+ this.alignGroups.addAll(variableGroups);
+
+ AlignIndexFinder<VariableDeclarationStatement> nameFinder = vd -> findName(
+ (VariableDeclarationFragment) vd.fragments().get(0));
+ variableGroups.forEach(vg -> alignNodes(vg, nameFinder));
+
+ AlignIndexFinder<VariableDeclarationStatement> assignFinder = vd -> findAssign(
+ (VariableDeclarationFragment) vd.fragments().get(0));
+ variableGroups.forEach(vg -> alignNodes(vg, assignFinder));
+ }
+
+ private void alignAssignmentStatements(List<Statement> statements) {
+ List<List<ExpressionStatement>> assignmentGroups = toAlignGroups(statements,
+ n -> optionalCast(n, ExpressionStatement.class)
+ .filter(es -> es.getExpression() instanceof Assignment));
+ this.alignGroups.addAll(assignmentGroups);
+
+ AlignIndexFinder<ExpressionStatement> assignFinder = es -> {
+ Assignment a = (Assignment) es.getExpression();
+ int operatorIndex = this.tm.firstIndexBefore(a.getRightHandSide(), -1);
+ while (this.tm.get(operatorIndex).isComment())
+ operatorIndex--;
+ return Optional.of(operatorIndex);
+ };
+ assignmentGroups.forEach(ag -> alignNodes(ag, assignFinder));
+
+ if (this.options.align_with_spaces || this.options.tab_char != DefaultCodeFormatterOptions.TAB) {
+ // align assign operators on their right side (e.g. +=, >>=)
+ for (List<ExpressionStatement> group : assignmentGroups) {
+ List<Token> assignTokens = group.stream()
+ .map(assignFinder::findIndex)
+ .filter(Optional::isPresent)
+ .map(o -> this.tm.get(o.get()))
+ .collect(toList());
+ int maxWidth = assignTokens.stream().mapToInt(Token::countChars).max().orElse(0);
+ for (Token token : assignTokens)
+ token.setAlign(token.getAlign() + maxWidth - token.countChars());
+ }
+ }
+ }
+
+ private <N extends ASTNode> Optional<N> optionalCast(ASTNode node, Class<N> c) {
+ return Optional.of(node).filter(c::isInstance).map(c::cast);
+ }
+
+ private Optional<Integer> findName(VariableDeclarationFragment fragment) {
+ int nameIndex = this.tm.firstIndexIn(fragment.getName(), TokenNameIdentifier);
+ return Optional.of(nameIndex);
+ }
+
+ private Optional<Integer> findAssign(VariableDeclarationFragment fragment) {
+ return Optional.ofNullable(fragment.getInitializer())
+ .map(i -> this.tm.firstIndexBefore(i, TokenNameEQUAL));
+ }
+
+ private <N extends ASTNode> List<List<N>> toAlignGroups(List<? extends ASTNode> nodes,
+ Function<ASTNode, Optional<N>> nodeConverter) {
+ List<List<N>> result = new ArrayList<>();
+ List<N> alignGroup = new ArrayList<>();
+ N previous = null;
+ for (ASTNode node : nodes) {
+ Optional<N> converted = nodeConverter.apply(node);
+ if (converted.isPresent()) {
+ if (isNewGroup(node, previous)) {
+ result.add(alignGroup);
+ alignGroup = new ArrayList<>();
+ }
+ alignGroup.add(converted.get());
+ }
+ previous = converted.orElse(null);
+ }
+ result.add(alignGroup);
+ result.removeIf(l -> l.size() < 2);
+ return result;
+ }
+
+ private boolean isNewGroup(ASTNode node, ASTNode previousNode) {
+ if (previousNode == null)
+ return true;
+ int lineBreaks = 0;
+ int from = this.tm.lastIndexIn(previousNode, -1);
+ int to = this.tm.firstIndexIn(node, -1);
+ Token previousToken = this.tm.get(from);
+ for (int i = from + 1; i <= to; i++) {
+ Token token = this.tm.get(i);
+ lineBreaks += Math.min(this.tm.countLineBreaksBetween(previousToken, token),
+ this.options.number_of_empty_lines_to_preserve + 1);
+ previousToken = token;
+ }
+ return lineBreaks > this.options.align_fields_grouping_blank_lines;
+ }
+
+ private <N extends ASTNode> void alignNodes(List<N> alignGroup, AlignIndexFinder<N> tokenFinder) {
+ int[] tokenIndexes = alignGroup.stream()
+ .map(tokenFinder::findIndex)
+ .filter(Optional::isPresent)
+ .mapToInt(Optional::get).toArray();
+ OptionalInt maxPosition = IntStream.of(tokenIndexes).map(this.tm::getPositionInLine).max();
+ if (maxPosition.isPresent()) {
+ int align = normalizedAlign(maxPosition.getAsInt());
+ for (int tokenIndex : tokenIndexes)
+ this.tm.get(tokenIndex).setAlign(align);
+ }
+ }
+
+ public void alignComments() {
+ boolean alignLineComments = !this.options.comment_preserve_white_space_between_code_and_line_comments;
+ PositionCounter positionCounter = new PositionCounter();
+ // align comments after field declarations
+ for (List<? extends ASTNode> alignGroup : this.alignGroups) {
+ int maxCommentAlign = 0;
+ for (ASTNode node : alignGroup) {
+ int firstIndexInLine = findFirstTokenInLine(node);
+ int lastIndex = this.tm.lastIndexIn(node, -1) + 1;
+ maxCommentAlign = Math.max(maxCommentAlign,
+ positionCounter.findMaxPosition(firstIndexInLine, lastIndex));
+ }
+ maxCommentAlign = normalizedAlign(maxCommentAlign);
+
+ for (ASTNode node : alignGroup) {
+ int firstIndexInLine = findFirstTokenInLine(node);
+ int lastIndex = this.tm.lastIndexIn(node, -1);
+ lastIndex = Math.min(lastIndex, this.tm.size() - 2);
+ for (int i = firstIndexInLine; i <= lastIndex; i++) {
+ Token token = this.tm.get(i);
+ Token next = this.tm.get(i + 1);
+ boolean lineBreak = token.getLineBreaksAfter() > 0 || next.getLineBreaksBefore() > 0;
+ if (lineBreak) {
+ if (token.tokenType == TokenNameCOMMENT_BLOCK) {
+ token.setAlign(maxCommentAlign);
+ } else if (alignLineComments) {
+ this.tm.addNLSAlignIndex(i, maxCommentAlign);
+ }
+ } else if (next.tokenType == TokenNameCOMMENT_LINE && alignLineComments
+ || (next.tokenType == TokenNameCOMMENT_BLOCK && i == lastIndex)) {
+ next.setAlign(maxCommentAlign);
+ }
+ }
+ }
+ }
+ }
+
+ private int findFirstTokenInLine(ASTNode node) {
+ if (node instanceof FieldDeclaration) {
+ int typeIndex = this.tm.firstIndexIn(((FieldDeclaration) node).getType(), -1);
+ return this.tm.findFirstTokenInLine(typeIndex);
+ }
+ if (node instanceof VariableDeclarationStatement) {
+ int typeIndex = this.tm.firstIndexIn(((VariableDeclarationStatement) node).getType(), -1);
+ return this.tm.findFirstTokenInLine(typeIndex);
+ }
+ if (node instanceof ExpressionStatement) {
+ return this.tm.firstIndexIn(node, -1);
+ }
+ throw new IllegalArgumentException(node.getClass().getName());
+ }
+
+ private int normalizedAlign(int desiredAlign) {
+ if (this.options.align_with_spaces)
+ return desiredAlign;
+ return this.tm.toIndent(desiredAlign, false);
+ }
+}
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/FieldAligner.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/FieldAligner.java
deleted file mode 100644
index 3e0863e..0000000
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/FieldAligner.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014, 2016 Mateusz Matela and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Mateusz Matela <mateusz.matela@gmail.com> - [formatter] Formatter does not format Java code correctly, especially when max line width is set - https://bugs.eclipse.org/303519
- * Lars Vogel <Lars.Vogel@vogella.com> - Contributions for
- * Bug 473178
- *******************************************************************************/
-package org.eclipse.jdt.internal.formatter.linewrap;
-
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_BLOCK;
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_LINE;
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameEQUAL;
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameIdentifier;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.jdt.core.dom.BodyDeclaration;
-import org.eclipse.jdt.core.dom.FieldDeclaration;
-import org.eclipse.jdt.core.dom.SimpleName;
-import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
-import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
-import org.eclipse.jdt.internal.formatter.Token;
-import org.eclipse.jdt.internal.formatter.TokenManager;
-import org.eclipse.jdt.internal.formatter.TokenTraverser;
-
-/** Implementation of the "Align fields on columns" feature */
-public class FieldAligner {
- private class PositionCounter extends TokenTraverser {
- int stoppingIndex;
- int maxPosition;
-
- public PositionCounter() {
- // nothing to do
- }
-
- @Override
- protected boolean token(Token token, int index) {
- if (index == this.stoppingIndex)
- return false;
- if (getLineBreaksBefore() > 0)
- this.counter = FieldAligner.this.tm.getPositionInLine(index);
- if (token.getAlign() > 0)
- this.counter = token.getAlign();
- this.counter += FieldAligner.this.tm.getLength(token, this.counter);
- if (isSpaceAfter() && getLineBreaksAfter() == 0)
- this.counter++;
- this.maxPosition = Math.max(this.maxPosition, this.counter);
- return true;
- }
-
- public int findMaxPosition(int fromIndex, int toIndex) {
- this.counter = FieldAligner.this.tm.getPositionInLine(fromIndex);
- this.stoppingIndex = toIndex;
- this.maxPosition = 0;
- FieldAligner.this.tm.traverse(fromIndex, this);
- return this.maxPosition;
- }
- }
-
- private final List<List<FieldDeclaration>> fieldAlignGroups = new ArrayList<>();
-
- private final DefaultCodeFormatterOptions options;
-
- final TokenManager tm;
-
- public FieldAligner(TokenManager tokenManager, DefaultCodeFormatterOptions options) {
- this.tm = tokenManager;
- this.options = options;
- }
-
- public void handleAlign(List<FieldDeclaration> bodyDeclarations) {
- if (!this.options.align_type_members_on_columns)
- return;
- ArrayList<FieldDeclaration> alignGroup = new ArrayList<>();
- BodyDeclaration previous = null;
- for (BodyDeclaration declaration : bodyDeclarations) {
- if (declaration instanceof FieldDeclaration) {
- if (isNewGroup(declaration, previous)) {
- alignFields(alignGroup);
- alignGroup = new ArrayList<>();
- }
- alignGroup.add((FieldDeclaration) declaration);
- }
- previous = declaration;
- }
- alignFields(alignGroup);
- }
-
- private boolean isNewGroup(BodyDeclaration declaration, BodyDeclaration previousDeclaration) {
- if (!(previousDeclaration instanceof FieldDeclaration))
- return true;
- int lineBreaks = 0;
- int from = this.tm.lastIndexIn(previousDeclaration, -1);
- int to = this.tm.firstIndexIn(declaration, -1);
- Token previous = this.tm.get(from);
- for (int i = from + 1; i <= to; i++) {
- Token token = this.tm.get(i);
- lineBreaks += Math.min(this.tm.countLineBreaksBetween(previous, token),
- this.options.number_of_empty_lines_to_preserve + 1);
- previous = token;
- }
- return lineBreaks > this.options.align_fields_grouping_blank_lines;
- }
-
- private void alignFields(ArrayList<FieldDeclaration> alignGroup) {
- if (alignGroup.size() < 2)
- return;
- this.fieldAlignGroups.add(alignGroup);
-
- int maxNameAlign = 0;
- for (FieldDeclaration declaration : alignGroup) {
- List<VariableDeclarationFragment> fragments = declaration.fragments();
- SimpleName fieldName = fragments.get(0).getName();
- int nameIndex = this.tm.firstIndexIn(fieldName, TokenNameIdentifier);
- int positionInLine = this.tm.getPositionInLine(nameIndex);
- maxNameAlign = Math.max(maxNameAlign, positionInLine);
- }
- maxNameAlign = normalizedAlign(maxNameAlign);
-
- int maxAssignAlign = 0;
- for (FieldDeclaration declaration : alignGroup) {
- List<VariableDeclarationFragment> fragments = declaration.fragments();
- VariableDeclarationFragment fragment = fragments.get(0);
- int nameIndex = this.tm.firstIndexIn(fragment.getName(), TokenNameIdentifier);
- Token nameToken = this.tm.get(nameIndex);
-
- nameToken.setAlign(maxNameAlign);
-
- if (fragment.getInitializer() != null) {
- int equalIndex = this.tm.firstIndexAfter(fragment.getName(), TokenNameEQUAL);
- int positionInLine = this.tm.getPositionInLine(equalIndex);
- maxAssignAlign = Math.max(maxAssignAlign, positionInLine);
- }
- }
- maxAssignAlign = normalizedAlign(maxAssignAlign);
-
- for (FieldDeclaration declaration : alignGroup) {
- List<VariableDeclarationFragment> fragments = declaration.fragments();
- VariableDeclarationFragment fragment = fragments.get(0);
- if (fragment.getInitializer() != null) {
- int assingIndex = this.tm.firstIndexAfter(fragment.getName(), TokenNameEQUAL);
- Token assignToken = this.tm.get(assingIndex);
- assignToken.setAlign(maxAssignAlign);
- }
- }
- }
-
- public void alignComments() {
- if (this.fieldAlignGroups.isEmpty())
- return;
- boolean alignLineComments = !this.options.comment_preserve_white_space_between_code_and_line_comments;
- PositionCounter positionCounter = new PositionCounter();
- // align comments after field declarations
- for (List<FieldDeclaration> alignGroup : this.fieldAlignGroups) {
- int maxCommentAlign = 0;
- for (FieldDeclaration declaration : alignGroup) {
- int typeIndex = this.tm.firstIndexIn(declaration.getType(), -1);
- int firstIndexInLine = this.tm.findFirstTokenInLine(typeIndex);
- int lastIndex = this.tm.lastIndexIn(declaration, -1) + 1;
- maxCommentAlign = Math.max(maxCommentAlign,
- positionCounter.findMaxPosition(firstIndexInLine, lastIndex));
- }
- maxCommentAlign = normalizedAlign(maxCommentAlign);
-
- for (FieldDeclaration declaration : alignGroup) {
- int typeIndex = this.tm.firstIndexIn(declaration.getType(), -1);
- int firstIndexInLine = this.tm.findFirstTokenInLine(typeIndex);
- int lastIndex = this.tm.lastIndexIn(declaration, -1);
- lastIndex = Math.min(lastIndex, this.tm.size() - 2);
- for (int i = firstIndexInLine; i <= lastIndex; i++) {
- Token token = this.tm.get(i);
- Token next = this.tm.get(i + 1);
- boolean lineBreak = token.getLineBreaksAfter() > 0 || next.getLineBreaksBefore() > 0;
- if (lineBreak) {
- if (token.tokenType == TokenNameCOMMENT_BLOCK) {
- token.setAlign(maxCommentAlign);
- } else if (alignLineComments) {
- this.tm.addNLSAlignIndex(i, maxCommentAlign);
- }
- } else if (next.tokenType == TokenNameCOMMENT_LINE && alignLineComments
- || (next.tokenType == TokenNameCOMMENT_BLOCK && i == lastIndex)) {
- next.setAlign(maxCommentAlign);
- }
- }
- }
- }
- }
-
- private int normalizedAlign(int desiredAlign) {
- if (this.options.align_with_spaces)
- return desiredAlign;
- return this.tm.toIndent(desiredAlign, false);
- }
-}
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
index 9987d6a..1b68433 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
@@ -175,7 +175,7 @@
final DefaultCodeFormatterOptions options;
final int kind;
- final FieldAligner fieldAligner;
+ final Aligner aligner;
int importsStart = -1, importsEnd = -1;
@@ -197,7 +197,7 @@
this.options = options;
this.kind = kind;
- this.fieldAligner = new FieldAligner(this.tm, this.options);
+ this.aligner = new Aligner(this.tm, this.options);
}
@Override
@@ -258,20 +258,20 @@
prepareElementsList(node.typeParameters(), TokenNameCOMMA, TokenNameLESS);
handleWrap(this.options.alignment_for_type_parameters);
- this.fieldAligner.handleAlign(node.bodyDeclarations());
+ this.aligner.handleAlign(node.bodyDeclarations());
return true;
}
@Override
public boolean visit(AnnotationTypeDeclaration node) {
- this.fieldAligner.handleAlign(node.bodyDeclarations());
+ this.aligner.handleAlign(node.bodyDeclarations());
return true;
}
@Override
public boolean visit(AnonymousClassDeclaration node) {
- this.fieldAligner.handleAlign(node.bodyDeclarations());
+ this.aligner.handleAlign(node.bodyDeclarations());
return true;
}
@@ -367,7 +367,7 @@
handleWrap(this.options.alignment_for_superinterfaces_in_enum_declaration, PREFERRED);
}
- this.fieldAligner.handleAlign(node.bodyDeclarations());
+ this.aligner.handleAlign(node.bodyDeclarations());
return true;
}
@@ -383,6 +383,12 @@
}
@Override
+ public boolean visit(Block node) {
+ this.aligner.handleAlign(node);
+ return true;
+ }
+
+ @Override
public boolean visit(MethodInvocation node) {
handleArguments(node.arguments(), this.options.alignment_for_arguments_in_method_invocation);
handleTypeArguments(node.typeArguments());
@@ -1075,7 +1081,7 @@
preserveExistingLineBreaks();
applyBreaksOutsideRegions(regions);
new WrapExecutor(this.tm, this.options).executeWraps();
- this.fieldAligner.alignComments();
+ this.aligner.alignComments();
wrapComments();
fixEnumConstantIndents(astRoot);
}