From 38a084ce6dac1515bb299fbea16f5b68e9829638 Mon Sep 17 00:00:00 2001 From: Marco Stornelli Date: Fri, 22 Mar 2019 19:18:04 +0100 Subject: [PATCH] Bug 500000 - Added proper formatting for lambda expressions Change-Id: Ia530b00f3710b74d1749978c9c5d23a2d55646f0 Signed-off-by: Marco Stornelli --- .../DefaultCodeFormatterConstants.java | 35 ++++ .../DefaultCodeFormatterOptions.java | 33 ++++ .../formatter/CodeFormatterVisitor.java | 166 +++++++++++++++++- .../internal/formatter/align/Alignment.java | 1 + .../cdt/ui/tests/text/CodeFormatterTest.java | 71 ++++++++ .../formatter/FormatterMessages.java | 6 + .../formatter/FormatterMessages.properties | 7 + .../formatter/LineWrappingTabPage.java | 12 ++ .../formatter/WhiteSpaceOptions.java | 19 ++ 9 files changed, 347 insertions(+), 3 deletions(-) diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java index c9a7ab8ca99..fd0b2c45b14 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java @@ -338,6 +338,17 @@ public class DefaultCodeFormatterConstants { */ public static final String FORMATTER_ALIGNMENT_FOR_THROWS_CLAUSE_IN_METHOD_DECLARATION = CCorePlugin.PLUGIN_ID + ".formatter.alignment_for_throws_clause_in_method_declaration"; //$NON-NLS-1$ + /** + *
+	 * FORMATTER / Option for alignment of lambda expression
+	 *     - option id:         "org.eclipse.cdt.core.formatter.alignment_for_lambda_expression"
+	 *     - possible values:   values returned by {@code createAlignmentValue(boolean, int, int)} call
+	 *     - default:           createAlignmentValue(false, WRAP_COMPACT, INDENT_DEFAULT)
+	 * 
+ * @see #createAlignmentValue(boolean, int, int) + */ + public static final String FORMATTER_ALIGNMENT_FOR_LAMBDA_EXPRESSION = CCorePlugin.PLUGIN_ID + + ".formatter.alignment_for_lambda_expression"; //$NON-NLS-1$ // /** // *
 	//	 * FORMATTER / Option to add blank lines after #include directive
@@ -1528,6 +1539,30 @@ public class DefaultCodeFormatterConstants {
 	 */
 	public static final String FORMATTER_INSERT_SPACE_AFTER_UNARY_OPERATOR = CCorePlugin.PLUGIN_ID
 			+ ".formatter.insert_space_after_unary_operator"; //$NON-NLS-1$
+	/**
+	 * 
+	 * FORMATTER / Option to insert a space after lambda return
+	 *     - option id:         "org.eclipse.cdt.core.formatter.insert_space_after_lambda_return"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           INSERT
+	 * 
+ * @see CCorePlugin#INSERT + * @see CCorePlugin#DO_NOT_INSERT + */ + public static final String FORMATTER_INSERT_SPACE_AFTER_LAMBDA_RETURN = CCorePlugin.PLUGIN_ID + + ".formatter.insert_space_after_lambda_return"; //$NON-NLS-1$ + /** + *
+	 * FORMATTER / Option to insert a space before lambda return
+	 *     - option id:         "org.eclipse.cdt.core.formatter.insert_before_lambda_return"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           INSERT
+	 * 
+ * @see CCorePlugin#INSERT + * @see CCorePlugin#DO_NOT_INSERT + */ + public static final String FORMATTER_INSERT_SPACE_BEFORE_LAMBDA_RETURN = CCorePlugin.PLUGIN_ID + + ".formatter.insert_space_before_lambda_return"; //$NON-NLS-1$ /** *
 	 * FORMATTER / Option to insert a space before an assignment operator
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java
index 7596897a0e4..4a0cd58b204 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java
@@ -79,6 +79,7 @@ public class DefaultCodeFormatterOptions {
 	public int alignment_for_parameters_in_method_declaration;
 	public int alignment_for_throws_clause_in_method_declaration;
 	public int alignment_for_constructor_initializer_list;
+	public int alignment_for_lambda_expression;
 
 	//	public boolean align_type_members_on_columns;
 
@@ -204,6 +205,8 @@ public class DefaultCodeFormatterOptions {
 	public boolean insert_space_after_question_in_conditional;
 	public boolean insert_space_after_semicolon_in_for;
 	public boolean insert_space_after_unary_operator;
+	public boolean insert_space_after_lambda_return;
+	public boolean insert_space_before_lambda_return;
 	public boolean insert_space_before_assignment_operator;
 	public boolean insert_space_before_binary_operator;
 	public boolean insert_space_before_closing_angle_bracket_in_template_arguments;
@@ -359,6 +362,8 @@ public class DefaultCodeFormatterOptions {
 				getAlignment(this.alignment_for_constructor_initializer_list));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_THROWS_CLAUSE_IN_METHOD_DECLARATION,
 				getAlignment(this.alignment_for_throws_clause_in_method_declaration));
+		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_LAMBDA_EXPRESSION,
+				getAlignment(this.alignment_for_lambda_expression));
 		//		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_TYPE_MEMBERS_ON_COLUMNS, this.align_type_members_on_columns ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		//		options.put(DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_AFTER_IMPORTS, Integer.toString(this.blank_lines_after_includes));
 		//		options.put(DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_BEFORE_FIELD, Integer.toString(this.blank_lines_before_field));
@@ -569,6 +574,10 @@ public class DefaultCodeFormatterOptions {
 				this.insert_space_after_semicolon_in_for ? CCorePlugin.INSERT : CCorePlugin.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_UNARY_OPERATOR,
 				this.insert_space_after_unary_operator ? CCorePlugin.INSERT : CCorePlugin.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_LAMBDA_RETURN,
+				this.insert_space_after_lambda_return ? CCorePlugin.INSERT : CCorePlugin.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_LAMBDA_RETURN,
+				this.insert_space_before_lambda_return ? CCorePlugin.INSERT : CCorePlugin.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_ASSIGNMENT_OPERATOR,
 				this.insert_space_before_assignment_operator ? CCorePlugin.INSERT : CCorePlugin.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_BINARY_OPERATOR,
@@ -982,6 +991,17 @@ public class DefaultCodeFormatterOptions {
 				this.alignment_for_throws_clause_in_method_declaration = Alignment.M_COMPACT_SPLIT;
 			}
 		}
+		final Object alignmentForLambdaExpressionOption = settings
+				.get(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_LAMBDA_EXPRESSION);
+		if (alignmentForLambdaExpressionOption != null) {
+			try {
+				this.alignment_for_lambda_expression = Integer.parseInt((String) alignmentForLambdaExpressionOption);
+			} catch (NumberFormatException e) {
+				this.alignment_for_lambda_expression = Alignment.M_COMPACT_SPLIT | Alignment.M_INDENT_BY_ONE;
+			} catch (ClassCastException e) {
+				this.alignment_for_lambda_expression = Alignment.M_COMPACT_SPLIT | Alignment.M_INDENT_BY_ONE;
+			}
+		}
 		//		final Object alignTypeMembersOnColumnsOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGN_TYPE_MEMBERS_ON_COLUMNS);
 		//		if (alignTypeMembersOnColumnsOption != null) {
 		//			this.align_type_members_on_columns = DefaultCodeFormatterConstants.TRUE.equals(alignTypeMembersOnColumnsOption);
@@ -1645,6 +1665,16 @@ public class DefaultCodeFormatterOptions {
 		if (insertSpaceAfterUnaryOperatorOption != null) {
 			this.insert_space_after_unary_operator = CCorePlugin.INSERT.equals(insertSpaceAfterUnaryOperatorOption);
 		}
+		final Object insertSpaceAfterLambdaReturnOption = settings
+				.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_LAMBDA_RETURN);
+		if (insertSpaceAfterLambdaReturnOption != null) {
+			this.insert_space_after_lambda_return = CCorePlugin.INSERT.equals(insertSpaceAfterLambdaReturnOption);
+		}
+		final Object insertSpaceBeforeLambdaReturnOption = settings
+				.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_LAMBDA_RETURN);
+		if (insertSpaceBeforeLambdaReturnOption != null) {
+			this.insert_space_before_lambda_return = CCorePlugin.INSERT.equals(insertSpaceBeforeLambdaReturnOption);
+		}
 		final Object insertSpaceBeforeAssignmentOperatorOption = settings
 				.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_ASSIGNMENT_OPERATOR);
 		if (insertSpaceBeforeAssignmentOperatorOption != null) {
@@ -2174,6 +2204,7 @@ public class DefaultCodeFormatterOptions {
 		this.alignment_for_parameters_in_method_declaration = Alignment.M_COMPACT_SPLIT;
 		//		this.alignment_for_selector_in_method_invocation = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_throws_clause_in_method_declaration = Alignment.M_COMPACT_SPLIT;
+		this.alignment_for_lambda_expression = Alignment.M_COMPACT_SPLIT | Alignment.M_INDENT_BY_ONE;
 		//		this.align_type_members_on_columns = false;
 		//		this.blank_lines_after_includes = 1;
 		//		this.blank_lines_before_field = 1;
@@ -2271,6 +2302,8 @@ public class DefaultCodeFormatterOptions {
 		this.insert_space_after_question_in_conditional = true;
 		this.insert_space_after_semicolon_in_for = true;
 		this.insert_space_after_unary_operator = false;
+		this.insert_space_after_lambda_return = true;
+		this.insert_space_before_lambda_return = true;
 		this.insert_space_before_assignment_operator = true;
 		this.insert_space_before_binary_operator = true;
 		this.insert_space_before_closing_angle_bracket_in_template_arguments = false;
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
index 2914d8bd5f6..bd5c069f87b 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
@@ -111,6 +111,7 @@ import org.eclipse.cdt.core.dom.ast.c.ICASTDesignator;
 import org.eclipse.cdt.core.dom.ast.c.ICASTVisitor;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAttributeList;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTBinaryExpression;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCapture;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTClassVirtSpecifier;
@@ -132,6 +133,8 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression.CaptureDefault;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier;
@@ -206,9 +209,15 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
 		boolean fSpaceBeforeOpeningParen;
 		int fContinuationIndentation = -1;
 		int fTieBreakRule = Alignment.R_INNERMOST;
+		CaptureDefault captureDefault;
+		int rightToken;
+		int leftToken;
 
 		ListOptions(int mode) {
 			this.fMode = mode;
+			captureDefault = CaptureDefault.UNSPECIFIED;
+			rightToken = Token.tRPAREN;
+			leftToken = Token.tLPAREN;
 		}
 	}
 
@@ -304,7 +313,23 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
 		@Override
 		public void run() {
 			boolean needSpace = skipConstVolatileRestrict(true);
+			// Skip mutable or constexpr keywords for a lambda expression
+			needSpace = skipMutableConstexpr() || needSpace;
 			int token = peekNextToken();
+			// Lambda return value
+			if (token == Token.tARROW) {
+				scribe.printNextToken(token, preferences.insert_space_before_lambda_return);
+				if (preferences.insert_space_after_lambda_return)
+					scribe.space();
+				if (node.getParent() instanceof ICPPASTLambdaExpression) {
+					final IASTTypeId returnValue = ((ICPPASTFunctionDeclarator) node).getTrailingReturnType();
+					returnValue.accept(CodeFormatterVisitor.this);
+					scribe.printTrailingComment();
+					scribe.space();
+				}
+				token = peekNextToken();
+				needSpace = true;
+			}
 			// Ref-qualifier.
 			if (token == Token.tAMPER || token == Token.tAND) {
 				scribe.printNextToken(token, true);
@@ -360,10 +385,19 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
 		private final boolean spaceBeforeClosingParen;
 		private final Runnable continuationFormatter;
 		private final int parenPosition;
+		private final int token;
+
+		public ClosingParensesisTailFormatter(boolean spaceBeforeClosingParen, Runnable tailFormatter, int token) {
+			this.spaceBeforeClosingParen = spaceBeforeClosingParen;
+			this.continuationFormatter = tailFormatter;
+			this.token = token;
+			this.parenPosition = scribe.findToken(token);
+		}
 
 		public ClosingParensesisTailFormatter(boolean spaceBeforeClosingParen, Runnable tailFormatter) {
 			this.spaceBeforeClosingParen = spaceBeforeClosingParen;
 			this.continuationFormatter = tailFormatter;
+			this.token = Token.tRPAREN;
 			this.parenPosition = scribe.findToken(Token.tRPAREN);
 		}
 
@@ -374,7 +408,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
 				if (offset < parenPosition)
 					scribe.restartAtOffset(parenPosition);
 				scribe.undoSpace();
-				scribe.printNextToken(Token.tRPAREN, spaceBeforeClosingParen);
+				scribe.printNextToken(token, spaceBeforeClosingParen);
 			}
 			if (continuationFormatter != null)
 				continuationFormatter.run();
@@ -955,6 +989,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
 			visit((ICPPASTSimpleTypeConstructorExpression) node);
 		} else if (node instanceof IASTProblemExpression) {
 			visit((IASTProblemExpression) node);
+		} else if (node instanceof ICPPASTLambdaExpression) {
+			visit((ICPPASTLambdaExpression) node);
 		} else {
 			formatRaw(node);
 		}
@@ -962,6 +998,83 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
 		return PROCESS_SKIP;
 	}
 
+	public int visit(ICPPASTLambdaExpression node) {
+		final int line = scribe.line;
+
+		final ListOptions options = createListOptionsForLambdaCapturesParameters(node);
+		ICPPASTCapture[] captures = node.getCaptures();
+		formatList(Arrays.asList(captures), options, true, captures.length > 0 && captures[0].isPackExpansion(), null,
+				new Runnable() {
+					@Override
+					public void run() {
+						if (options.captureDefault == CaptureDefault.BY_COPY) {
+							scribe.printNextToken(Token.tASSIGN, options.fSpaceAfterOpeningParen);
+						} else if (options.captureDefault == CaptureDefault.BY_REFERENCE) {
+							scribe.printNextToken(Token.tAMPER, options.fSpaceAfterOpeningParen);
+						}
+
+						if (options.captureDefault != CaptureDefault.UNSPECIFIED && node.getCaptures().length > 0) {
+							scribe.printNextToken(Token.tCOMMA, options.fSpaceBeforeSeparator);
+							if (options.fSpaceAfterSeparator)
+								scribe.space();
+						}
+					}
+				});
+
+		// declarator
+		final ICPPASTFunctionDeclarator declarator = node.getDeclarator();
+		skipNonWhitespaceToNode(declarator);
+		boolean hasSpace = scribe.printComment();
+		boolean hasPointerOps = declarator.getPointerOperators().length > 0;
+		boolean needSpace = (hasPointerOps && hasSpace) || (!hasPointerOps && peekNextToken() == Token.tIDENTIFIER);
+		if (needSpace) {
+			scribe.space();
+		}
+		Runnable tailFormatter = null;
+		IASTStatement bodyStmt = node.getBody();
+		if (DefaultCodeFormatterConstants.END_OF_LINE.equals(preferences.brace_position_for_method_declaration)
+				&& bodyStmt instanceof IASTCompoundStatement && !startsWithMacroExpansion(bodyStmt)) {
+			tailFormatter = new TrailingTokenFormatter(Token.tLBRACE, nodeOffset(bodyStmt),
+					preferences.insert_space_before_opening_brace_in_method_declaration, false);
+			scribe.setTailFormatter(tailFormatter);
+		}
+		declarator.accept(this);
+
+		IASTAttributeSpecifier[] attributes = declarator.getAttributeSpecifiers();
+		if (attributes.length > 0) {
+			formatAttributes(declarator, true, false);
+		}
+
+		if (tailFormatter != null) {
+			scribe.runTailFormatter();
+			scribe.setTailFormatter(null);
+		}
+
+		Alignment alignment = scribe.createAlignment(Alignment.LAMBDA_EXPRESSION,
+				preferences.alignment_for_lambda_expression, Alignment.R_INNERMOST, 1, getCurrentPosition());
+		scribe.enterAlignment(alignment);
+
+		// Body
+		if (bodyStmt instanceof IASTCompoundStatement) {
+			if (enterNode(bodyStmt)) {
+				if (getCurrentPosition() <= nodeOffset(bodyStmt)) {
+					formatLeftCurlyBrace(line, preferences.brace_position_for_method_declaration);
+				}
+				formatBlock((IASTCompoundStatement) bodyStmt, preferences.brace_position_for_method_declaration,
+						preferences.insert_space_before_opening_brace_in_method_declaration,
+						preferences.indent_statements_compare_to_body);
+				exitNode(bodyStmt);
+			}
+		} else if (bodyStmt != null) {
+			bodyStmt.accept(this);
+		}
+		scribe.printTrailingComment();
+
+		// go back to the previous alignment again:
+		scribe.exitAlignment(alignment, true);
+		return PROCESS_SKIP;
+	}
+
 	/*
 	 * @see ASTVisitor#visit(IASTStatement)
 	 */
@@ -1556,6 +1669,17 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
 		return skipped;
 	}
 
+	private boolean skipMutableConstexpr() {
+		boolean skipped = false;
+		int token = peekNextToken();
+		while (token == Token.t_mutable || token == Token.t_constexpr) {
+			scribe.printNextToken(token, true);
+			token = peekNextToken();
+			skipped = true;
+		}
+		return skipped;
+	}
+
 	private int visit(IASTStandardFunctionDeclarator node) {
 		final List parameters = Arrays.asList(node.getParameters());
 		final ListOptions options = createListOptionsForFunctionDeclarationParameters();
@@ -1575,6 +1699,21 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
 		return options;
 	}
 
+	private ListOptions createListOptionsForLambdaCapturesParameters(ICPPASTLambdaExpression expr) {
+		final ListOptions options = new ListOptions(preferences.alignment_for_parameters_in_method_declaration);
+		options.fSpaceBeforeOpeningParen = preferences.insert_space_before_opening_paren_in_method_declaration;
+		options.fSpaceAfterOpeningParen = preferences.insert_space_after_opening_paren_in_method_declaration;
+		options.fSpaceBeforeClosingParen = preferences.insert_space_before_closing_paren_in_method_declaration;
+		options.fSpaceBetweenEmptyParen = preferences.insert_space_between_empty_parens_in_method_declaration;
+		options.fSpaceBeforeSeparator = preferences.insert_space_before_comma_in_method_declaration_parameters;
+		options.fSpaceAfterSeparator = preferences.insert_space_after_comma_in_method_declaration_parameters;
+		options.fTieBreakRule = Alignment.R_OUTERMOST;
+		options.rightToken = Token.tRBRACKET;
+		options.leftToken = Token.tLBRACKET;
+		options.captureDefault = expr.getCaptureDefault();
+		return options;
+	}
+
 	/**
 	 * Returns the position of the last character of a node, or -1 if that character is part of
 	 * a macro expansion.
@@ -2257,16 +2396,37 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
 	 */
 	private void formatList(List elements, ListOptions options, boolean encloseInParen, boolean addEllipsis,
 			Runnable tailFormatter) {
+		formatList(elements, options, encloseInParen, addEllipsis, tailFormatter, null);
+	}
+
+	/**
+	 * Format a given list of elements according alignment options.
+	 *
+	 * @param elements the elements to format, which can be either {@link IASTNode}s or
+	 *     {@link TokenRange}s.
+	 * @param options formatting options
+	 * @param encloseInParen indicates whether the list should be enclosed in parentheses
+	 * @param addEllipsis indicates whether ellipsis should be added after the last element
+	 * @param tailFormatter formatter for the trailing text that should be kept together with
+	 * 		the last element of the list.
+	 * @param prefix A custom list prefix to format the first element
+	 */
+	private void formatList(List elements, ListOptions options, boolean encloseInParen, boolean addEllipsis,
+			Runnable tailFormatter, Runnable prefix) {
 		if (encloseInParen)
-			scribe.printNextToken(Token.tLPAREN, options.fSpaceBeforeOpeningParen);
+			scribe.printNextToken(options.leftToken, options.fSpaceBeforeOpeningParen);
 
 		final int elementsLength = elements.size();
 		if (encloseInParen) {
 			boolean spaceBeforeClosingParen = elements.isEmpty() && !addEllipsis ? options.fSpaceBetweenEmptyParen
 					: options.fSpaceBeforeClosingParen;
-			tailFormatter = new ClosingParensesisTailFormatter(spaceBeforeClosingParen, tailFormatter);
+			tailFormatter = new ClosingParensesisTailFormatter(spaceBeforeClosingParen, tailFormatter,
+					options.rightToken);
 		}
 
+		if (prefix != null)
+			prefix.run();
+
 		if (!elements.isEmpty() || addEllipsis) {
 			if (options.fSpaceAfterOpeningParen) {
 				scribe.space();
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/align/Alignment.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/align/Alignment.java
index 4ce3410da34..5e4c8f63a4b 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/align/Alignment.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/align/Alignment.java
@@ -32,6 +32,7 @@ public class Alignment {
 	public static final String CONDITIONAL_EXPRESSION = "conditionalExpression"; //$NON-NLS-1$
 	public static final String CONDITIONAL_EXPRESSION_CHAIN = "conditionalExpressionChain"; //$NON-NLS-1$
 	public static final String DECLARATION_INITIALIZER = "declarationInitializer"; //$NON-NLS-1$
+	public static final String LAMBDA_EXPRESSION = "lambdaExpression"; //$NON-NLS-1$
 	public static final String DESIGNATED_INITIALIZER = "designatedInitializer"; //$NON-NLS-1$
 	public static final String EXCEPTION_SPECIFICATION = "exceptionSpecification"; //$NON-NLS-1$
 	public static final String FIELD_REFERENCE = "fieldReference"; //$NON-NLS-1$
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java
index e612154189f..fa128f2d680 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java
@@ -4152,4 +4152,75 @@ public class CodeFormatterTest extends BaseUITestCase {
 	public void testNamespacesWithInactiveSections_Bug405049() throws Exception {
 		assertFormatterResult();
 	}
+
+	//int main() {
+	//	auto f = []() {
+	//
+	//		for(int c1 = 0; c1 < 3; c1 ++) {
+	//			for(int i = 0; i < 5; i ++) {
+	//				for(int c2 = 0; c2 < 3; c2 ++) {
+	//					// keep me here
+	//				}
+	//			}
+	//		}
+	//	};
+	//	f();
+	//	return 0;
+	//}
+
+	//int main() {
+	//	auto f = []() {
+	//
+	//		for (int c1 = 0; c1 < 3; c1++) {
+	//			for (int i = 0; i < 5; i++) {
+	//				for (int c2 = 0; c2 < 3; c2++) {
+	//					// keep me here
+	//				}
+	//			}
+	//		}
+	//	};
+	//	f();
+	//	return 0;
+	//}
+	public void testAlignmentOfLambda1_Bug500000() throws Exception {
+		assertFormatterResult();
+	}
+
+	//int main() {
+	//	int n = 0;
+	//	auto f = [=]()mutable{n= 20;};
+	//	f();
+	//	return 0;
+	//}
+
+	//int main() {
+	//	int n = 0;
+	//	auto f = [=]() mutable {
+	//		n = 20;
+	//	};
+	//	f();
+	//	return 0;
+	//}
+	public void testAlignmentOfLambda2_Bug500000() throws Exception {
+		assertFormatterResult();
+	}
+
+	//int main() {
+	//	int n = 0;
+	//	auto f = [=]()throw(int)[[deprecated]]{throw 1;};
+	//	f();
+	//	return 0;
+	//}
+
+	//int main() {
+	//	int n = 0;
+	//	auto f = [=]() throw (int) [[deprecated]] {
+	//		throw 1;
+	//	};
+	//	f();
+	//	return 0;
+	//}
+	public void testAlignmentOfLambda3_Bug500000() throws Exception {
+		assertFormatterResult();
+	}
 }
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java
index 7332e953e88..fecf76a9955 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java
@@ -43,6 +43,9 @@ final class FormatterMessages extends NLS {
 	public static String WhiteSpaceTabPage_operators_after_prefix_operators;
 	public static String WhiteSpaceTabPage_operators_before_postfix_operators;
 	public static String WhiteSpaceTabPage_operators_after_postfix_operators;
+	public static String WhiteSpaceTabPage_lambda_expressions;
+	public static String WhiteSpaceTabPage_lambda_before_return;
+	public static String WhiteSpaceTabPage_lambda_after_return;
 	public static String WhiteSpaceTabPage_classes;
 	public static String WhiteSpaceTabPage_classes_before_opening_brace_of_a_class;
 	public static String WhiteSpaceTabPage_classes_before_colon_of_base_clause;
@@ -129,6 +132,7 @@ final class FormatterMessages extends NLS {
 	public static String WhiteSpaceOptions_unary_operator;
 	public static String WhiteSpaceOptions_prefix_operator;
 	public static String WhiteSpaceOptions_postfix_operator;
+	public static String WhiteSpaceOptions_lambda_arrow_operator;
 	public static String WhiteSpaceOptions_opening_paren;
 	public static String WhiteSpaceOptions_pointer;
 	public static String WhiteSpaceOptions_catch;
@@ -209,6 +213,7 @@ final class FormatterMessages extends NLS {
 	public static String LineWrappingTabPage_parameters;
 	public static String LineWrappingTabPage_arguments;
 	public static String LineWrappingTabPage_throws_clause;
+	public static String LineWrappingTabPage_lambda_expression;
 	public static String LineWrappingTabPage_constructor_initializer_list;
 	public static String LineWrappingTabPage_enum_decls;
 	public static String LineWrappingTabPage_enumerator_list;
@@ -232,6 +237,7 @@ final class FormatterMessages extends NLS {
 	public static String LineWrappingTabPage_parameters_lowercase;
 	public static String LineWrappingTabPage_arguments_lowercase;
 	public static String LineWrappingTabPage_throws_clause_lowercase;
+	public static String LineWrappingTabPage_lambda_expression_lowercase;
 	public static String LineWrappingTabPage_constructor_initializer_list_lowercase;
 	public static String LineWrappingTabPage_enum_decls_lowercase;
 	public static String LineWrappingTabPage_enumerator_list_lowercase;
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties
index 4cb176db07c..ffcf7dec9e5 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties
@@ -30,6 +30,10 @@ WhiteSpaceTabPage_operators_after_prefix_operators=after prefix operators
 WhiteSpaceTabPage_operators_before_postfix_operators=before postfix operators
 WhiteSpaceTabPage_operators_after_postfix_operators=after postfix operators
 
+WhiteSpaceTabPage_lambda_expressions=Lambda expressions
+WhiteSpaceTabPage_lambda_before_return=before return arrow
+WhiteSpaceTabPage_lambda_after_return=after return arrow
+
 WhiteSpaceTabPage_classes=Types
 WhiteSpaceTabPage_classes_before_opening_brace_of_a_class=before opening brace of a class
 WhiteSpaceTabPage_classes_before_colon_of_base_clause=before colon of base clause
@@ -140,6 +144,7 @@ WhiteSpaceOptions_binary_operator=Binary operator
 WhiteSpaceOptions_unary_operator=Unary operator
 WhiteSpaceOptions_prefix_operator=Prefix operator
 WhiteSpaceOptions_postfix_operator=Postfix operator
+WhiteSpaceOptions_lambda_arrow_operator=Lambda arrow operator
 
 WhiteSpaceOptions_pointer=Pointer
 WhiteSpaceOptions_before_pointer=Before pointer
@@ -240,6 +245,7 @@ LineWrappingTabPage_base_clause=Base-clause
 LineWrappingTabPage_parameters=Parameters
 LineWrappingTabPage_arguments=Arguments
 LineWrappingTabPage_throws_clause=Exception specification
+LineWrappingTabPage_lambda_expression=Lambda expression
 LineWrappingTabPage_constructor_initializer_list=Constructor initializer list
 #LineWrappingTabPage_object_allocation=Object allocation arguments
 LineWrappingTabPage_enum_decls='enum' declaration
@@ -265,6 +271,7 @@ LineWrappingTabPage_base_clause_lowercase=base-clause
 LineWrappingTabPage_parameters_lowercase=parameters
 LineWrappingTabPage_arguments_lowercase=arguments
 LineWrappingTabPage_throws_clause_lowercase=exception specification
+LineWrappingTabPage_lambda_expression_lowercase=lambda expression
 LineWrappingTabPage_constructor_initializer_list_lowercase=constructor initializer list
 #LineWrappingTabPage_object_allocation_lowercase=object allocation arguments
 LineWrappingTabPage_enum_decls_lowercase='enum' declaration
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/LineWrappingTabPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/LineWrappingTabPage.java
index d01c56d97a6..9673756f15a 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/LineWrappingTabPage.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/LineWrappingTabPage.java
@@ -412,6 +412,17 @@ public class LineWrappingTabPage extends FormatterTabPage {
 			FormatterMessages.LineWrappingTabPage_throws_clause,
 			FormatterMessages.LineWrappingTabPage_throws_clause_lowercase);
 
+	private final Category fLambdaCategory = new Category(
+			DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_LAMBDA_EXPRESSION, "int foo() {" + //$NON-NLS-1$
+					"  auto f = [](){for(int c1 = 0; c1 < 3; c1 ++) {\n" + //$NON-NLS-1$
+					"			for(int i = 0; i < 5; i ++) {\n" + //$NON-NLS-1$
+					"				for(int c2 = 0; c2 < 3; c2 ++) {\n" + //$NON-NLS-1$
+					"				}\n" + //$NON-NLS-1$
+					"			}\n" + //$NON-NLS-1$
+					"		}};}", //$NON-NLS-1$
+			FormatterMessages.LineWrappingTabPage_lambda_expression,
+			FormatterMessages.LineWrappingTabPage_lambda_expression_lowercase);
+
 	private final Category fConstructorInitializerListCategory = new Category(
 			DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONSTRUCTOR_INITIALIZER_LIST, "class Point {" + //$NON-NLS-1$
 					"public:" + //$NON-NLS-1$
@@ -638,6 +649,7 @@ public class LineWrappingTabPage extends FormatterTabPage {
 		methodDeclarations.children.add(fMethodDeclarationsParametersCategory);
 		methodDeclarations.children.add(fMethodThrowsClauseCategory);
 		methodDeclarations.children.add(fConstructorInitializerListCategory);
+		methodDeclarations.children.add(fLambdaCategory);
 
 		final Category enumDeclarations = new Category(FormatterMessages.LineWrappingTabPage_enum_decls,
 				FormatterMessages.LineWrappingTabPage_enum_decls_lowercase);
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java
index 109b053864b..7336a30e56c 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java
@@ -180,6 +180,9 @@ public final class WhiteSpaceOptions {
 					"void bar(int x, int y) throw() {}" + //$NON-NLS-1$
 					"void* baz(int* x, int& y) {return 0;}"); //$NON-NLS-1$
 
+	private final PreviewSnippet LAMBDA_PREVIEW = new PreviewSnippet(CodeFormatter.K_CLASS_BODY_DECLARATIONS,
+			"void foo() { auto f = []()->int{return 0;};}"); //$NON-NLS-1$
+
 	private final PreviewSnippet INITIALIZER_LIST_PREVIEW = new PreviewSnippet(CodeFormatter.K_STATEMENTS,
 			"int array[]= {1, 2, 3};"); //$NON-NLS-1$
 
@@ -470,6 +473,7 @@ public final class WhiteSpaceOptions {
 		createNamespaceTree(workingValues, declarations);
 		createLinkageTree(workingValues, declarations);
 		//        createConstructorTree(workingValues, declarations);
+		createLambdaDeclTree(workingValues, declarations);
 		createMethodDeclTree(workingValues, declarations);
 		createExceptionSpecificationTree(workingValues, declarations);
 		createLabelTree(workingValues, declarations);
@@ -591,6 +595,8 @@ public final class WhiteSpaceOptions {
 				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_PREFIX_OPERATOR, OPERATOR_PREVIEW);
 		createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_postfix_operator,
 				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_POSTFIX_OPERATOR, OPERATOR_PREVIEW);
+		createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_lambda_arrow_operator,
+				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_LAMBDA_RETURN, LAMBDA_PREVIEW);
 	}
 
 	private void createBeforeClosingBracketTree(Map workingValues, final InnerNode parent) {
@@ -822,6 +828,8 @@ public final class WhiteSpaceOptions {
 				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_PREFIX_OPERATOR, OPERATOR_PREVIEW);
 		createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_postfix_operator,
 				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_POSTFIX_OPERATOR, OPERATOR_PREVIEW);
+		createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_lambda_arrow_operator,
+				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_LAMBDA_RETURN, LAMBDA_PREVIEW);
 	}
 
 	private void createAfterOpenBracketTree(Map workingValues, final InnerNode parent) {
@@ -971,6 +979,17 @@ public final class WhiteSpaceOptions {
 		return root;
 	}
 
+	private InnerNode createLambdaDeclTree(Map workingValues, InnerNode parent) {
+		final InnerNode root = new InnerNode(parent, workingValues,
+				FormatterMessages.WhiteSpaceTabPage_lambda_expressions);
+
+		createOption(root, workingValues, FormatterMessages.WhiteSpaceTabPage_lambda_before_return,
+				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_LAMBDA_RETURN, LAMBDA_PREVIEW);
+		createOption(root, workingValues, FormatterMessages.WhiteSpaceTabPage_lambda_after_return,
+				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_LAMBDA_RETURN, LAMBDA_PREVIEW);
+		return root;
+	}
+
 	private InnerNode createMethodDeclTree(Map workingValues, InnerNode parent) {
 		final InnerNode root = new InnerNode(parent, workingValues, FormatterMessages.WhiteSpaceTabPage_functions);