diff options
author | Marco Stornelli | 2019-03-22 18:18:04 +0000 |
---|---|---|
committer | Marco Stornelli | 2019-05-15 17:49:05 +0000 |
commit | 38a084ce6dac1515bb299fbea16f5b68e9829638 (patch) | |
tree | 9f9ebb8170f70e12e877008ebfb7f64db239aedd /core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal | |
parent | 8b2c6229aadf97d65d749ee6962047df512a5024 (diff) | |
download | org.eclipse.cdt-38a084ce6dac1515bb299fbea16f5b68e9829638.tar.gz org.eclipse.cdt-38a084ce6dac1515bb299fbea16f5b68e9829638.tar.xz org.eclipse.cdt-38a084ce6dac1515bb299fbea16f5b68e9829638.zip |
Bug 500000 - Added proper formatting for lambda expressions
Change-Id: Ia530b00f3710b74d1749978c9c5d23a2d55646f0
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
Diffstat (limited to 'core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal')
2 files changed, 164 insertions, 3 deletions
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<IASTParameterDeclaration> 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$ |