Bug 104910 - [formatter] add "keep simple for/while on one line" option

Change-Id: Ibe7219084ed3bb33a96d9baf1443fe6d61cd48e4
Signed-off-by: Mateusz Matela <mateusz.matela@gmail.com>
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 dacaf3a..687a381 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
@@ -14179,4 +14179,84 @@
 	String input = getCompilationUnit("Formatter", "", "test128653", "in.java").getSource();
 	formatSource(input, getCompilationUnit("Formatter", "", "test128653", "I_out.java").getSource());
 }
+
+/**
+ * https://bugs.eclipse.org/104910 - [formatter] add "keep simple for/while on one line" option
+ */
+public void testBug104910a() throws JavaModelException {
+	this.formatterPrefs.keep_simple_for_body_on_same_line = true;
+	String input = getCompilationUnit("Formatter", "", "test104910", "in.java").getSource();
+	formatSource(input, getCompilationUnit("Formatter", "", "test104910", "A_out.java").getSource());
+}
+/**
+ * https://bugs.eclipse.org/104910 - [formatter] add "keep simple for/while on one line" option
+ */
+public void testBug104910b() throws JavaModelException {
+	this.formatterPrefs.keep_simple_while_body_on_same_line = true;
+	String input = getCompilationUnit("Formatter", "", "test104910", "in.java").getSource();
+	formatSource(input, getCompilationUnit("Formatter", "", "test104910", "B_out.java").getSource());
+}
+/**
+ * https://bugs.eclipse.org/104910 - [formatter] add "keep simple for/while on one line" option
+ */
+public void testBug104910c() throws JavaModelException {
+	this.formatterPrefs.keep_simple_do_while_body_on_same_line = true;
+	String input = getCompilationUnit("Formatter", "", "test104910", "in.java").getSource();
+	formatSource(input, getCompilationUnit("Formatter", "", "test104910", "C_out.java").getSource());
+}
+/**
+ * https://bugs.eclipse.org/104910 - [formatter] add "keep simple for/while on one line" option
+ */
+public void testBug104910d() throws JavaModelException {
+	this.formatterPrefs.keep_simple_for_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_while_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_do_while_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_if_on_one_line = true;
+	this.formatterPrefs.alignment_for_compact_if = Alignment.M_ONE_PER_LINE_SPLIT + Alignment.M_FORCE;
+	this.formatterPrefs.alignment_for_compact_loop = Alignment.M_ONE_PER_LINE_SPLIT + Alignment.M_FORCE;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = true;
+	String input = getCompilationUnit("Formatter", "", "test104910", "in.java").getSource();
+	formatSource(input, getCompilationUnit("Formatter", "", "test104910", "D_out.java").getSource());
+}
+/**
+ * https://bugs.eclipse.org/104910 - [formatter] add "keep simple for/while on one line" option
+ */
+public void testBug104910e() throws JavaModelException {
+	this.formatterPrefs.keep_simple_for_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_while_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_do_while_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_if_on_one_line = true;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = true;
+	this.formatterPrefs.page_width = 55;
+	String input = getCompilationUnit("Formatter", "", "test104910", "in.java").getSource();
+	formatSource(input, getCompilationUnit("Formatter", "", "test104910", "E_out.java").getSource());
+}
+/**
+ * https://bugs.eclipse.org/104910 - [formatter] add "keep simple for/while on one line" option
+ */
+public void testBug104910f() throws JavaModelException {
+	this.formatterPrefs.keep_simple_for_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_while_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_do_while_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_if_on_one_line = true;
+	this.formatterPrefs.alignment_for_compact_if = Alignment.M_ONE_PER_LINE_SPLIT + Alignment.M_FORCE + Alignment.M_INDENT_ON_COLUMN;
+	this.formatterPrefs.alignment_for_compact_loop = Alignment.M_ONE_PER_LINE_SPLIT + Alignment.M_FORCE + Alignment.M_INDENT_ON_COLUMN;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = true;
+	String input = getCompilationUnit("Formatter", "", "test104910", "in.java").getSource();
+	formatSource(input, getCompilationUnit("Formatter", "", "test104910", "F_out.java").getSource());
+}
+/**
+ * https://bugs.eclipse.org/104910 - [formatter] add "keep simple for/while on one line" option
+ */
+public void testBug104910g() throws JavaModelException {
+	this.formatterPrefs.keep_simple_for_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_while_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_do_while_body_on_same_line = true;
+	this.formatterPrefs.keep_simple_if_on_one_line = true;
+	this.formatterPrefs.alignment_for_compact_if = Alignment.M_NO_ALIGNMENT;
+	this.formatterPrefs.page_width = 40;
+	String input = getCompilationUnit("Formatter", "", "test104910", "in.java").getSource();
+	formatSource(input, getCompilationUnit("Formatter", "", "test104910", "G_out.java").getSource());
+}
+
 }
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test056/A_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test056/A_out.java
index 114b3f5..e900439 100644
--- a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test056/A_out.java
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test056/A_out.java
@@ -1,2 +1,2 @@
-if (true) ;
+if (true);
 else System.out.println();
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/A_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/A_out.java
new file mode 100644
index 0000000..227548b
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/A_out.java
@@ -0,0 +1,63 @@
+public class A {
+	void f() {
+		if (one != 1)
+			doSomething();
+
+		for (int i = 0; i < list.size(); i++) list.get(i).print();
+
+		for (Printer printer : list) printer.print(myDocument);
+
+		while (!queue.isEmpty())
+			consume(queue.remove());
+
+		do
+			list.add(createElement());
+		while (list.size() < 100);
+
+		/* */while /* */ (condition)
+			/* */ doSomething();
+		/* */do
+			/* */createElement();
+		/* */ while/* */ (condition);
+		/* */
+		/* */ for /* */ (String s : strings) /* */ System.out.println(s);
+
+		while (!queue.isEmpty())
+			for (String s : queue.remove()) if (!s.isEmpty())
+				print(s);
+		for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) sum += i * j;
+		while (x-- > 0)
+			while (y-- > 0)
+				drawPoint(x, y);
+		do
+			for (String s : queue.remove()) if (!s.isEmpty())
+				print(s);
+		while (!queue.isEmpty());
+
+		while (!queue.isEmpty()) {
+			for (String s : queue.remove()) if (!s.isEmpty())
+				print(s);
+		}
+		;
+		for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) {
+			sum += i * j;
+		}
+		while (x-- > 0) {
+			while (y-- > 0)
+				while (z-- > 0)
+					drawPoint(x, y, z);
+		}
+		do
+			for (String s : queue.remove()) {
+				if (!s.isEmpty())
+					print(s);
+			}
+		while (!queue.isEmpty());
+
+		while (aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccc())
+			ddddddddddddddddddddd.eeeeeeeeeeeeeeeee().fffffffffffffffffffff();
+		do
+			aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccccc();
+		while (ddddddddddddddddddddd.eeeeeeeeeeeeeeeee().fffffffffffffffffffff());
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/B_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/B_out.java
new file mode 100644
index 0000000..bef0065
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/B_out.java
@@ -0,0 +1,65 @@
+public class A {
+	void f() {
+		if (one != 1)
+			doSomething();
+
+		for (int i = 0; i < list.size(); i++)
+			list.get(i).print();
+
+		for (Printer printer : list)
+			printer.print(myDocument);
+
+		while (!queue.isEmpty()) consume(queue.remove());
+
+		do
+			list.add(createElement());
+		while (list.size() < 100);
+
+		/* */while /* */ (condition) /* */ doSomething();
+		/* */do
+			/* */createElement();
+		/* */ while/* */ (condition);
+		/* */
+		/* */ for /* */ (String s : strings)
+			/* */ System.out.println(s);
+
+		while (!queue.isEmpty()) for (String s : queue.remove())
+			if (!s.isEmpty())
+				print(s);
+		for (int i = 0; i < 10; i++)
+			for (int j = 0; j < 10; j++)
+				sum += i * j;
+		while (x-- > 0) while (y-- > 0) drawPoint(x, y);
+		do
+			for (String s : queue.remove())
+				if (!s.isEmpty())
+					print(s);
+		while (!queue.isEmpty());
+
+		while (!queue.isEmpty()) {
+			for (String s : queue.remove())
+				if (!s.isEmpty())
+					print(s);
+		}
+		;
+		for (int i = 0; i < 10; i++)
+			for (int j = 0; j < 10; j++) {
+				sum += i * j;
+			}
+		while (x-- > 0) {
+			while (y-- > 0) while (z-- > 0) drawPoint(x, y, z);
+		}
+		do
+			for (String s : queue.remove()) {
+				if (!s.isEmpty())
+					print(s);
+			}
+		while (!queue.isEmpty());
+
+		while (aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccc())
+			ddddddddddddddddddddd.eeeeeeeeeeeeeeeee().fffffffffffffffffffff();
+		do
+			aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccccc();
+		while (ddddddddddddddddddddd.eeeeeeeeeeeeeeeee().fffffffffffffffffffff());
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/C_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/C_out.java
new file mode 100644
index 0000000..fdb9560
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/C_out.java
@@ -0,0 +1,65 @@
+public class A {
+	void f() {
+		if (one != 1)
+			doSomething();
+
+		for (int i = 0; i < list.size(); i++)
+			list.get(i).print();
+
+		for (Printer printer : list)
+			printer.print(myDocument);
+
+		while (!queue.isEmpty())
+			consume(queue.remove());
+
+		do list.add(createElement()); while (list.size() < 100);
+
+		/* */while /* */ (condition)
+			/* */ doSomething();
+		/* */do/* */createElement();/* */ while/* */ (condition);
+		/* */
+		/* */ for /* */ (String s : strings)
+			/* */ System.out.println(s);
+
+		while (!queue.isEmpty())
+			for (String s : queue.remove())
+				if (!s.isEmpty())
+					print(s);
+		for (int i = 0; i < 10; i++)
+			for (int j = 0; j < 10; j++)
+				sum += i * j;
+		while (x-- > 0)
+			while (y-- > 0)
+				drawPoint(x, y);
+		do for (String s : queue.remove())
+			if (!s.isEmpty())
+				print(s);
+		while (!queue.isEmpty());
+
+		while (!queue.isEmpty()) {
+			for (String s : queue.remove())
+				if (!s.isEmpty())
+					print(s);
+		}
+		;
+		for (int i = 0; i < 10; i++)
+			for (int j = 0; j < 10; j++) {
+				sum += i * j;
+			}
+		while (x-- > 0) {
+			while (y-- > 0)
+				while (z-- > 0)
+					drawPoint(x, y, z);
+		}
+		do for (String s : queue.remove()) {
+			if (!s.isEmpty())
+				print(s);
+		}
+		while (!queue.isEmpty());
+
+		while (aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccc())
+			ddddddddddddddddddddd.eeeeeeeeeeeeeeeee().fffffffffffffffffffff();
+		do aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccccc();
+		while (ddddddddddddddddddddd.eeeeeeeeeeeeeeeee().fffffffffffffffffffff());
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/D_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/D_out.java
new file mode 100644
index 0000000..d50db34
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/D_out.java
@@ -0,0 +1,67 @@
+public class A {
+	void f() {
+		if (one != 1)
+		    doSomething();
+
+		for (int i = 0; i < list.size(); i++)
+		    list.get(i).print();
+
+		for (Printer printer : list)
+		    printer.print(myDocument);
+
+		while (!queue.isEmpty())
+		    consume(queue.remove());
+
+		do list.add(createElement());
+		while (list.size() < 100);
+
+		/* */while /* */ (condition)
+		    /* */ doSomething();
+		/* */do/* */createElement();
+		/* */ while/* */ (condition);
+		/* */
+		/* */ for /* */ (String s : strings)
+		    /* */ System.out.println(s);
+
+		while (!queue.isEmpty())
+		    for (String s : queue.remove())
+		        if (!s.isEmpty())
+		            print(s);
+		for (int i = 0; i < 10; i++)
+		    for (int j = 0; j < 10; j++)
+		        sum += i * j;
+		while (x-- > 0)
+		    while (y-- > 0)
+		        drawPoint(x, y);
+		do for (String s : queue.remove())
+		    if (!s.isEmpty())
+		        print(s);
+		while (!queue.isEmpty());
+
+		while (!queue.isEmpty()) {
+			for (String s : queue.remove())
+			    if (!s.isEmpty())
+			        print(s);
+		}
+		;
+		for (int i = 0; i < 10; i++)
+		    for (int j = 0; j < 10; j++) {
+			    sum += i * j;
+		    }
+		while (x-- > 0) {
+			while (y-- > 0)
+			    while (z-- > 0)
+			        drawPoint(x, y, z);
+		}
+		do for (String s : queue.remove()) {
+			if (!s.isEmpty())
+			    print(s);
+		}
+		while (!queue.isEmpty());
+
+		while (aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccc())
+		    ddddddddddddddddddddd.eeeeeeeeeeeeeeeee().fffffffffffffffffffff();
+		do aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccccc();
+		while (ddddddddddddddddddddd.eeeeeeeeeeeeeeeee().fffffffffffffffffffff());
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/E_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/E_out.java
new file mode 100644
index 0000000..8a9980b
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/E_out.java
@@ -0,0 +1,65 @@
+public class A {
+	void f() {
+		if (one != 1) doSomething();
+
+		for (int i = 0; i < list.size(); i++)
+		    list.get(i).print();
+
+		for (Printer printer : list)
+		    printer.print(myDocument);
+
+		while (!queue.isEmpty())
+		    consume(queue.remove());
+
+		do list.add(createElement());
+		while (list.size() < 100);
+
+		/* */while /* */ (condition)
+		    /* */ doSomething();
+		/* */do/* */createElement();
+		/* */ while/* */ (condition);
+		/* */
+		/* */ for /* */ (String s : strings)
+		    /* */ System.out.println(s);
+
+		while (!queue.isEmpty())
+		    for (String s : queue.remove())
+		        if (!s.isEmpty()) print(s);
+		for (int i = 0; i < 10; i++)
+		    for (int j = 0; j < 10; j++) sum += i * j;
+		while (x-- > 0)
+		    while (y-- > 0) drawPoint(x, y);
+		do for (String s : queue.remove())
+		    if (!s.isEmpty()) print(s);
+		while (!queue.isEmpty());
+
+		while (!queue.isEmpty()) {
+			for (String s : queue.remove())
+			    if (!s.isEmpty()) print(s);
+		}
+		;
+		for (int i = 0; i < 10; i++)
+		    for (int j = 0; j < 10; j++) {
+			    sum += i * j;
+		    }
+		while (x-- > 0) {
+			while (y-- > 0)
+			    while (z-- > 0) drawPoint(x, y, z);
+		}
+		do for (String s : queue.remove()) {
+			if (!s.isEmpty()) print(s);
+		}
+		while (!queue.isEmpty());
+
+		while (aaaaaaaaaaaaaaaaaaaaaa
+		        .bbbbbbbbbbbbbbbbbbb()
+		        .cccccccccccccccccccccc())
+		    ddddddddddddddddddddd.eeeeeeeeeeeeeeeee()
+		            .fffffffffffffffffffff();
+		do aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb()
+		        .cccccccccccccccccccccccc();
+		while (ddddddddddddddddddddd
+		        .eeeeeeeeeeeeeeeee()
+		        .fffffffffffffffffffff());
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/F_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/F_out.java
new file mode 100644
index 0000000..ba6cb7f
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/F_out.java
@@ -0,0 +1,71 @@
+public class A {
+	void f() {
+		if (one != 1)
+		              doSomething();
+
+		for (int i = 0; i < list.size(); i++)
+		                                      list.get(i).print();
+
+		for (Printer printer : list)
+		                             printer.print(myDocument);
+
+		while (!queue.isEmpty())
+		                         consume(queue.remove());
+
+		do list.add(createElement());
+		                              while (list.size() < 100);
+
+		/* */while /* */ (condition)
+		                            /* */ doSomething();
+		/* */do/* */createElement();
+		                            /* */ while/* */ (condition);
+		/* */
+		/* */ for /* */ (String s : strings)
+		                                    /* */ System.out.println(s);
+
+		while (!queue.isEmpty())
+		                         for (String s : queue.remove())
+		                                                         if (!s.isEmpty())
+		                                                                           print(s);
+		for (int i = 0; i < 10; i++)
+		                             for (int j = 0; j < 10; j++)
+		                                                          sum += i * j;
+		while (x-- > 0)
+		                while (y-- > 0)
+		                                drawPoint(x, y);
+		do for (String s : queue.remove())
+		                                   if (!s.isEmpty())
+		                                                     print(s);
+		                                                               while (!queue.isEmpty());
+
+		while (!queue.isEmpty()) {
+			for (String s : queue.remove())
+			                                if (!s.isEmpty())
+			                                                  print(s);
+		}
+		;
+		for (int i = 0; i < 10; i++)
+		                             for (int j = 0; j < 10; j++) {
+			                             sum += i * j;
+		                             }
+		while (x-- > 0) {
+			while (y-- > 0)
+			                while (z-- > 0)
+			                                drawPoint(x, y, z);
+		}
+		do for (String s : queue.remove()) {
+			if (!s.isEmpty())
+			                  print(s);
+		}
+		  while (!queue.isEmpty());
+
+		while (aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccc())
+		                                                                              ddddddddddddddddddddd
+		                                                                                      .eeeeeeeeeeeeeeeee()
+		                                                                                      .fffffffffffffffffffff();
+		do aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccccc();
+		                                                                            while (ddddddddddddddddddddd
+		                                                                                    .eeeeeeeeeeeeeeeee()
+		                                                                                    .fffffffffffffffffffff());
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/G_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/G_out.java
new file mode 100644
index 0000000..e6f0e49
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/G_out.java
@@ -0,0 +1,76 @@
+public class A {
+	void f() {
+		if (one != 1) doSomething();
+
+		for (int i = 0; i < list
+				.size(); i++)
+			list.get(i).print();
+
+		for (Printer printer : list)
+			printer.print(myDocument);
+
+		while (!queue.isEmpty())
+			consume(queue.remove());
+
+		do list.add(createElement());
+		while (list.size() < 100);
+
+		/* */while /* */ (condition)
+			/* */ doSomething();
+		/* */do/* */createElement();
+		/* */ while/* */ (condition);
+		/* */
+		/* */ for /* */ (String s : strings)
+			/* */ System.out.println(s);
+
+		while (!queue.isEmpty())
+			for (String s : queue
+					.remove())
+				if (!s.isEmpty()) print(
+						s);
+		for (int i = 0; i < 10; i++)
+			for (int j = 0; j < 10; j++)
+				sum += i * j;
+		while (x-- > 0) while (y-- > 0)
+			drawPoint(x, y);
+		do for (String s : queue
+				.remove())
+			if (!s.isEmpty()) print(s);
+		while (!queue.isEmpty());
+
+		while (!queue.isEmpty()) {
+			for (String s : queue
+					.remove())
+				if (!s.isEmpty()) print(
+						s);
+		}
+		;
+		for (int i = 0; i < 10; i++)
+			for (int j = 0; j < 10; j++) {
+				sum += i * j;
+			}
+		while (x-- > 0) {
+			while (y-- > 0)
+				while (z-- > 0)
+					drawPoint(x, y, z);
+		}
+		do for (String s : queue
+				.remove()) {
+			if (!s.isEmpty()) print(s);
+		}
+		while (!queue.isEmpty());
+
+		while (aaaaaaaaaaaaaaaaaaaaaa
+				.bbbbbbbbbbbbbbbbbbb()
+				.cccccccccccccccccccccc())
+			ddddddddddddddddddddd
+					.eeeeeeeeeeeeeeeee()
+					.fffffffffffffffffffff();
+		do aaaaaaaaaaaaaaaaaaaaaa
+				.bbbbbbbbbbbbbbbbbbb()
+				.cccccccccccccccccccccccc();
+		while (ddddddddddddddddddddd
+				.eeeeeeeeeeeeeeeee()
+				.fffffffffffffffffffff());
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/in.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/in.java
new file mode 100644
index 0000000..822d104
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test104910/in.java
@@ -0,0 +1,31 @@
+public class A {
+	void f() {
+		if(one != 1) doSomething();
+
+		for(int i = 0; i < list.size(); i++) list.get(i).print();
+
+		for(Printer printer : list) printer.print(myDocument);
+
+		while(!queue.isEmpty()) consume(queue.remove());
+
+		do list.add(createElement()); while (list.size() < 100);
+
+		/* */while /* */ (condition) /* */ doSomething();
+		/* */do/* */createElement();/* */while/* */(condition);
+		/* */
+		/* */   for   /* */   (String s : strings)   /* */   System.out.println(s);
+		
+		while(!queue.isEmpty()) for (String s : queue.remove()) if (!s.isEmpty()) print(s);
+		for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) sum += i * j;
+		while(x --> 0) while (y --> 0) drawPoint(x,y);
+		do for (String s : queue.remove()) if (!s.isEmpty()) print(s); while (!queue.isEmpty());
+
+		while(!queue.isEmpty()) { for (String s : queue.remove()) if (!s.isEmpty()) print(s); };
+		for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) { sum += i * j; }
+		while(x --> 0) { while (y --> 0) while (z --> 0) drawPoint(x,y,z); }
+		do for (String s : queue.remove()) { if (!s.isEmpty()) print(s); } while (!queue.isEmpty());
+
+		while (aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccc()) ddddddddddddddddddddd.eeeeeeeeeeeeeeeee().fffffffffffffffffffff();
+		do aaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb().cccccccccccccccccccccccc(); while (ddddddddddddddddddddd.eeeeeeeeeeeeeeeee().fffffffffffffffffffff());
+	}
+}
diff --git a/org.eclipse.jdt.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.core/META-INF/MANIFEST.MF
index e3a1554..3721439 100644
--- a/org.eclipse.jdt.core/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.core/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.core; singleton:=true
-Bundle-Version: 3.14.100.qualifier
+Bundle-Version: 3.15.0.qualifier
 Bundle-Activator: org.eclipse.jdt.core.JavaCore
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
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 60efae1..93c217f 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
@@ -180,6 +180,17 @@
 	public static final String FORMATTER_ALIGNMENT_FOR_COMPACT_IF = JavaCore.PLUGIN_ID + ".formatter.alignment_for_compact_if";	 //$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option for alignment of compact loops
+	 *     - option id:         "org.eclipse.jdt.core.formatter.alignment_for_compact_loops"
+	 *     - possible values:   values returned by <code>createAlignmentValue(boolean, int, int)</code> call
+	 *     - default:           createAlignmentValue(false, WRAP_ONE_PER_LINE, INDENT_BY_ONE)
+	 * </pre>
+	 * @see #createAlignmentValue(boolean, int, int)
+	 * @since 3.15
+	 */
+	public static final String FORMATTER_ALIGNMENT_FOR_COMPACT_LOOP = JavaCore.PLUGIN_ID + ".formatter.alignment_for_compact_loops";	 //$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option for alignment of conditional expression
 	 *     - option id:         "org.eclipse.jdt.core.formatter.alignment_for_conditional_expression"
 	 *     - possible values:   values returned by <code>createAlignmentValue(boolean, int, int)</code> call
@@ -3920,6 +3931,43 @@
 
 	/**
 	 * <pre>
+	 * FORMATTER / Option to keep a simple 'for' loop body on the same line
+	 *     - option id:         "org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line"
+	 *     - possible values:   { TRUE, FALSE }
+	 *     - default:           FALSE
+	 * </pre>
+	 * @see #TRUE
+	 * @see #FALSE
+	 * @since 3.15
+	 */
+	public static final String FORMATTER_KEEP_SIMPLE_FOR_BODY_ON_SAME_LINE = JavaCore.PLUGIN_ID + ".formatter.keep_simple_for_body_on_same_line";//$NON-NLS-1$
+	/**
+	 * <pre>
+	 * FORMATTER / Option to keep a simple 'while' loop body on the same line
+	 *     - option id:         "org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line"
+	 *     - possible values:   { TRUE, FALSE }
+	 *     - default:           FALSE
+	 * </pre>
+	 * @see #TRUE
+	 * @see #FALSE
+	 * @since 3.15
+	 */
+	public static final String FORMATTER_KEEP_SIMPLE_WHILE_BODY_ON_SAME_LINE = JavaCore.PLUGIN_ID + ".formatter.keep_simple_while_body_on_same_line";//$NON-NLS-1$
+	/**
+	 * <pre>
+	 * FORMATTER / Option to keep a simple 'do-while' loop body on the same line
+	 *     - option id:         "org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line"
+	 *     - possible values:   { TRUE, FALSE }
+	 *     - default:           FALSE
+	 * </pre>
+	 * @see #TRUE
+	 * @see #FALSE
+	 * @since 3.15
+	 */
+	public static final String FORMATTER_KEEP_SIMPLE_DO_WHILE_BODY_ON_SAME_LINE = JavaCore.PLUGIN_ID + ".formatter.keep_simple_do_while_body_on_same_line";//$NON-NLS-1$
+
+	/**
+	 * <pre>
 	 * FORMATTER / Option to specify the length of the page. Beyond this length, the formatter will try to split the code
 	 *     - option id:         "org.eclipse.jdt.core.formatter.lineSplit"
 	 *     - possible values:   "&lt;n&gt;", where n is zero or a positive integer
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 a2a5109..2c8705a 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
@@ -119,6 +119,7 @@
 	public int alignment_for_assignment;
 	public int alignment_for_binary_expression;
 	public int alignment_for_compact_if;
+	public int alignment_for_compact_loop;
 	public int alignment_for_conditional_expression;
 	public int alignment_for_enum_constants;
 	public int alignment_for_expressions_in_array_initializer;
@@ -414,6 +415,9 @@
 	public boolean keep_empty_array_initializer_on_one_line;
 	public boolean keep_simple_if_on_one_line;
 	public boolean keep_then_statement_on_same_line;
+	public boolean keep_simple_for_body_on_same_line;
+	public boolean keep_simple_while_body_on_same_line;
+	public boolean keep_simple_do_while_body_on_same_line;
 	public boolean never_indent_block_comments_on_first_column;
 	public boolean never_indent_line_comments_on_first_column;
 	public int number_of_empty_lines_to_preserve;
@@ -458,6 +462,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ASSIGNMENT, getAlignment(this.alignment_for_assignment));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_BINARY_EXPRESSION, getAlignment(this.alignment_for_binary_expression));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_COMPACT_IF, getAlignment(this.alignment_for_compact_if));
+		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_COMPACT_LOOP, getAlignment(this.alignment_for_compact_loop));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION, getAlignment(this.alignment_for_conditional_expression));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ENUM_CONSTANTS, getAlignment(this.alignment_for_enum_constants));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_ARRAY_INITIALIZER, getAlignment(this.alignment_for_expressions_in_array_initializer));
@@ -737,6 +742,9 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_EMPTY_ARRAY_INITIALIZER_ON_ONE_LINE, this.keep_empty_array_initializer_on_one_line ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_SIMPLE_IF_ON_ONE_LINE, this.keep_simple_if_on_one_line ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_THEN_STATEMENT_ON_SAME_LINE, this.keep_then_statement_on_same_line ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_SIMPLE_FOR_BODY_ON_SAME_LINE, this.keep_simple_for_body_on_same_line ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_SIMPLE_WHILE_BODY_ON_SAME_LINE, this.keep_simple_while_body_on_same_line ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_SIMPLE_DO_WHILE_BODY_ON_SAME_LINE, this.keep_simple_do_while_body_on_same_line ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_NEVER_INDENT_BLOCK_COMMENTS_ON_FIRST_COLUMN, this.never_indent_block_comments_on_first_column ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_NEVER_INDENT_LINE_COMMENTS_ON_FIRST_COLUMN, this.never_indent_line_comments_on_first_column ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_NUMBER_OF_EMPTY_LINES_TO_PRESERVE, Integer.toString(this.number_of_empty_lines_to_preserve));
@@ -859,6 +867,10 @@
 				this.alignment_for_compact_if = Alignment.M_ONE_PER_LINE_SPLIT | Alignment.M_INDENT_BY_ONE;
 			}
 		}
+		final Object alignmentForCompactLoopOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_COMPACT_LOOP);
+		if (alignmentForCompactLoopOption != null)
+			this.alignment_for_compact_loop = toInt(alignmentForCompactLoopOption, Alignment.M_ONE_PER_LINE_SPLIT | Alignment.M_INDENT_BY_ONE);
+
 		final Object alignmentForConditionalExpressionOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION);
 		if (alignmentForConditionalExpressionOption != null) {
 			try {
@@ -2188,6 +2200,18 @@
 		if (keepThenStatementOnSameLineOption != null) {
 			this.keep_then_statement_on_same_line = DefaultCodeFormatterConstants.TRUE.equals(keepThenStatementOnSameLineOption);
 		}
+		final Object keepSimpleForBodyOnSameLineOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_KEEP_SIMPLE_FOR_BODY_ON_SAME_LINE);
+		if (keepSimpleForBodyOnSameLineOption != null) {
+			this.keep_simple_for_body_on_same_line = DefaultCodeFormatterConstants.TRUE.equals(keepSimpleForBodyOnSameLineOption);
+		}
+		final Object keepSimpleWhileBodyOnSameLineOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_KEEP_SIMPLE_WHILE_BODY_ON_SAME_LINE);
+		if (keepSimpleWhileBodyOnSameLineOption != null) {
+			this.keep_simple_while_body_on_same_line = DefaultCodeFormatterConstants.TRUE.equals(keepSimpleWhileBodyOnSameLineOption);
+		}
+		final Object keepSimpleDoWhileBodyOnSameLineOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_KEEP_SIMPLE_DO_WHILE_BODY_ON_SAME_LINE);
+		if (keepSimpleDoWhileBodyOnSameLineOption != null) {
+			this.keep_simple_do_while_body_on_same_line = DefaultCodeFormatterConstants.TRUE.equals(keepSimpleDoWhileBodyOnSameLineOption);
+		}
 		final Object neverIndentBlockCommentOnFirstColumnOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_NEVER_INDENT_BLOCK_COMMENTS_ON_FIRST_COLUMN);
 		if (neverIndentBlockCommentOnFirstColumnOption != null) {
 			this.never_indent_block_comments_on_first_column = DefaultCodeFormatterConstants.TRUE.equals(neverIndentBlockCommentOnFirstColumnOption);
@@ -2443,6 +2467,7 @@
 		this.alignment_for_assignment = Alignment.M_NO_ALIGNMENT;
 		this.alignment_for_binary_expression = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_compact_if = Alignment.M_ONE_PER_LINE_SPLIT | Alignment.M_INDENT_BY_ONE;
+		this.alignment_for_compact_loop = Alignment.M_ONE_PER_LINE_SPLIT | Alignment.M_INDENT_BY_ONE;
 		this.alignment_for_conditional_expression = Alignment.M_ONE_PER_LINE_SPLIT;
 		this.alignment_for_enum_constants = Alignment.M_NO_ALIGNMENT;
 		this.alignment_for_expressions_in_array_initializer = Alignment.M_COMPACT_SPLIT;
@@ -2720,6 +2745,9 @@
 		this.keep_empty_array_initializer_on_one_line = false;
 		this.keep_simple_if_on_one_line = false;
 		this.keep_then_statement_on_same_line = false;
+		this.keep_simple_for_body_on_same_line = false;
+		this.keep_simple_while_body_on_same_line = false;
+		this.keep_simple_do_while_body_on_same_line = false;
 		this.never_indent_block_comments_on_first_column = false;
 		this.never_indent_line_comments_on_first_column = false;
 		this.number_of_empty_lines_to_preserve = 1;
@@ -2756,6 +2784,7 @@
 		this.alignment_for_assignment = Alignment.M_NO_ALIGNMENT;
 		this.alignment_for_binary_expression = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_compact_if = Alignment.M_COMPACT_SPLIT;
+		this.alignment_for_compact_loop = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_conditional_expression = Alignment.M_NEXT_PER_LINE_SPLIT;
 		this.alignment_for_enum_constants = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_expressions_in_array_initializer = Alignment.M_COMPACT_SPLIT;
@@ -3033,6 +3062,9 @@
 		this.keep_empty_array_initializer_on_one_line = false;
 		this.keep_simple_if_on_one_line = false;
 		this.keep_then_statement_on_same_line = false;
+		this.keep_simple_for_body_on_same_line = false;
+		this.keep_simple_while_body_on_same_line = false;
+		this.keep_simple_do_while_body_on_same_line = false;
 		this.never_indent_block_comments_on_first_column = false;
 		this.never_indent_line_comments_on_first_column = false;
 		this.number_of_empty_lines_to_preserve = 1;
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 0b3f6a1..6bca97a 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014, 2015 Mateusz Matela and others.
+ * 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
@@ -369,9 +369,11 @@
 	@Override
 	public boolean visit(DoStatement node) {
 		Statement body = node.getBody();
-		handleLoopBody(body);
+		boolean sameLine = this.options.keep_simple_do_while_body_on_same_line;
+		if (!sameLine)
+			handleLoopBody(body);
 		if (this.options.insert_new_line_before_while_in_do_statement
-				|| (!(body instanceof Block) && !(body instanceof EmptyStatement))) {
+				|| (!(body instanceof Block) && !(body instanceof EmptyStatement) && !sameLine)) {
 			Token whileToken = this.tm.firstTokenBefore(node.getExpression(), TokenNamewhile);
 			whileToken.breakBefore();
 		}
@@ -535,7 +537,8 @@
 
 	@Override
 	public boolean visit(WhileStatement node) {
-		handleLoopBody(node.getBody());
+		if (!this.options.keep_simple_while_body_on_same_line)
+			handleLoopBody(node.getBody());
 
 		int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN);
 		int rParen = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN);
@@ -545,7 +548,8 @@
 
 	@Override
 	public boolean visit(ForStatement node) {
-		handleLoopBody(node.getBody());
+		if (!this.options.keep_simple_for_body_on_same_line)
+			handleLoopBody(node.getBody());
 
 		int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN);
 		int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN);
@@ -555,7 +559,8 @@
 
 	@Override
 	public boolean visit(EnhancedForStatement node) {
-		handleLoopBody(node.getBody());
+		if (!this.options.keep_simple_for_body_on_same_line)
+			handleLoopBody(node.getBody());
 
 		int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN);
 		int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN);
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java
index 76b26cc..797355a 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014, 2016 Mateusz Matela and others.
+ * 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
@@ -38,6 +38,7 @@
 import org.eclipse.jdt.core.dom.CreationReference;
 import org.eclipse.jdt.core.dom.Dimension;
 import org.eclipse.jdt.core.dom.DoStatement;
+import org.eclipse.jdt.core.dom.EmptyStatement;
 import org.eclipse.jdt.core.dom.EnhancedForStatement;
 import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
 import org.eclipse.jdt.core.dom.EnumDeclaration;
@@ -363,6 +364,7 @@
 				this.options.insert_space_after_opening_paren_in_while);
 		handleTokenBefore(node.getBody(), TokenNameRPAREN, this.options.insert_space_before_closing_paren_in_while,
 				false);
+		handleLoopBody(node.getBody());
 		return true;
 	}
 
@@ -564,16 +566,14 @@
 				this.options.insert_space_after_opening_paren_in_if);
 
 		Statement thenStatement = node.getThenStatement();
-		int closingParenIndex = this.tm.firstIndexBefore(thenStatement, TokenNameRPAREN);
-		handleToken(this.tm.get(closingParenIndex), this.options.insert_space_before_closing_paren_in_if,
-				/* space before then statement may be needed if it will stay on the same line */
-				!(thenStatement instanceof Block) && !this.tm.get(closingParenIndex + 1).isComment());
+		handleTokenBefore(thenStatement, TokenNameRPAREN, this.options.insert_space_before_closing_paren_in_if, false);
 
 		if (thenStatement instanceof Block && this.tm.isGuardClause((Block) thenStatement)) {
 			handleToken(thenStatement, TokenNameLBRACE, false, true);
 			this.tm.lastTokenIn(node, TokenNameRBRACE).spaceBefore();
 		}
 
+		handleLoopBody(thenStatement);
 		handleSemicolon(thenStatement);
 		return true;
 	}
@@ -597,6 +597,8 @@
 		handleTokenBefore(node.getBody(), TokenNameSEMICOLON,
 				this.options.insert_space_before_semicolon_in_for && !part2Empty,
 				this.options.insert_space_after_semicolon_in_for && !part3Empty);
+
+		handleLoopBody(node.getBody());
 		return true;
 	}
 
@@ -622,6 +624,7 @@
 				this.options.insert_space_before_closing_paren_in_for, false);
 		handleTokenAfter(node.getParameter(), TokenNameCOLON, this.options.insert_space_before_colon_in_for,
 				this.options.insert_space_after_colon_in_for);
+		handleLoopBody(node.getBody());
 		return true;
 	}
 
@@ -1082,6 +1085,15 @@
 		}
 	}
 
+	private void handleLoopBody(Statement loopBody) {
+		/* space before body statement may be needed if it will stay on the same line */
+		int firstTokenIndex = this.tm.firstIndexIn(loopBody, -1);
+		if (!(loopBody instanceof Block) && !(loopBody instanceof EmptyStatement)
+				&& !this.tm.get(firstTokenIndex - 1).isComment()) {
+			this.tm.get(firstTokenIndex).spaceBefore();
+		}
+	}
+
 	public void finishUp() {
 		this.tm.traverse(0, new TokenTraverser() {
 			boolean isPreviousJIDP = false;
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
index 011b8cc..6ccf535 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
@@ -652,7 +652,8 @@
 		if (policy.indentOnColumn) {
 			wrapIndent = this.tm.getPositionInLine(policy.wrapParentIndex);
 			wrapIndent += this.tm.getLength(wrapParent, wrapIndent);
-			if (wrapParent.isSpaceAfter() || this.tm.get(policy.wrapParentIndex + 1).isSpaceBefore())
+			Token next = this.tm.get(policy.wrapParentIndex + 1);
+			if (wrapParent.isSpaceAfter() || (next.isSpaceBefore() && !next.isComment()))
 				wrapIndent++;
 		}
 		wrapIndent += policy.extraIndent;
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 f279cc4..9987d6a 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
@@ -36,6 +36,7 @@
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamethis;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamethrows;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameto;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamewhile;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamewith;
 
 import java.util.ArrayList;
@@ -56,6 +57,8 @@
 import org.eclipse.jdt.core.dom.ConditionalExpression;
 import org.eclipse.jdt.core.dom.ConstructorInvocation;
 import org.eclipse.jdt.core.dom.CreationReference;
+import org.eclipse.jdt.core.dom.DoStatement;
+import org.eclipse.jdt.core.dom.EnhancedForStatement;
 import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
 import org.eclipse.jdt.core.dom.EnumDeclaration;
 import org.eclipse.jdt.core.dom.ExportsDirective;
@@ -93,6 +96,7 @@
 import org.eclipse.jdt.core.dom.VariableDeclaration;
 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
+import org.eclipse.jdt.core.dom.WhileStatement;
 import org.eclipse.jdt.core.formatter.CodeFormatter;
 import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
 import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions.Alignment;
@@ -647,27 +651,10 @@
 
 	@Override
 	public boolean visit(IfStatement node) {
-		Statement thenStatement = node.getThenStatement();
-		Statement elseStatement = node.getElseStatement();
-		if (!(thenStatement instanceof Block)) {
-			boolean keepThenOnSameLine = this.options.keep_then_statement_on_same_line
-					|| (this.options.keep_simple_if_on_one_line && elseStatement == null);
-			if (keepThenOnSameLine) {
-				this.wrapIndexes.add(this.tm.firstIndexIn(thenStatement, -1));
-				this.wrapParentIndex = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN);
-				this.wrapGroupEnd = this.tm.lastIndexIn(thenStatement, -1);
-				handleWrap(this.options.alignment_for_compact_if, node);
-			}
-		}
-		if (elseStatement != null && !(elseStatement instanceof Block) && !(elseStatement instanceof IfStatement)) {
-			if (this.options.keep_else_statement_on_same_line) {
-				int elseIndex = this.tm.firstIndexIn(elseStatement, -1);
-				this.wrapIndexes.add(elseIndex);
-				this.wrapParentIndex = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN);
-				this.wrapGroupEnd = this.tm.lastIndexIn(elseStatement, -1);
-				handleWrap(this.options.alignment_for_compact_if, node);
-			}
-		}
+		boolean keepThenOnSameLine = this.options.keep_then_statement_on_same_line
+				|| (this.options.keep_simple_if_on_one_line && node.getElseStatement() == null);
+		if (keepThenOnSameLine)
+			handleSimpleLoop(node.getThenStatement(), this.options.alignment_for_compact_if);
 		return true;
 	}
 
@@ -684,12 +671,63 @@
 		if (!this.wrapIndexes.isEmpty()) {
 			this.wrapParentIndex = this.tm.firstIndexIn(node, TokenNameLPAREN);
 			this.wrapGroupEnd = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN);
-			handleWrap(this.options.alignment_for_expressions_in_for_loop_header, node);
+			handleWrap(this.options.alignment_for_expressions_in_for_loop_header);
 		}
+		if (this.options.keep_simple_for_body_on_same_line)
+			handleSimpleLoop(node.getBody(), this.options.alignment_for_compact_loop);
 		return true;
 	}
 
 	@Override
+	public boolean visit(EnhancedForStatement node) {
+		if (this.options.keep_simple_for_body_on_same_line)
+			handleSimpleLoop(node.getBody(), this.options.alignment_for_compact_loop);
+		return true;
+	}
+
+	@Override
+	public boolean visit(WhileStatement node) {
+		if (this.options.keep_simple_while_body_on_same_line)
+			handleSimpleLoop(node.getBody(), this.options.alignment_for_compact_loop);
+		return true;
+	}
+
+	private void handleSimpleLoop(Statement body, int wrappingOption) {
+		if (!(body instanceof Block)) {
+			this.wrapIndexes.add(this.tm.firstIndexIn(body, -1));
+			this.wrapParentIndex = this.tm.firstIndexBefore(body, TokenNameRPAREN);
+			this.wrapGroupEnd = this.tm.lastIndexIn(body, -1);
+			handleWrap(wrappingOption, body.getParent());
+
+			body.accept(new ASTVisitor() {
+				@Override
+				public boolean visit(Block node) {
+					forceContinuousWrapping(node, WrapPreparator.this.tm.firstIndexIn(node, -1));
+					return false;
+				}
+			});
+		}
+	}
+
+	@Override
+	public void endVisit(DoStatement node) {
+		if (this.options.keep_simple_do_while_body_on_same_line && !(node.getBody() instanceof Block)) {
+			int whileIndex = this.tm.firstIndexAfter(node.getBody(), TokenNamewhile);
+			this.wrapIndexes.add(whileIndex);
+			this.wrapParentIndex = this.tm.lastIndexIn(node.getBody(), -1);
+			this.wrapGroupEnd = this.tm.lastIndexIn(node, -1);
+
+			int alignment = this.options.alignment_for_compact_loop;
+			for (int i = this.tm.firstIndexIn(node, -1) + 1; i < whileIndex; i++) {
+				Token token = this.tm.get(i);
+				if (token.getLineBreaksBefore() > 0 || token.getLineBreaksAfter() > 0)
+					alignment |= Alignment.M_FORCE;
+			}
+			handleWrap(alignment, node);
+		}
+	}
+
+	@Override
 	public boolean visit(TryStatement node) {
 		prepareElementsList(node.resources(), TokenNameSEMICOLON, TokenNameLPAREN);
 		handleWrap(this.options.alignment_for_resources_in_try);
@@ -819,7 +857,7 @@
 	 * Makes sure all new lines within given node will have wrap policy so that
 	 * wrap executor will fix their indentation if necessary.
 	 */
-	private void forceContinuousWrapping(ASTNode node, int parentIndex) {
+	void forceContinuousWrapping(ASTNode node, int parentIndex) {
 		int parentIndent = this.tm.get(parentIndex).getIndent();
 		int indentChange = -parentIndent;
 		int lineStart = this.tm.findFirstTokenInLine(parentIndex);
@@ -982,9 +1020,13 @@
 			if (!this.options.indent_body_declarations_compare_to_enum_declaration_header)
 				extraIndent--;
 			isAlreadyWrapped = isFirst;
-		} else if (parentNode instanceof IfStatement) {
+		} else if (parentNode instanceof IfStatement || parentNode instanceof ForStatement
+				|| parentNode instanceof EnhancedForStatement || parentNode instanceof WhileStatement) {
 			extraIndent = 1;
 			this.wrapParentIndex = this.tm.firstIndexIn(parentNode, -1); // only if !indoentOnColumn
+		} else if (parentNode instanceof DoStatement) {
+			extraIndent = 0;
+			this.wrapParentIndex = this.tm.firstIndexIn(parentNode, -1); // only if !indoentOnColumn
 		} else if ((wrappingOption & Alignment.M_INDENT_BY_ONE) != 0) {
 			extraIndent = 1;
 		} else if (parentNode instanceof ArrayInitializer) {
diff --git a/org.eclipse.jdt.core/pom.xml b/org.eclipse.jdt.core/pom.xml
index 10fad74..f44c277 100644
--- a/org.eclipse.jdt.core/pom.xml
+++ b/org.eclipse.jdt.core/pom.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-  Copyright (c) 2012, 2016 Eclipse Foundation and others.
+  Copyright (c) 2012, 2018 Eclipse Foundation and others.
   All rights reserved. This program and the accompanying materials
   are made available under the terms of the Eclipse Distribution License v1.0
   which accompanies this distribution, and is available at
@@ -18,7 +18,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.core</artifactId>
-  <version>3.14.100-SNAPSHOT</version>
+  <version>3.15.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 
   <properties>