diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java index ae1c0cc4983..17d53908aa8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java @@ -418,6 +418,14 @@ public class MacroExpander { return result; } + private void addImageLocationInfo(int offset, Token t) { + ImageLocationInfo info= createImageLocationInfo(t); + if (info != null) { + info.fTokenOffsetInExpansion= offset; + fImageLocationInfos.add(info); + } + } + private ImageLocationInfo createImageLocationInfo(Token t) { if (fLocationMap != null) { final Object s= t.fSource; @@ -950,20 +958,12 @@ public class MacroExpander { case CPreprocessor.tEXPANDED_IDENTIFIER: t.setType(IToken.tIDENTIFIER); if (createImageLocations) { - ImageLocationInfo info= createImageLocationInfo(t); - if (info != null) { - info.fTokenOffsetInExpansion= offset; - fImageLocationInfos.add(info); - } + addImageLocationInfo(offset, t); } break; case IToken.tIDENTIFIER: if (createImageLocations) { - ImageLocationInfo info= createImageLocationInfo(t); - if (info != null) { - info.fTokenOffsetInExpansion= offset; - fImageLocationInfos.add(info); - } + addImageLocationInfo(offset, t); } break; @@ -978,6 +978,12 @@ public class MacroExpander { t.setOffset(offset, offset + t.getLength()); t.setNext(null); return; + + default: + if (createImageLocations && t.fSource instanceof CPreprocessor) { + addImageLocationInfo(offset, t); + } + break; } t.setOffset(offset, ++offset); l= t; 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 3a9d9d64d8e..19ba1afcff7 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 @@ -66,6 +66,7 @@ import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; import org.eclipse.cdt.core.dom.ast.IASTNullStatement; import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; @@ -143,6 +144,7 @@ import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator; import org.eclipse.cdt.core.formatter.DefaultCodeFormatterConstants; import org.eclipse.cdt.core.formatter.DefaultCodeFormatterOptions; import org.eclipse.cdt.core.parser.IToken; +import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.formatter.align.Alignment; import org.eclipse.cdt.internal.formatter.align.AlignmentException; @@ -232,6 +234,28 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } } + private static class TokenRange { + private int offset; + private int endOffset; + + TokenRange(int offset, int endOffset) { + this.offset = offset; + this.endOffset = endOffset; + } + + int getOffset() { + return offset; + } + + int getEndOffset() { + return endOffset; + } + + int getLength() { + return endOffset - offset; + } + } + /** * Formats a trailing semicolon. * @see #formatList(List, ListOptions, boolean, boolean, Runnable) @@ -360,6 +384,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, private final Scribe scribe; private boolean fInsideFor; + private boolean fInsideMacroArguments; private boolean fExpectSemicolonAfterDeclaration= true; private MultiStatus fStatus; @@ -540,97 +565,79 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, if (fileLocation != null) { scribe.printRaw(fileLocation.getNodeOffset(), fileLocation.getNodeLength()); } - fileLocation = macroExpansion.getFileLocation(); - scribe.printNextToken(Token.tLPAREN); IMacroBinding binding = (IMacroBinding) name.resolveBinding(); - if (preferences.insert_space_after_opening_paren_in_method_invocation) { - scribe.space(); + List arguments = getMacroArguments(binding.getParameterList().length); + + final ListOptions options= new ListOptions(preferences.alignment_for_arguments_in_method_invocation); + options.fSeparatorToken = Token.tCOMMA; + 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.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; + fInsideMacroArguments = true; + try { + formatList(arguments, options, true, false, scribe.takeTailFormatter()); + } finally { + fInsideMacroArguments = false; } - final int continuationIndentation = preferences.continuation_indentation; - Alignment listAlignment = scribe.createAlignment( - Alignment.MACRO_ARGUMENTS, - preferences.alignment_for_arguments_in_method_invocation, - Alignment.R_OUTERMOST, - binding.getParameterList().length, - getCurrentPosition(), - continuationIndentation, - false); - scribe.enterAlignment(listAlignment); - boolean ok = false; - do { - try { - int fragment = 0; - scribe.alignFragment(listAlignment, fragment); - int parenLevel= 0; - boolean done = false; - while (!done) { - boolean hasWhitespace= scribe.printComment(); - int token = peekNextToken(); - switch (token) { - case Token.tLPAREN: - ++parenLevel; - scribe.printNextToken(token, hasWhitespace); - break; - case Token.tRPAREN: - if (parenLevel > 0) { - --parenLevel; - scribe.printNextToken(token, hasWhitespace); - } else { - if (preferences.insert_space_before_closing_paren_in_method_invocation) { - scribe.space(); - } - scribe.printNextToken(token); - done = true; - } - break; - case Token.tCOMMA: - if (parenLevel == 0 && preferences.insert_space_before_comma_in_method_invocation_arguments) { - scribe.space(); - } - scribe.printNextToken(token); - if (parenLevel == 0) { - if (preferences.insert_space_after_comma_in_method_invocation_arguments) { - scribe.space(); - } - scribe.printComment(); - ++fragment; - if (fragment < listAlignment.fragmentCount) { - scribe.alignFragment(listAlignment, fragment); - } - } - break; - case Token.tSTRING: - case Token.tLSTRING: - case Token.tRSTRING: - boolean needSpace= hasWhitespace; - while (true) { - scribe.printNextToken(token, needSpace); - if (peekNextToken() != token) { - break; - } - scribe.printCommentPreservingNewLines(); - needSpace= true; - } - break; - case Token.tBADCHAR: - // Avoid infinite loop if something bad happened. - scribe.exitAlignment(listAlignment, true); - return; - default: - scribe.printNextToken(token, hasWhitespace); - } + } + + /** + * Scans macro expansion arguments starting from the current position and returns a list of + * arguments where each argument is represented either by a {@link IASTNode} or, if not + * possible, by a {@link TokenRange}. + */ + private List getMacroArguments(int expectedNumberOfArguments) { + List argumentRanges = new ArrayList(expectedNumberOfArguments); + TokenRange currentArgument = null; + localScanner.resetTo(getCurrentPosition(), scribe.scannerEndPosition); + localScanner.getNextToken(); // Skip the opening parenthesis. + int parenLevel = 0; + int token; + while ((token = localScanner.getNextToken()) != Token.tBADCHAR) { + int tokenOffset = localScanner.getCurrentTokenStartPosition(); + if (parenLevel == 0 && (token == Token.tCOMMA || token == Token.tRPAREN)) { + if (currentArgument != null) { + argumentRanges.add(currentArgument); + currentArgument = null; + } else { + argumentRanges.add(new TokenRange(tokenOffset, tokenOffset)); } - int token = peekNextToken(); - if (token == Token.tSEMI) { - scribe.printNextToken(token); - scribe.startNewLine(); + if (token == Token.tRPAREN) + break; + } else { + int tokenEndOffset = localScanner.getCurrentPosition(); + if (currentArgument == null) { + currentArgument = new TokenRange(tokenOffset, tokenEndOffset); + } else { + currentArgument.endOffset = tokenEndOffset; + } + + switch (token) { + case Token.tLPAREN: + ++parenLevel; + break; + case Token.tRPAREN: + if (parenLevel > 0) + --parenLevel; + break; } - ok = true; - } catch (AlignmentException e) { - scribe.redoAlignment(e); } - } while (!ok); - scribe.exitAlignment(listAlignment, true); + } + + List arguments = new ArrayList(argumentRanges.size()); + IASTNodeSelector nodeSelector = ast.getNodeSelector(null); + for (TokenRange argument : argumentRanges) { + IASTNode node = nodeSelector.findNodeInExpansion(argument.getOffset(), argument.getLength()); + if (node != null) { + arguments.add(node); + } else { + arguments.add(argument); + } + } + return arguments; } @Override @@ -2077,15 +2084,16 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, /** * Format a given list of elements according alignment options. * - * @param elements the elements to format + * @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. */ - private void formatList(List elements, ListOptions options, - boolean encloseInParen, boolean addEllipsis, Runnable tailFormatter) { + private void formatList(List elements, ListOptions options, boolean encloseInParen, + boolean addEllipsis, Runnable tailFormatter) { if (encloseInParen) scribe.printNextToken(Token.tLPAREN, options.fSpaceBeforeOpeningParen); @@ -2118,22 +2126,26 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, try { int i; for (i = 0; i < elementsLength; i++) { - final IASTNode node= elements.get(i); + final Object element = elements.get(i); if (i < elementsLength - 1) { scribe.setTailFormatter( new TrailingTokenFormatter(options.fSeparatorToken, - findTokenAfterNode(options.fSeparatorToken, node), + findTokenAfterNodeOrTokenRange(options.fSeparatorToken, element), options.fSpaceBeforeSeparator, options.fSpaceAfterSeparator)); } else { scribe.setTailFormatter(tailFormatter); } scribe.alignFragment(alignment, i); - if (node instanceof ICPPASTConstructorChainInitializer) { - // Constructor chain initializer is a special case. - visit((ICPPASTConstructorChainInitializer) node); + if (element instanceof IASTNode) { + if (element instanceof ICPPASTConstructorChainInitializer) { + // Constructor chain initializer is a special case. + visit((ICPPASTConstructorChainInitializer) element); + } else { + ((IASTNode) element).accept(this); + } } else { - node.accept(this); + formatTokenRange((TokenRange) element); } if (i < elementsLength - 1) { scribe.runTailFormatter(); @@ -2163,6 +2175,15 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } } + private void formatTokenRange(TokenRange tokenRange) { + scribe.restartAtOffset(tokenRange.getOffset()); + while (getCurrentPosition() < tokenRange.getEndOffset()) { + boolean hasWhitespace= scribe.printComment(); + int token = peekNextToken(); + scribe.printNextToken(token, hasWhitespace); + } + } + private int visit(ICPPASTTryBlockStatement node) { scribe.printNextToken(Token.t_try, scribe.printComment()); final IASTStatement tryBody= node.getTryBody(); @@ -3782,18 +3803,23 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } IASTNodeLocation[] locations= node.getNodeLocations(); if (locations.length == 0) { - } else if (locations[0] instanceof IASTMacroExpansionLocation) { + } else if (!fInsideMacroArguments && locations[0] instanceof IASTMacroExpansionLocation) { IASTMacroExpansionLocation location = (IASTMacroExpansionLocation) locations[0]; if (locations.length <= 2 && node instanceof IASTStatement) { IASTPreprocessorMacroExpansion macroExpansion = location.getExpansion(); IASTFileLocation macroLocation = macroExpansion.getFileLocation(); - IASTFileLocation nodeLocation = node.getFileLocation(); + IASTFileLocation nodeLocation = getFileLocation(node); if (macroLocation.getNodeOffset() >= getCurrentPosition() && !scribe.shouldSkip(macroLocation.getNodeOffset()) && (nodeLocation.getNodeOffset() + nodeLocation.getNodeLength() == macroLocation.getNodeOffset() + macroLocation.getNodeLength() || locations.length == 2 && isSemicolonLocation(locations[1])) && isFunctionStyleMacroExpansion(macroExpansion)) { + if (locations.length == 2 && isSemicolonLocation(locations[1])) { + scribe.setTailFormatter( + new TrailingTokenFormatter(Token.tSEMI, locations[1].getNodeOffset(), + preferences.insert_space_before_semicolon, false)); + } formatFunctionStyleMacroExpansion(macroExpansion); return false; } @@ -3808,12 +3834,16 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, return false; } } else { - IASTFileLocation fileLocation= node.getFileLocation(); + IASTFileLocation fileLocation= getFileLocation(node); scribe.restartAtOffset(fileLocation.getNodeOffset()); } return true; } + private IASTFileLocation getFileLocation(IASTNode node) { + return fInsideMacroArguments ? ((ASTNode) node).getImageLocation() : node.getFileLocation(); + } + /** * Formatting of node is complete. Undo skip region if any. * @@ -3824,7 +3854,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, return; } if (scribe.skipRange()) { - IASTFileLocation fileLocation= node.getFileLocation(); + IASTFileLocation fileLocation= getFileLocation(node); if (fileLocation != null) { int nodeEndOffset= fileLocation.getNodeOffset() + fileLocation.getNodeLength(); scribe.restartAtOffset(nodeEndOffset); @@ -3845,7 +3875,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, if (node instanceof IASTProblemHolder || node instanceof IASTTranslationUnit) { return; } - IASTFileLocation fileLocation= node.getFileLocation(); + IASTFileLocation fileLocation= getFileLocation(node); if (fileLocation == null) { return; } @@ -3881,7 +3911,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } private void skipNode(IASTNode node) { - final IASTNodeLocation fileLocation= node.getFileLocation(); + final IASTNodeLocation fileLocation= getFileLocation(node); if (fileLocation != null && fileLocation.getNodeLength() > 0) { final int endOffset= fileLocation.getNodeOffset() + fileLocation.getNodeLength(); final int currentOffset= getCurrentPosition(); @@ -3893,7 +3923,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } private void skipToNode(IASTNode node) { - final IASTNodeLocation fileLocation= node.getFileLocation(); + final IASTNodeLocation fileLocation= getFileLocation(node); if (fileLocation != null) { final int startOffset= fileLocation.getNodeOffset(); final int currentOffset= getCurrentPosition(); @@ -3905,7 +3935,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } private void skipNonWhitespaceToNode(IASTNode node) { - final IASTNodeLocation fileLocation= node.getFileLocation(); + final IASTNodeLocation fileLocation= getFileLocation(node); if (fileLocation != null) { final int startOffset= fileLocation.getNodeOffset(); final int nextTokenOffset= getNextTokenOffset(); @@ -3985,18 +4015,22 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } } - private static boolean startsWithMacroExpansion(IASTNode node) { + private boolean startsWithMacroExpansion(IASTNode node) { + if (fInsideMacroArguments) + return false; IASTNodeLocation[] locations= node.getNodeLocations(); if (!(node instanceof IASTProblemHolder) && locations.length != 0 && locations[0] instanceof IASTMacroExpansionLocation) { IASTFileLocation expansionLocation= locations[0].asFileLocation(); - IASTFileLocation fileLocation= node.getFileLocation(); + IASTFileLocation fileLocation= getFileLocation(node); return expansionLocation.getNodeOffset() == fileLocation.getNodeOffset(); } return false; } - private static boolean endsWithMacroExpansion(IASTNode node) { + private boolean endsWithMacroExpansion(IASTNode node) { + if (fInsideMacroArguments) + return false; IASTNodeLocation[] locations= node.getNodeLocations(); if (!(node instanceof IASTProblemHolder) && locations.length != 0 && locations[locations.length - 1] instanceof IASTMacroExpansionLocation) { @@ -4005,13 +4039,17 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, return false; } - private static boolean enclosedInMacroExpansion(IASTNode node) { + private boolean enclosedInMacroExpansion(IASTNode node) { + if (fInsideMacroArguments) + return false; IASTNodeLocation[] locations= node.getNodeLocations(); return locations.length == 1 && locations[0] instanceof IASTMacroExpansionLocation; } - private static boolean withinMacroExpansion(IASTNode node, int offset) { - IASTFileLocation loc = node.getFileLocation(); + private boolean withinMacroExpansion(IASTNode node, int offset) { + if (fInsideMacroArguments) + return false; + IASTFileLocation loc = getFileLocation(node); if (loc == null || offset < loc.getNodeOffset() || offset >= loc.getNodeOffset() + loc.getNodeLength()) { return false; } @@ -4061,9 +4099,9 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, * normally separated by other tokens this is an indication that they were produced by the same * macro expansion. */ - private static boolean doNodeLocationsOverlap(IASTNode node1, IASTNode node2) { - IASTFileLocation loc1 = node1.getFileLocation(); - IASTFileLocation loc2 = node2.getFileLocation(); + private boolean doNodeLocationsOverlap(IASTNode node1, IASTNode node2) { + IASTFileLocation loc1 = getFileLocation(node1); + IASTFileLocation loc2 = getFileLocation(node2); return loc1.getNodeOffset() + loc1.getNodeLength() > loc2.getNodeOffset() && loc1.getNodeOffset() < loc2.getNodeOffset() + loc2.getNodeLength(); } @@ -4073,16 +4111,16 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, * separated by other tokens this is an indication that they were produced by the same macro * expansion. */ - private static boolean doNodesHaveSameOffset(IASTNode node1, IASTNode node2) { + private boolean doNodesHaveSameOffset(IASTNode node1, IASTNode node2) { return nodeOffset(node1) == nodeOffset(node2); } - private static int nodeOffset(IASTNode node) { - return node.getFileLocation().getNodeOffset(); + private int nodeOffset(IASTNode node) { + return getFileLocation(node).getNodeOffset(); } - private static int nodeEndOffset(IASTNode node) { - IASTFileLocation loc = node.getFileLocation(); + private int nodeEndOffset(IASTNode node) { + IASTFileLocation loc = getFileLocation(node); return loc.getNodeOffset() + loc.getNodeLength(); } @@ -4407,14 +4445,19 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } private int findTokenWithinNode(int tokenType, IASTNode node) { - IASTFileLocation location = node.getFileLocation(); + IASTFileLocation location = getFileLocation(node); int endOffset = location.getNodeOffset() + location.getNodeLength(); return scribe.findToken(tokenType, endOffset); } - private int findTokenAfterNode(int tokenType, IASTNode node) { - IASTFileLocation location = node.getFileLocation(); - int startOffset = location.getNodeOffset() + location.getNodeLength(); + private int findTokenAfterNodeOrTokenRange(int tokenType, Object nodeOrTokenRange) { + int startOffset; + if (nodeOrTokenRange instanceof IASTNode) { + IASTFileLocation location = getFileLocation((IASTNode) nodeOrTokenRange); + startOffset = location.getNodeOffset() + location.getNodeLength(); + } else { + startOffset = ((TokenRange) nodeOrTokenRange).getEndOffset(); + } return scribe.findToken(tokenType, startOffset, scribe.scannerEndPosition - 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 f2ef0f47940..f1032773097 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 @@ -1765,7 +1765,6 @@ public class CodeFormatterTest extends BaseUITestCase { // } //#endif //} - public void testMacroAsFunctionArguments_Bug253039() throws Exception { assertFormatterResult(); } @@ -1901,6 +1900,33 @@ public class CodeFormatterTest extends BaseUITestCase { assertFormatterResult(); } + //#define MACRO(a,b) f(a,b) + //void f(bool b, int i); + //int function_with_loooooooooooooooong_name(); + //int another_function_with_loooooong_name(); + // + //void test(){ + // MACRO("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"=="bbbbbbbbbbbbbbbbbbbbbbbbbbb",function_with_loooooooooooooooong_name()+another_function_with_loooooong_name()); + //} + + //#define MACRO(a,b) f(a,b) + //void f(bool b, int i); + //int function_with_loooooooooooooooong_name(); + //int another_function_with_loooooong_name(); + // + //void test() { + // MACRO("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + // == "bbbbbbbbbbbbbbbbbbbbbbbbbbb", + // function_with_loooooooooooooooong_name() + // + another_function_with_loooooong_name()); + //} + public void testMacroArguments() throws Exception { + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, CCorePlugin.SPACE); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION, + Integer.toString(Alignment.M_COMPACT_SPLIT | Alignment.M_INDENT_ON_COLUMN)); + assertFormatterResult(); + } + //bool member __attribute__ ((__unused__)) = false; //bool member __attribute__ ((__unused__)) = false; @@ -2892,7 +2918,7 @@ public class CodeFormatterTest extends BaseUITestCase { //void f() { // if (1) { // } - // IF(1>0); + // IF(1 > 0); //} public void testMacroAfterCompoundStatement_Bug356690() throws Exception { assertFormatterResult();