JSR_308 - Fix for 313524
diff --git a/buildnotes_jdt-core.html b/buildnotes_jdt-core.html
index 2251dc5..1bdfba5 100644
--- a/buildnotes_jdt-core.html
+++ b/buildnotes_jdt-core.html
@@ -48,9 +48,60 @@
 <br>Project org.eclipse.jdt.core v_A54
 (<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_A54">cvs</a>).
 <h2>What's new in this drop</h2>
+<ul>
+<li>
+Added a new preference to force the formatter to try to keep nested expressions on one line.
+<p>
+This new preference is controlled with the option:</p>
+<code>DefaultCodeFormatterConstants.FORMATTER_WRAP_OUTER_EXPRESSIONS_WHEN_NESTED</code>
+<pre>
+/**
+ * FORMATTER / Option to wrap outer expressions in nested expressions
+ *     - option id:         "org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested"
+ *     - possible values:   { TRUE, FALSE }
+ *     - default:           TRUE
+ *
+ * This option changes the formatter behavior when nested method calls are encountered.
+ * Since 3.6, the formatter tries to wrap outermost method calls first to have a better output.
+ * For example, let's say we are using the Eclipse built-in profile with a max line width=40+space for tab policy.
+ * Then consider the following snippet:
+ *
+ * public class X01 {
+ *     void test() {
+ *         foo(bar(1, 2, 3, 4), bar(5, 6, 7, 8));
+ *     }
+ * }
+ *
+ * With this new strategy, the formatter will wrap the line earlier, between the arguments of the message call
+ * for this example, and then it will allow to keep each nested call on a single line.
+ * Hence, the output will be:
+ *
+ * public class X01 {
+ *     void test() {
+ *         foo(bar(1, 2, 3, 4),
+ *             bar(5, 6, 7, 8));
+ *     }
+ * }
+ *
+ * Important notes:
+ * 1. This new behavior is automatically activated (ie. the default value for this preference is {@link #TRUE}).
+ *    If the backward compatibility regarding previous versions formatter behavior (ie. before 3.6 version) is necessary,
+ *    then the preference needs to be set to {@link #FALSE} to retrieve the previous formatter behavior.
+ * 2. The new strategy currently only applies to nested method calls, but might be extended to other nested expressions in future versions
+ * 
+ * @see #TRUE
+ * @see #FALSE
+ * @since 3.6
+ */
+</pre>
+See bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=313524">313524</a> for more details.
+</li>
+</ul>
 
 <h3>Problem Reports Fixed</h3>
-<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=313109">313109</a>
+<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=313524">313524</a>
+[formatter] Add preference for improved lines wrapping in nested method calls
+<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=313109">313109</a>
 @SuppressWarnings on multiple locals is marked unnecessary if any local is never used
 
 <a name="v_A53"></a>
diff --git a/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java b/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
index 87f0b7e..4ce5551 100644
--- a/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
+++ b/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
@@ -3496,6 +3496,51 @@
 	public static final String FORMATTER_WRAP_BEFORE_BINARY_OPERATOR = JavaCore.PLUGIN_ID + ".formatter.wrap_before_binary_operator"; //$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to wrap outer expressions in nested expressions
+	 *     - option id:         "org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested"
+	 *     - possible values:   { TRUE, FALSE }
+	 *     - default:           TRUE
+	 * </pre>
+	 * <p>
+	 * This option changes the formatter behavior when nested method calls are encountered.
+	 * Since 3.6, the formatter tries to wrap outermost method calls first to have a better output.</p>
+	 * <p>For example, let's say we are using the Eclipse built-in profile with a max line width=40+space for tab policy.
+	 * Then consider the following snippet:</p>
+	 * <pre>
+	 * public class X01 {
+	 *     void test() {
+	 *         foo(bar(1, 2, 3, 4), bar(5, 6, 7, 8));
+	 *     }
+	 * }
+	 * </pre>
+	 * <p>With this new strategy, the formatter will wrap the line earlier, between the arguments of the message call
+	 * for this example, and then it will allow to keep each nested call on a single line.</p>
+	 * <p>Hence, the output will be:</p>
+	 * <pre>
+	 * public class X01 {
+	 *     void test() {
+	 *         foo(bar(1, 2, 3, 4),
+	 *             bar(5, 6, 7, 8));
+	 *     }
+	 * }
+	 * </pre>
+	 * <p>
+	 * </p>
+	 * <p><b><u>Important notes</u></b>:</p>
+	 * <ol>
+	 * <li>This new behavior is automatically activated (ie. the default value for this preference is {@link #TRUE}).
+	 * If the backward compatibility regarding previous versions formatter behavior (ie. before 3.6 version) is necessary,
+	 * then the preference needs to be set to {@link #FALSE} to retrieve the previous formatter behavior.</li>
+	 * <li>The new strategy currently only applies to nested method calls, but might be extended to other nested expressions in future versions</li>
+	 * </ol>
+	 * 
+	 * @see #TRUE
+	 * @see #FALSE
+	 * @since 3.6
+	 */
+	public static final String FORMATTER_WRAP_OUTER_EXPRESSIONS_WHEN_NESTED = JavaCore.PLUGIN_ID + ".formatter.wrap_outer_expressions_when_nested"; //$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / The wrapping is done by indenting by one compare to the current indentation.
 	 * </pre>
 	 * @since 3.0
diff --git a/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java b/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
index 3965ef1..cb86fab 100644
--- a/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
+++ b/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
@@ -1362,7 +1362,9 @@
 			}
 			startingPositionInCascade = 2;
 		}
-		int tieBreakRule = size-startingPositionInCascade > 2 ? Alignment.R_OUTERMOST : Alignment.R_INNERMOST;
+		int tieBreakRule = this.preferences.wrap_outer_expressions_when_nested && size-startingPositionInCascade > 2
+			? Alignment.R_OUTERMOST
+			: Alignment.R_INNERMOST;
 		Alignment cascadingMessageSendAlignment =
 			this.scribe.createAlignment(
 				Alignment.CASCADING_MESSAGE_SEND,
@@ -1674,7 +1676,7 @@
 		Alignment messageAlignment) {
 
 		if (messageAlignment != null) {
-			if (messageAlignment.canAlign()) {
+			if (!this.preferences.wrap_outer_expressions_when_nested || messageAlignment.canAlign()) {
 				this.scribe.alignFragment(messageAlignment, 0);
 			}
 			this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
diff --git a/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java b/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
index 87e465f..0e6bf72 100644
--- a/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
+++ b/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
@@ -325,6 +325,7 @@
 	public int tab_char;
 	public boolean use_tabs_only_for_leading_indentations;
 	public boolean wrap_before_binary_operator;
+	public boolean wrap_outer_expressions_when_nested;
 
 	public int initial_indentation_level;
 	public String line_separator;
@@ -622,6 +623,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_DISABLING_TAG, this.disabling_tag == null ? Util.EMPTY_STRING : new String(this.disabling_tag));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ENABLING_TAG, this.enabling_tag == null ? Util.EMPTY_STRING : new String(this.enabling_tag));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_USE_ON_OFF_TAGS, this.use_tags ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_WRAP_OUTER_EXPRESSIONS_WHEN_NESTED, this.wrap_outer_expressions_when_nested ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		return options;
 	}
 
@@ -1997,6 +1999,10 @@
 				}
 			}
 		}
+		final Object wrapWrapOuterExpressionsWhenNestedOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_WRAP_OUTER_EXPRESSIONS_WHEN_NESTED);
+		if (wrapWrapOuterExpressionsWhenNestedOption != null) {
+			this.wrap_outer_expressions_when_nested = DefaultCodeFormatterConstants.TRUE.equals(wrapWrapOuterExpressionsWhenNestedOption);
+		}
 	}
 
 	/**
@@ -2310,6 +2316,7 @@
 		this.use_tags = false;
 		this.disabling_tag = DEFAULT_DISABLING_TAG;
 		this.enabling_tag = DEFAULT_ENABLING_TAG;
+		this.wrap_outer_expressions_when_nested = true;
 	}
 
 	public void setEclipseDefaultSettings() {
@@ -2584,5 +2591,6 @@
 		this.use_tags = false;
 		this.disabling_tag = DEFAULT_DISABLING_TAG;
 		this.enabling_tag = DEFAULT_ENABLING_TAG;
+		this.wrap_outer_expressions_when_nested = true;
 	}
 }
diff --git a/formatter/org/eclipse/jdt/internal/formatter/Scribe.java b/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
index 33aa2f8..c46b4f2 100644
--- a/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
+++ b/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
@@ -1258,6 +1258,38 @@
 	}
 
 	public void handleLineTooLong() {
+		if (this.formatter.preferences.wrap_outer_expressions_when_nested) {
+			handleLineTooLongSmartly();
+			return;
+		}
+		// search for closest breakable alignment, using tiebreak rules
+		// look for outermost breakable one
+		int relativeDepth = 0, outerMostDepth = -1;
+		Alignment targetAlignment = this.currentAlignment;
+		while (targetAlignment != null){
+			if (targetAlignment.tieBreakRule == Alignment.R_OUTERMOST && targetAlignment.couldBreak()){
+				outerMostDepth = relativeDepth;
+			}
+			targetAlignment = targetAlignment.enclosing;
+			relativeDepth++;
+		}
+		if (outerMostDepth >= 0) {
+			throw new AlignmentException(AlignmentException.LINE_TOO_LONG, outerMostDepth);
+		}
+		// look for innermost breakable one
+		relativeDepth = 0;
+		targetAlignment = this.currentAlignment;
+		while (targetAlignment != null){
+			if (targetAlignment.couldBreak()){
+				throw new AlignmentException(AlignmentException.LINE_TOO_LONG, relativeDepth);
+			}
+			targetAlignment = targetAlignment.enclosing;
+			relativeDepth++;
+		}
+		// did not find any breakable location - proceed
+	}
+
+	private void handleLineTooLongSmartly() {
 		// search for closest breakable alignment, using tiebreak rules
 		// look for outermost breakable one
 		int relativeDepth = 0, outerMostDepth = -1;