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 1000370213b..034819153f1 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 @@ -170,9 +170,10 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, private static class ListOptions { final int fMode; + int fSeparatorToken = Token.tCOMMA; boolean fInsertNewLineBeforeListIfNecessary; - boolean fSpaceBeforeComma; - boolean fSpaceAfterComma = true; + boolean fSpaceBeforeSeparator; + boolean fSpaceAfterSeparator = true; boolean fSpaceAfterOpeningParen; boolean fSpaceBeforeClosingParen; boolean fSpaceBetweenEmptyParen; @@ -228,9 +229,11 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, * Formats a trailing comma. * @see #formatList(List, ListOptions, boolean, boolean, Runnable) */ - class TrailingCommaFormatter extends TrailingTokenFormatter { - TrailingCommaFormatter(boolean spaceBeforeComma, boolean spaceAfterComma) { - super(Token.tCOMMA, scribe.findToken(Token.tCOMMA), spaceBeforeComma, spaceAfterComma); + class TrailingSeparatorFormatter extends TrailingTokenFormatter { + TrailingSeparatorFormatter(int separatorToken, boolean spaceBeforeSeparator, + boolean spaceAfterSeparator) { + super(separatorToken, scribe.findToken(separatorToken), spaceBeforeSeparator, + spaceAfterSeparator); } } @@ -1193,8 +1196,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, final ICPPASTTemplateParameter[] templateParameters= node.getTemplateParameters(); if (templateParameters.length > 0) { final ListOptions options= new ListOptions(Alignment.M_COMPACT_SPLIT); - options.fSpaceAfterComma= preferences.insert_space_after_comma_in_template_parameters; - options.fSpaceBeforeComma= preferences.insert_space_before_comma_in_template_parameters; + options.fSpaceAfterSeparator= preferences.insert_space_after_comma_in_template_parameters; + options.fSpaceBeforeSeparator= preferences.insert_space_before_comma_in_template_parameters; formatList(Arrays.asList(templateParameters), options, false, false, null); } scribe.printNextToken(new int[] { Token.tGT, Token.tSHIFTR }, preferences.insert_space_before_closing_angle_bracket_in_template_parameters); @@ -1462,8 +1465,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, 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.fSpaceBeforeComma= preferences.insert_space_before_comma_in_method_declaration_parameters; - options.fSpaceAfterComma= preferences.insert_space_after_comma_in_method_declaration_parameters; + 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; return options; } @@ -1609,8 +1612,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } } else { final ListOptions options= new ListOptions(preferences.alignment_for_declarator_list); - options.fSpaceAfterComma= preferences.insert_space_after_comma_in_declarator_list; - options.fSpaceBeforeComma= preferences.insert_space_before_comma_in_declarator_list; + options.fSpaceAfterSeparator= preferences.insert_space_after_comma_in_declarator_list; + options.fSpaceBeforeSeparator= preferences.insert_space_before_comma_in_declarator_list; formatList(declarators, options, false, false, tailFormatter); } } @@ -1632,8 +1635,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, final ICPPASTTemplateParameter[] templateParameters= node.getTemplateParameters(); if (templateParameters.length > 0) { final ListOptions options= new ListOptions(Alignment.M_COMPACT_SPLIT); - options.fSpaceAfterComma= preferences.insert_space_after_comma_in_template_parameters; - options.fSpaceBeforeComma= preferences.insert_space_before_comma_in_template_parameters; + options.fSpaceAfterSeparator= preferences.insert_space_after_comma_in_template_parameters; + options.fSpaceBeforeSeparator= preferences.insert_space_before_comma_in_template_parameters; formatList(Arrays.asList(templateParameters), options, false, false, null); } scribe.printNextToken(new int[] { Token.tGT, Token.tSHIFTR }, preferences.insert_space_before_closing_angle_bracket_in_template_parameters); @@ -1805,8 +1808,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } catch (ExpansionOverlapsBoundaryException exc) { } final ListOptions options= new ListOptions(preferences.alignment_for_base_clause_in_type_declaration); - options.fSpaceAfterComma= preferences.insert_space_after_comma_in_base_types; - options.fSpaceBeforeComma= preferences.insert_space_before_comma_in_base_types; + options.fSpaceAfterSeparator= preferences.insert_space_after_comma_in_base_types; + options.fSpaceBeforeSeparator= preferences.insert_space_before_comma_in_base_types; formatList(baseSpecifiers, options, false, false, null); } @@ -1955,15 +1958,15 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, final IASTEnumerator[] enumerators= node.getEnumerators(); final ListOptions options= new ListOptions(preferences.alignment_for_enumerator_list); - options.fSpaceBeforeComma= preferences.insert_space_before_comma_in_enum_declarations; - options.fSpaceAfterComma= preferences.insert_space_after_comma_in_enum_declarations; + options.fSpaceBeforeSeparator= preferences.insert_space_before_comma_in_enum_declarations; + options.fSpaceAfterSeparator= preferences.insert_space_after_comma_in_enum_declarations; options.fContinuationIndentation= enumIndent == headerIndent ? 1 : 0; formatList(Arrays.asList(enumerators), options, false, false, null); // Handle trailing comma if (peekNextToken() == Token.tCOMMA) { - scribe.printNextToken(Token.tCOMMA, options.fSpaceBeforeComma); - if (options.fSpaceAfterComma) { + scribe.printNextToken(Token.tCOMMA, options.fSpaceBeforeSeparator); + if (options.fSpaceAfterSeparator) { scribe.space(); } } @@ -2043,8 +2046,9 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, final IASTNode node= elements.get(i); if (i < alignment.fragmentCount - 1) { scribe.setTailFormatter( - new TrailingCommaFormatter(options.fSpaceBeforeComma, - options.fSpaceAfterComma)); + new TrailingSeparatorFormatter(options.fSeparatorToken, + options.fSpaceBeforeSeparator, + options.fSpaceAfterSeparator)); } else { scribe.setTailFormatter(tailFormatter); } @@ -2061,11 +2065,11 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } if (addEllipsis) { if (i > 0) { - scribe.printNextToken(Token.tCOMMA, options.fSpaceBeforeComma); + scribe.printNextToken(options.fSeparatorToken, options.fSpaceBeforeSeparator); scribe.printTrailingComment(); } scribe.alignFragment(alignment, i); - if (i > 0 && options.fSpaceAfterComma) { + if (i > 0 && options.fSpaceAfterSeparator) { scribe.space(); } scribe.printNextToken(Token.tELIPSE); @@ -2250,8 +2254,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, options.fSpaceAfterOpeningParen= preferences.insert_space_after_opening_paren_in_method_invocation; options.fSpaceBeforeClosingParen= preferences.insert_space_before_closing_paren_in_method_invocation; options.fSpaceBetweenEmptyParen= preferences.insert_space_between_empty_parens_in_method_invocation; - options.fSpaceBeforeComma= preferences.insert_space_before_comma_in_method_invocation_arguments; - options.fSpaceAfterComma= preferences.insert_space_after_comma_in_method_invocation_arguments; + options.fSpaceBeforeSeparator= preferences.insert_space_before_comma_in_method_invocation_arguments; + options.fSpaceAfterSeparator= preferences.insert_space_after_comma_in_method_invocation_arguments; options.fTieBreakRule = Alignment.R_OUTERMOST; formatList(expressions, options, true, false, scribe.getTailFormatter()); } @@ -2259,8 +2263,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, private int visit(IASTExpressionList node) { final List expressions = Arrays.asList(node.getExpressions()); final ListOptions options= new ListOptions(preferences.alignment_for_expression_list); - options.fSpaceBeforeComma= preferences.insert_space_before_comma_in_expression_list; - options.fSpaceAfterComma= preferences.insert_space_after_comma_in_expression_list; + options.fSpaceBeforeSeparator= preferences.insert_space_before_comma_in_expression_list; + options.fSpaceAfterSeparator= preferences.insert_space_after_comma_in_expression_list; formatList(expressions, options, false, false, null); return PROCESS_SKIP; } @@ -2426,15 +2430,15 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } final ListOptions options= new ListOptions(preferences.alignment_for_expressions_in_initializer_list); - options.fSpaceBeforeComma= preferences.insert_space_before_comma_in_initializer_list; - options.fSpaceAfterComma= preferences.insert_space_after_comma_in_initializer_list; + options.fSpaceBeforeSeparator= preferences.insert_space_before_comma_in_initializer_list; + options.fSpaceAfterSeparator= preferences.insert_space_after_comma_in_initializer_list; options.fContinuationIndentation= preferences.continuation_indentation_for_initializer_list; formatList(initializers, options, false, false, null); // handle trailing comma if (peekNextToken() == Token.tCOMMA) { - scribe.printNextToken(Token.tCOMMA, options.fSpaceBeforeComma); - if (options.fSpaceAfterComma) { + scribe.printNextToken(Token.tCOMMA, options.fSpaceBeforeSeparator); + if (options.fSpaceAfterSeparator) { scribe.space(); } } @@ -2525,10 +2529,20 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, if (enclosedInMacroExpansion(node)) { return PROCESS_SKIP; } + if (doNodeLocationsOverlap(node.getOperand1(), node.getOperand2())) { + // Overlapping of operands is possible if the central part of the binary expression is + // a result of macro expansion. There is no need to print the operator in such case, + // so we simply delegate to each of the operands. + node.getOperand1().accept(this); + node.getOperand2().accept(this); + return PROCESS_SKIP; + } if (isAssignment(node)) { return formatAssignment(node); } + Runnable tailFormatter = scribe.getTailFormatter(); + Alignment expressionAlignment= scribe.createAlignment( Alignment.BINARY_EXPRESSION, preferences.alignment_for_binary_expression, @@ -2545,10 +2559,10 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, op1.accept(this); scribe.printTrailingComment(); - scribe.alignFragment(expressionAlignment, 1); - // In case of macros we may have already passed the operator position. if (scribe.scanner.getCurrentPosition() < node.getOperand2().getFileLocation().getNodeOffset()) { + scribe.alignFragment(expressionAlignment, 1); + // Operator final int nextToken= peekNextToken(); // In case of C++ alternative operators, like 'and', 'not', etc. a space @@ -2571,6 +2585,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, final IASTExpression op2= node.getOperand2(); op2.accept(this); + if (tailFormatter != null) + tailFormatter.run(); ok = true; } catch (AlignmentException e) { scribe.redoAlignment(e); @@ -3203,8 +3219,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, final IASTNode[] templateArguments= node.getTemplateArguments(); if (templateArguments.length > 0) { final ListOptions options= new ListOptions(Alignment.M_COMPACT_SPLIT); - options.fSpaceAfterComma= preferences.insert_space_after_comma_in_template_arguments; - options.fSpaceBeforeComma= preferences.insert_space_before_comma_in_template_arguments; + options.fSpaceAfterSeparator= preferences.insert_space_after_comma_in_template_arguments; + options.fSpaceBeforeSeparator= preferences.insert_space_before_comma_in_template_arguments; formatList(Arrays.asList(templateArguments), options, false, false, null); } if (peekNextToken() == Token.tSHIFTR) { @@ -3738,6 +3754,13 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, return false; } + private static boolean doNodeLocationsOverlap(IASTNode node1, IASTNode node2) { + IASTFileLocation loc1 = node1.getFileLocation(); + IASTFileLocation loc2 = node2.getFileLocation(); + return loc1.getNodeOffset() + loc1.getNodeLength() > loc2.getNodeOffset() && + loc1.getNodeOffset() < loc2.getNodeOffset() + loc2.getNodeLength(); + } + private void formatBlock(IASTCompoundStatement block, String block_brace_position, boolean insertSpaceBeforeOpeningBrace, boolean indentStatements) { formatBlockOpening(block, block_brace_position, insertSpaceBeforeOpeningBrace); 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 8cb7927df0a..d96b64338ba 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 @@ -2043,24 +2043,64 @@ public class CodeFormatterTest extends BaseUITestCase { //#define B() { if (1+2) b(); } //void g() { - // if (1) { - // B(); - // } else { - // x(); - // } - // z(); + //if (1) { + //B(); + //} else { + //x(); + //} + //z(); //} //#define B() { if (1+2) b(); } //void g() { - // if (1) { - // B(); - // } else { - // x(); - // } - // z(); + // if (1) { + // B(); + // } else { + // x(); + // } + // z(); //} - public void testBinaryExpressionInMacro() throws Exception { + public void testBinaryExpressionInMacro_1() throws Exception { + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, CCorePlugin.SPACE); + assertFormatterResult(); + } + + //class Stream { + //Stream& operator <<(const char* s); + //}; + // + //class Voidifier { + //public: + //Voidifier(); + //void operator &(Stream&); + //}; + // + //Stream stream; + //#define STREAM Voidifier() & stream + // + //void test() { + //STREAM << "text text test text " << "text text " << "text text text text te"; + //} + + //class Stream { + // Stream& operator <<(const char* s); + //}; + // + //class Voidifier { + //public: + // Voidifier(); + // void operator &(Stream&); + //}; + // + //Stream stream; + //#define STREAM Voidifier() & stream + // + //void test() { + // STREAM << "text text test text " << "text text " + // << "text text text text te"; + //} + public void testBinaryExpressionInMacro_2() throws Exception { + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, CCorePlugin.SPACE); assertFormatterResult(); }