blob: f7f0294d75a773ea3a13107877d2f674bf802b28 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2017 Wind River Systems, Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Anton Leherbauer (Wind River Systems) - initial API and implementation
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.formatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EmptyStackException;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import java.util.function.Predicate;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.ExpansionOverlapsBoundaryException;
import org.eclipse.cdt.core.dom.ast.IASTASMDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
import org.eclipse.cdt.core.dom.ast.IASTAttributeOwner;
import org.eclipse.cdt.core.dom.ast.IASTAttributeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
import org.eclipse.cdt.core.dom.ast.IASTCaseStatement;
import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
import org.eclipse.cdt.core.dom.ast.IASTContinueStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTDefaultStatement;
import org.eclipse.cdt.core.dom.ast.IASTDoStatement;
import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpressionList;
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
import org.eclipse.cdt.core.dom.ast.IASTFieldDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTInitializerList;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
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;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElifStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElseStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorEndifStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfdefStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfndefStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTProblemExpression;
import org.eclipse.cdt.core.dom.ast.IASTProblemHolder;
import org.eclipse.cdt.core.dom.ast.IASTProblemStatement;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdInitializerExpression;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
import org.eclipse.cdt.core.dom.ast.c.ICASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTDesignatedInitializer;
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;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDecltypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDesignatedInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDesignator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
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;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTPointerToMember;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplatedTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTryBlockStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisitor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTWhileStatement;
import org.eclipse.cdt.core.dom.ast.gnu.IGCCASTAttributeList;
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.core.parser.util.IUnaryPredicate;
import org.eclipse.cdt.core.parser.util.InstanceOfPredicate;
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;
import org.eclipse.cdt.internal.formatter.scanner.Scanner;
import org.eclipse.cdt.internal.formatter.scanner.Token;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.text.Position;
import org.eclipse.text.edits.TextEdit;
/**
* This class is responsible for formatting C/C++ source code.
* Some heuristic is applied in case of syntax errors or other problems
* to skip those areas, but because of incomplete location information
* the formatting may fail. The reason of the failure is logged.
*
* @since 4.0
*/
public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, ICASTVisitor {
private static boolean DEBUG = Boolean
.parseBoolean(Platform.getDebugOption("org.eclipse.cdt.core/debug/formatter")); //$NON-NLS-1$
private static class ASTProblemException extends RuntimeException {
ASTProblemException(IASTProblem problem) {
super(problem.getMessageWithLocation());
}
}
private static class ListOptions {
final int fMode;
int fSeparatorToken = Token.tCOMMA;
boolean fSpaceBeforeSeparator;
boolean fSpaceAfterSeparator = true;
boolean fSpaceAfterOpeningParen;
boolean fSpaceBeforeClosingParen;
boolean fSpaceBetweenEmptyParen;
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;
}
}
/**
* Formats a given token at a given position.
* @see #formatList(List, ListOptions, boolean, boolean, Runnable)
*/
private class TrailingTokenFormatter implements Runnable {
private final int tokenType;
private final int tokenPosition;
private final boolean spaceBeforeToken;
private final boolean spaceAfterToken;
TrailingTokenFormatter(int tokenType, int tokenPosition, boolean spaceBeforeToken, boolean spaceAfterToken) {
this.tokenType = tokenType;
this.tokenPosition = tokenPosition;
this.spaceBeforeToken = spaceBeforeToken;
this.spaceAfterToken = spaceAfterToken;
}
TrailingTokenFormatter(int tokenType, IASTNode containingNode, boolean spaceBeforeToken,
boolean spaceAfterToken) {
this(tokenType, findTokenWithinNode(tokenType, containingNode), spaceBeforeToken, spaceAfterToken);
}
@Override
public void run() {
int offset = scribe.scanner.getCurrentPosition();
if (tokenPosition < 0 || offset > tokenPosition)
return;
if (offset < tokenPosition)
scribe.restartAtOffset(tokenPosition);
int token = peekNextToken();
if (token == tokenType) {
scribe.undoSpace();
scribe.printNextToken(tokenType, spaceBeforeToken);
scribe.printTrailingComment();
if (spaceAfterToken) {
scribe.space();
}
}
}
}
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)
*/
private class TrailingSemicolonFormatter extends TrailingTokenFormatter {
TrailingSemicolonFormatter(IASTNode node) {
super(Token.tSEMI, getLastNodeCharacterPosition(node),
fHasClauseInitStatement ? preferences.insert_space_before_semicolon_in_for
: preferences.insert_space_before_semicolon,
false);
}
}
/**
* Formats the part of a function declaration following the parameter list.
* @see #formatList(List, ListOptions, boolean, boolean, Runnable)
*/
private class FunctionDeclaratorTailFormatter implements Runnable {
private final IASTFunctionDeclarator node;
private final Runnable continuationFormatter;
public FunctionDeclaratorTailFormatter(IASTFunctionDeclarator node, Runnable tailFormatter) {
this.node = node;
this.continuationFormatter = tailFormatter;
}
@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);
token = peekNextToken();
needSpace = true;
}
if (token == Token.t_noexcept || token == Token.t_throw || token == Token.tIDENTIFIER) {
if (node instanceof ICPPASTFunctionDeclarator) {
final IASTTypeId[] exceptionSpecification = ((ICPPASTFunctionDeclarator) node)
.getExceptionSpecification();
if (exceptionSpecification != null && token == Token.t_throw)
formatExceptionSpecification(exceptionSpecification);
final ICPPASTExpression noexceptExpression = ((ICPPASTFunctionDeclarator) node)
.getNoexceptExpression();
if (noexceptExpression != null && token == Token.t_noexcept)
formatExceptionSpecification(noexceptExpression);
}
if (peekNextToken() == Token.tIDENTIFIER) {
Alignment alignment = scribe.createAlignment(Alignment.TRAILING_TEXT, Alignment.M_COMPACT_SPLIT, 1,
scribe.scanner.getCurrentPosition());
scribe.enterAlignment(alignment);
boolean ok = false;
do {
try {
scribe.alignFragment(alignment, 0);
// Skip the rest of the declarator.
scribe.printTrailingComment();
scribe.space();
if (continuationFormatter != null)
continuationFormatter.run();
skipNode(node);
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(alignment, true);
}
} else {
// Skip the rest (=0)
if (needSpace) {
scribe.printTrailingComment();
scribe.space();
}
skipNode(node);
if (continuationFormatter != null)
continuationFormatter.run();
}
}
}
/**
* Formats a trailing semicolon.
* @see #formatList(List, ListOptions, boolean, boolean, Runnable)
*/
private class ClosingParensesisTailFormatter implements Runnable {
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);
}
@Override
public void run() {
int offset = scribe.scanner.getCurrentPosition();
if (parenPosition >= 0 && offset <= parenPosition) {
if (offset < parenPosition)
scribe.restartAtOffset(parenPosition);
scribe.undoSpace();
scribe.printNextToken(token, spaceBeforeClosingParen);
}
if (continuationFormatter != null)
continuationFormatter.run();
}
}
{
shouldVisitNames = true;
shouldVisitDeclarations = true;
shouldVisitInitializers = true;
shouldVisitParameterDeclarations = true;
shouldVisitDeclarators = true;
shouldVisitDeclSpecifiers = true;
shouldVisitDecltypeSpecifiers = true;
shouldVisitExpressions = true;
shouldVisitStatements = true;
shouldVisitTypeIds = true;
shouldVisitEnumerators = true;
shouldVisitTranslationUnit = true;
shouldVisitBaseSpecifiers = true;
shouldVisitNamespaces = true;
shouldVisitTemplateParameters = true;
shouldVisitVirtSpecifiers = true;
}
private final Scanner localScanner;
private List<InactivePosition> fInactivePreprocessorPositions;
final DefaultCodeFormatterOptions preferences;
private final Scribe scribe;
private boolean fHasClauseInitStatement;
private boolean fInsideMacroArguments;
private boolean fExpectSemicolonAfterDeclaration = true;
private MultiStatus fStatus;
private IASTTranslationUnit ast;
public CodeFormatterVisitor(DefaultCodeFormatterOptions preferences, int offset, int length) {
localScanner = new Scanner() {
@Override
public Token nextToken() {
Token t = super.nextToken();
while (t != null && (t.isWhiteSpace() || t.isPreprocessor())) {
t = super.nextToken();
}
return t;
}
};
this.preferences = preferences;
scribe = new Scribe(this, offset, length);
fInactivePreprocessorPositions = Collections.emptyList();
}
/**
* @see org.eclipse.cdt.core.formatter.CodeFormatter#format(int, String, int, int, int, String)
*/
public TextEdit format(String string, IASTTranslationUnit unit) {
// reset the scribe
scribe.reset();
final long startTime = DEBUG ? System.currentTimeMillis() : 0;
final char[] compilationUnitSource = string.toCharArray();
localScanner.setSource(compilationUnitSource);
scribe.initializeScanner(compilationUnitSource);
fInactivePreprocessorPositions = collectInactiveCodePositions(unit);
List<InactivePosition> inactive = collectNoFormatCodePositions(unit);
inactive.addAll(fInactivePreprocessorPositions);
scribe.setSkipInactivePositions(inactive);
fStatus = new MultiStatus(CCorePlugin.PLUGIN_ID, 0, "Formatting problem(s) in '" + unit.getFilePath() + "'", //$NON-NLS-1$//$NON-NLS-2$
null);
try {
unit.accept(this);
} catch (RuntimeException e) {
reportFormattingProblem(e);
if (DEBUG)
return failedToFormat(e);
}
if (DEBUG) {
System.out.println("Formatting time: " + (System.currentTimeMillis() - startTime)); //$NON-NLS-1$
}
return scribe.getRootEdit();
}
/**
* @return the status collected during formatting
*/
IStatus getStatus() {
return fStatus;
}
private TextEdit failedToFormat(RuntimeException e) {
if (DEBUG) {
System.out.println("COULD NOT FORMAT: " + e.getMessage()); //$NON-NLS-1$
System.out.println(scribe.scanner);
System.out.println(scribe);
System.out.flush();
System.err.flush();
e.printStackTrace();
System.err.flush();
}
return null;
}
private void reportFormattingProblem(RuntimeException e) {
String errorMessage = e.getMessage();
if (errorMessage == null) {
errorMessage = "Unknown error"; //$NON-NLS-1$
}
fStatus.add(createStatus(errorMessage, e));
}
private static IStatus createStatus(String msg, Throwable e) {
return new Status(IStatus.WARNING, CCorePlugin.PLUGIN_ID, msg, e);
}
/*
* @see ASTVisitor#visit(IASTTranslationUnit)
*/
@Override
public int visit(IASTTranslationUnit tu) {
ast = tu;
// Fake new line
scribe.lastNumberOfNewLines = 1;
scribe.startNewLine();
final int indentLevel = scribe.indentationLevel;
IASTDeclaration[] decls = tu.getDeclarations();
formatDeclarations(decls, indentLevel);
scribe.printEndOfTranslationUnit();
return PROCESS_SKIP;
}
private void formatDeclarations(IASTDeclaration[] decls, final int indentLevel) {
IASTPreprocessorMacroExpansion[] macroExpansions = ast.getMacroExpansions();
int m = 0;
for (int i = 0; i < decls.length; i++) {
IASTDeclaration declaration = decls[i];
if (!declaration.isPartOfTranslationUnitFile()) {
continue;
}
try {
int pos = getCurrentPosition();
IASTFileLocation declarationLocation = declaration.getFileLocation();
int declarationOffset = declarationLocation.getNodeOffset();
for (; m < macroExpansions.length; m++) {
IASTPreprocessorMacroExpansion macroExpansion = macroExpansions[m];
IASTFileLocation macroLocation = macroExpansion.getFileLocation();
int macroOffset = macroLocation.getNodeOffset();
if (macroOffset > declarationOffset) {
break;
}
int macroEndOffset = macroOffset + macroLocation.getNodeLength();
if (isFunctionStyleMacroExpansion(macroExpansion) && macroOffset >= pos) {
// Find the last declaration overlapping with the macro.
for (int j = i + 1; j < decls.length; j++) {
IASTDeclaration next = decls[j];
if (!next.isPartOfTranslationUnitFile()) {
continue;
}
IASTFileLocation nextLocation = next.getFileLocation();
int nextOffset = nextLocation.getNodeOffset();
if (macroEndOffset <= nextOffset) {
break;
}
i = j;
declaration = next;
declarationLocation = nextLocation;
declarationOffset = declarationLocation.getNodeOffset();
}
int declarationEndOffset = declarationOffset + declarationLocation.getNodeLength();
if (macroEndOffset <= declarationOffset || macroEndOffset >= declarationEndOffset
|| macroEndOffset == declarationEndOffset - 1
&& isSemicolonAtPosition(macroEndOffset)) {
// The function-style macro expansion either doesn't overlap with
// the following declaration, or completely covers one or more
// declarations, with a possible exception for the trailing semicolon
// of the last one. In both cases formatting is driven by the text of
// parameters of the macro, not by the expanded code.
scribe.setTailFormatter(new TrailingTokenFormatter(Token.tSEMI, macroEndOffset,
preferences.insert_space_before_semicolon, false));
formatFunctionStyleMacroExpansion(macroExpansion);
}
}
}
declaration.accept(this);
scribe.startNewLine();
} catch (RuntimeException e) {
// Report, but continue
reportFormattingProblem(e);
if (i < decls.length - 1) {
exitAlignments();
skipToNode(decls[i + 1]);
while (scribe.indentationLevel < indentLevel) {
scribe.indent();
}
while (scribe.indentationLevel > indentLevel) {
scribe.unIndent();
}
}
}
}
}
private boolean isFunctionStyleMacroExpansion(IASTPreprocessorMacroExpansion macroExpansion) {
IASTName name = macroExpansion.getMacroReference();
IMacroBinding binding = (IMacroBinding) name.resolveBinding();
return binding.isFunctionStyle() && binding.getParameterList().length >= 0;
}
private void formatFunctionStyleMacroExpansion(IASTPreprocessorMacroExpansion macroExpansion) {
IASTName name = macroExpansion.getMacroReference();
IASTFileLocation fileLocation = name.getFileLocation();
if (fileLocation != null) {
scribe.printRaw(fileLocation.getNodeOffset(), fileLocation.getNodeLength());
}
IMacroBinding binding = (IMacroBinding) name.resolveBinding();
List<Object> 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;
}
}
/**
* 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<Object> getMacroArguments(int expectedNumberOfArguments) {
List<TokenRange> 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()) != -1) {
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));
}
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;
}
}
}
List<Object> 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
public int visit(IASTDeclaration node) {
if (!enterNode(node)) {
return PROCESS_SKIP;
}
int result = formatDeclaration(node);
exitNode(node);
return result;
}
private int formatDeclaration(IASTDeclaration node) {
int indentLevel = scribe.indentationLevel;
try {
if (node instanceof IASTFunctionDefinition) {
return visit((IASTFunctionDefinition) node);
} else if (node instanceof IASTSimpleDeclaration) {
return visit((IASTSimpleDeclaration) node);
} else if (node instanceof ICPPASTDeductionGuide) {
return visit((ICPPASTDeductionGuide) node);
} else if (node instanceof IASTASMDeclaration) {
return visit((IASTASMDeclaration) node);
} else if (node instanceof ICPPASTVisibilityLabel) {
return visit((ICPPASTVisibilityLabel) node);
} else if (node instanceof ICPPASTNamespaceDefinition) {
return visit((ICPPASTNamespaceDefinition) node);
} else if (node instanceof ICPPASTNamespaceAlias) {
return visit((ICPPASTNamespaceAlias) node);
} else if (node instanceof ICPPASTUsingDeclaration) {
return visit((ICPPASTUsingDeclaration) node);
} else if (node instanceof ICPPASTUsingDirective) {
return visit((ICPPASTUsingDirective) node);
} else if (node instanceof ICPPASTLinkageSpecification) {
return visit((ICPPASTLinkageSpecification) node);
} else if (node instanceof ICPPASTTemplateDeclaration) {
return visit((ICPPASTTemplateDeclaration) node);
} else if (node instanceof ICPPASTTemplateSpecialization) {
return visit((ICPPASTTemplateSpecialization) node);
} else if (node instanceof ICPPASTExplicitTemplateInstantiation) {
return visit((ICPPASTExplicitTemplateInstantiation) node);
} else if (node instanceof IASTProblemDeclaration) {
return visit((IASTProblemDeclaration) node);
} else {
formatRaw(node);
}
} catch (ASTProblemException e) {
if (node instanceof IASTProblemDeclaration) {
throw e;
} else {
skipNode(node);
while (scribe.indentationLevel > indentLevel) {
scribe.unIndent();
}
}
}
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(IASTName)
*/
@Override
public int visit(IASTName node) {
if (!enterNode(node)) {
return PROCESS_SKIP;
}
if (node instanceof ICPPASTQualifiedName) {
visit((ICPPASTQualifiedName) node);
} else if (node instanceof ICPPASTTemplateId) {
visit((ICPPASTTemplateId) node);
} else {
formatRaw(node);
}
exitNode(node);
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(IASTInitializer)
*/
@Override
public int visit(IASTInitializer node) {
if (node instanceof ICPPASTConstructorInitializer) {
return visit((ICPPASTConstructorInitializer) node);
}
if (peekNextToken() == Token.tASSIGN) {
scribe.printNextToken(Token.tASSIGN, preferences.insert_space_before_assignment_operator);
if (preferences.insert_space_after_assignment_operator) {
scribe.space();
}
}
if (!enterNode(node)) {
return PROCESS_SKIP;
}
if (node instanceof IASTEqualsInitializer) {
visit((IASTEqualsInitializer) node);
} else if (node instanceof IASTInitializerList) {
visit((IASTInitializerList) node);
} else if (node instanceof ICASTDesignatedInitializer) {
visit((ICASTDesignatedInitializer) node);
} else if (node instanceof ICPPASTDesignatedInitializer) {
visit((ICPPASTDesignatedInitializer) node);
} else {
formatRaw(node);
}
exitNode(node);
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(IASTParameterDeclaration)
*/
@Override
public int visit(IASTParameterDeclaration node) {
if (!enterNode(node)) {
return PROCESS_SKIP;
}
// decl-specifier
final IASTDeclSpecifier declSpec = node.getDeclSpecifier();
if (declSpec != null) {
declSpec.accept(this);
}
// declarator
final IASTDeclarator declarator = node.getDeclarator();
if (declarator != null) {
boolean needSpace = declarator.getPointerOperators().length > 0 && scribe.printComment();
if (needSpace) {
scribe.space();
}
declarator.accept(this);
}
exitNode(node);
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(IASTDeclarator)
*/
@Override
public int visit(IASTDeclarator node) {
if (!enterNode(node)) {
return PROCESS_SKIP;
}
// Common to all declarators
final IASTPointerOperator[] pointerOperators = node.getPointerOperators();
formatPointers(pointerOperators);
if (node instanceof IASTStandardFunctionDeclarator) {
if (preferences.insert_new_line_before_identifier_in_function_declaration) {
scribe.startNewLine();
} else {
// Preserve newline if not explicitly requested
if (scribe.printCommentPreservingNewLines()) {
scribe.space();
}
}
}
IASTName name = node.getName();
IASTDeclarator nestedDecl = node.getNestedDeclarator();
if (name != null && name.getSimpleID().length != 0 || nestedDecl != null) {
if (node.getPropertyInParent() != IASTDeclarator.NESTED_DECLARATOR && isFirstDeclarator(node)) {
// Preserve non-space between pointer operator and name or nested declarator.
if (pointerOperators.length == 0) {
scribe.space();
} else
scribe.printComment();
}
if (name != null)
name.accept(this);
}
if (nestedDecl != null) {
scribe.printNextToken(Token.tLPAREN, false);
nestedDecl.accept(this);
scribe.printNextToken(Token.tRPAREN, false);
}
if (node instanceof ICPPASTFunctionDeclarator) {
return visit((ICPPASTFunctionDeclarator) node);
} else if (node instanceof IASTStandardFunctionDeclarator) {
visit((IASTStandardFunctionDeclarator) node);
} else if (node instanceof ICASTKnRFunctionDeclarator) {
visit((ICASTKnRFunctionDeclarator) node);
} else if (node instanceof IASTFieldDeclarator) {
visit((IASTFieldDeclarator) node);
} else if (node instanceof IASTArrayDeclarator) {
visit((IASTArrayDeclarator) node);
}
IASTInitializer initializer = node.getInitializer();
if (initializer != null) {
initializer.accept(this);
}
exitNode(node);
return PROCESS_SKIP;
}
/**
* Determine whether the given declarator is the first in a list of declarators (if any).
*
* @param node the declarator node
* @return <code>true</code> if this node is the first in a list
*/
private boolean isFirstDeclarator(IASTDeclarator node) {
IASTNode parent = node.getParent();
if (parent instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration) parent;
return simpleDecl.getDeclarators()[0] == node;
}
return true;
}
/*
* @see ASTVisitor#visit(IASTDeclSpecifier)
*/
@Override
public int visit(IASTDeclSpecifier node) {
if (!enterNode(node)) {
return PROCESS_SKIP;
}
if (node instanceof ICPPASTCompositeTypeSpecifier) {
visit((ICPPASTCompositeTypeSpecifier) node);
} else if (node instanceof ICASTCompositeTypeSpecifier) {
visit((ICASTCompositeTypeSpecifier) node);
} else if (node instanceof IASTElaboratedTypeSpecifier) {
visit((IASTElaboratedTypeSpecifier) node);
} else if (node instanceof IASTEnumerationSpecifier) {
visit((IASTEnumerationSpecifier) node);
} else if (node instanceof IASTSimpleDeclSpecifier) {
visit((IASTSimpleDeclSpecifier) node);
} else if (node instanceof IASTNamedTypeSpecifier) {
visit((IASTNamedTypeSpecifier) node);
} else {
formatRaw(node);
}
exitNode(node);
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(ICPPASTDecltypeSpecifier)
*/
@Override
public int visit(ICPPASTDecltypeSpecifier node) {
formatRaw(node);
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(IASTExpression)
*/
@Override
public int visit(IASTExpression node) {
if (!enterNode(node)) {
return PROCESS_SKIP;
}
if (node instanceof IASTArraySubscriptExpression) {
visit((IASTArraySubscriptExpression) node);
} else if (node instanceof IASTConditionalExpression) {
visit((IASTConditionalExpression) node);
} else if (node instanceof IASTFunctionCallExpression) {
visit((IASTFunctionCallExpression) node);
} else if (node instanceof IASTExpressionList) {
visit((IASTExpressionList) node);
} else if (node instanceof IASTTypeIdExpression) {
visit((IASTTypeIdExpression) node);
} else if (node instanceof IASTBinaryExpression) {
visit((IASTBinaryExpression) node);
} else if (node instanceof IASTLiteralExpression) {
visit((IASTLiteralExpression) node);
} else if (node instanceof IASTIdExpression) {
visit((IASTIdExpression) node);
} else if (node instanceof IASTCastExpression) {
visit((IASTCastExpression) node);
} else if (node instanceof IASTUnaryExpression) {
visit((IASTUnaryExpression) node);
} else if (node instanceof IASTFieldReference) {
visit((IASTFieldReference) node);
} else if (node instanceof IASTTypeIdInitializerExpression) {
visit((IASTTypeIdInitializerExpression) node);
} else if (node instanceof ICPPASTNewExpression) {
visit((ICPPASTNewExpression) node);
} else if (node instanceof ICPPASTDeleteExpression) {
visit((ICPPASTDeleteExpression) node);
} else if (node instanceof ICPPASTSimpleTypeConstructorExpression) {
visit((ICPPASTSimpleTypeConstructorExpression) node);
} else if (node instanceof IASTProblemExpression) {
visit((IASTProblemExpression) node);
} else if (node instanceof ICPPASTLambdaExpression) {
visit((ICPPASTLambdaExpression) node);
} else {
formatRaw(node);
}
exitNode(node);
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,
() -> {
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);
boolean ok = false;
do {
try {
// 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();
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
// go back to the previous alignment again:
scribe.exitAlignment(alignment, true);
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(IASTStatement)
*/
@Override
public int visit(IASTStatement node) {
if (getCurrentPosition() <= nodeOffset(node) && startsWithMacroExpansion(node)) {
scribe.printCommentPreservingNewLines();
}
if (!enterNode(node)) {
return PROCESS_SKIP;
}
int indentLevel = scribe.indentationLevel;
try {
if (node instanceof IASTCompoundStatement) {
visit((IASTCompoundStatement) node);
} else if (node instanceof IASTNullStatement) {
visit((IASTNullStatement) node);
} else if (node instanceof IASTDeclarationStatement) {
visit((IASTDeclarationStatement) node);
} else if (node instanceof IASTForStatement) {
visit((IASTForStatement) node);
} else if (node instanceof ICPPASTRangeBasedForStatement) {
visit((ICPPASTRangeBasedForStatement) node);
} else if (node instanceof IASTIfStatement) {
visit((IASTIfStatement) node);
} else if (node instanceof ICPPASTCatchHandler) {
visit((ICPPASTCatchHandler) node);
} else if (node instanceof ICPPASTTryBlockStatement) {
visit((ICPPASTTryBlockStatement) node);
} else if (node instanceof IASTWhileStatement) {
visit((IASTWhileStatement) node);
} else if (node instanceof IASTDoStatement) {
visit((IASTDoStatement) node);
} else if (node instanceof IASTSwitchStatement) {
visit((IASTSwitchStatement) node);
} else if (node instanceof IASTExpressionStatement) {
visit((IASTExpressionStatement) node);
} else if (node instanceof IASTContinueStatement) {
visit((IASTContinueStatement) node);
} else if (node instanceof IASTReturnStatement) {
visit((IASTReturnStatement) node);
} else if (node instanceof IASTBreakStatement) {
visit((IASTBreakStatement) node);
} else if (node instanceof IASTCaseStatement) {
visit((IASTCaseStatement) node);
} else if (node instanceof IASTDefaultStatement) {
visit((IASTDefaultStatement) node);
} else if (node instanceof IASTGotoStatement) {
visit((IASTGotoStatement) node);
} else if (node instanceof IASTLabelStatement) {
visit((IASTLabelStatement) node);
} else if (node instanceof IASTProblemStatement) {
visit((IASTProblemStatement) node);
} else {
formatRaw(node);
}
exitNode(node);
} catch (ASTProblemException e) {
if (node instanceof IASTProblemStatement) {
throw e;
} else {
skipNode(node);
while (scribe.indentationLevel > indentLevel) {
scribe.unIndent();
}
}
exitNode(node);
}
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(IASTTypeId)
*/
@Override
public int visit(IASTTypeId node) {
if (!enterNode(node)) {
return PROCESS_SKIP;
}
if (node instanceof IASTProblemHolder) {
throw new ASTProblemException(((IASTProblemHolder) node).getProblem());
}
// decl-specifier
final IASTDeclSpecifier declSpec = node.getDeclSpecifier();
if (declSpec != null) {
declSpec.accept(this);
}
// declarator
final IASTDeclarator declarator = node.getAbstractDeclarator();
if (declarator != null) {
boolean needSpace = declarator.getPointerOperators().length > 0 && scribe.printComment();
if (needSpace) {
scribe.space();
}
declarator.accept(this);
}
exitNode(node);
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(IASTEnumerator)
*/
@Override
public int visit(IASTEnumerator enumerator) {
if (!enterNode(enumerator)) {
return PROCESS_SKIP;
}
// name
enumerator.getName().accept(this);
formatAttributes(enumerator, true, false, ICPPASTAttributeList.TYPE_FILTER);
// optional value assignment
final IASTExpression value = enumerator.getValue();
if (value != null) {
scribe.printNextToken(Token.tASSIGN, preferences.insert_space_before_assignment_operator);
if (preferences.insert_space_after_assignment_operator) {
scribe.space();
}
value.accept(this);
}
exitNode(enumerator);
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier)
*/
@Override
public int visit(ICPPASTBaseSpecifier specifier) {
if (!enterNode(specifier)) {
return PROCESS_SKIP;
}
boolean needSpace = false;
loop: while (true) {
int token = peekNextToken();
switch (token) {
case Token.t_public:
case Token.t_protected:
case Token.t_private:
case Token.t_virtual:
scribe.printNextToken(token, needSpace);
needSpace = true;
break;
default:
break loop;
}
}
if (needSpace) {
scribe.space();
}
specifier.getNameSpecifier().accept(this);
exitNode(specifier);
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(ICPPASTNamespaceDefinition)
*/
@Override
public int visit(ICPPASTNamespaceDefinition node) {
if (!enterNode(node)) {
return PROCESS_SKIP;
}
final int line = scribe.line;
if (node.isInline()) {
scribe.printNextToken(Token.t_inline, false);
scribe.space();
}
if (peekNextToken() == Token.tCOLONCOLON) {
// namespace <name>::<name>
scribe.printNextToken(Token.tCOLONCOLON, false);
} else {
// namespace <name>
scribe.printNextToken(Token.t_namespace, false);
scribe.space();
formatLeadingAttributes(node, ICPPASTAttributeList.TYPE_FILTER);
}
boolean isNamedNamespace = !CPPVisitor.isAnonymousNamespace(node);
if (isNamedNamespace) {
IASTName name = node.getName();
name.accept(this);
}
if (peekNextToken() == Token.tCOLONCOLON)
return PROCESS_CONTINUE;
formatAttributes(node, isNamedNamespace, false, IGCCASTAttributeList.TYPE_FILTER);
// member declarations
IASTDeclaration[] memberDecls = node.getDeclarations();
formatLeftCurlyBrace(line, preferences.brace_position_for_namespace_declaration);
formatOpeningBrace(preferences.brace_position_for_namespace_declaration,
preferences.insert_space_before_opening_brace_in_namespace_declaration);
if (preferences.indent_body_declarations_compare_to_namespace_header) {
scribe.indent();
}
scribe.startNewLine();
formatDeclarations(memberDecls, scribe.indentationLevel);
if (preferences.indent_body_declarations_compare_to_namespace_header) {
scribe.unIndent();
}
formatClosingBrace(preferences.brace_position_for_namespace_declaration);
exitNode(node);
return PROCESS_SKIP;
}
private int visit(ICPPASTLinkageSpecification node) {
scribe.printComment();
final int line = scribe.line;
// extern "<linkage>"
scribe.printNextToken(Token.t_extern, false);
scribe.space();
scribe.printNextToken(Token.tSTRING);
// member declarations
IASTDeclaration[] memberDecls = node.getDeclarations();
if (memberDecls.length == 1 && peekNextToken() != Token.tLBRACE) {
scribe.space();
memberDecls[0].accept(this);
} else {
formatLeftCurlyBrace(line, preferences.brace_position_for_linkage_declaration);
formatOpeningBrace(preferences.brace_position_for_linkage_declaration,
preferences.insert_space_before_opening_brace_in_linkage_declaration);
if (preferences.indent_body_declarations_compare_to_linkage) {
scribe.indent();
}
scribe.startNewLine();
for (IASTDeclaration declaration : memberDecls) {
declaration.accept(this);
scribe.startNewLine();
}
if (preferences.indent_body_declarations_compare_to_linkage) {
scribe.unIndent();
}
formatClosingBrace(preferences.brace_position_for_linkage_declaration);
}
return PROCESS_SKIP;
}
/**
* <pre>
* namespace-alias-definition:
* namespace identifier = qualified-namespace-specifier ;
* </pre>
*/
private int visit(ICPPASTNamespaceAlias node) {
scribe.printNextToken(Token.t_namespace);
scribe.space();
node.getAlias().accept(this);
scribe.printNextToken(Token.tASSIGN, preferences.insert_space_before_assignment_operator);
if (preferences.insert_space_after_assignment_operator) {
scribe.space();
}
node.getMappingName().accept(this);
scribe.printNextToken(Token.tSEMI, preferences.insert_space_before_semicolon);
return PROCESS_SKIP;
}
/**
* <pre>
* using-declaration:
* using typename<sub>opt</sub> ::<sub>opt</sub> nested-name-specifier unqualified-id ;
* using :: unqualified-id ;
* </pre>
*/
private int visit(ICPPASTUsingDeclaration node) {
int token = peekNextToken();
if (token == Token.t_using)
scribe.printNextToken(token);
token = peekNextToken();
if (token == Token.t_typename) {
scribe.printNextToken(token, true);
}
scribe.space();
node.getName().accept(this);
token = peekNextToken();
if (token == Token.tSEMI) {
scribe.printNextToken(token, preferences.insert_space_before_semicolon);
}
return PROCESS_SKIP;
}
/**
* <pre>
* using-directive:
* using namespace ::<sub>opt</sub> nested-name-specifier<sub>opt</sub> namespace-name ;
* </pre>
*/
private int visit(ICPPASTUsingDirective node) {
scribe.printNextToken(Token.t_using);
scribe.printNextToken(Token.t_namespace, true);
scribe.space();
node.getQualifiedName().accept(this);
scribe.printNextToken(Token.tSEMI, preferences.insert_space_before_semicolon);
return PROCESS_SKIP;
}
/*
* @see ASTVisitor#visit(ICPPASTTemplateParameter)
*/
@Override
public int visit(ICPPASTTemplateParameter node) {
if (!enterNode(node)) {
return PROCESS_SKIP;
}
try {
if (node instanceof ICPPASTSimpleTypeTemplateParameter) {
visit((ICPPASTSimpleTypeTemplateParameter) node);
} else if (node instanceof ICPPASTTemplatedTypeTemplateParameter) {
visit((ICPPASTTemplatedTypeTemplateParameter) node);
} else {
visit((IASTParameterDeclaration) node);
}
exitNode(node);
} catch (ASTProblemException e) {
skipNode(node);
exitNode(node);
}
return PROCESS_SKIP;
}
private int visit(ICPPASTSimpleTypeTemplateParameter node) {
switch (node.getParameterType()) {
case ICPPASTSimpleTypeTemplateParameter.st_class:
scribe.printNextToken(Token.t_class);
scribe.space();
break;
case ICPPASTSimpleTypeTemplateParameter.st_typename:
scribe.printNextToken(Token.t_typename);
scribe.space();
break;
default:
assert false : "Unknown template paramter type"; //$NON-NLS-1$
formatRaw(node);
return PROCESS_SKIP;
}
node.getName().accept(this);
IASTTypeId defaultType = node.getDefaultType();
if (defaultType != null) {
scribe.printNextToken(Token.tASSIGN, preferences.insert_space_before_assignment_operator);
if (preferences.insert_space_after_assignment_operator) {
scribe.space();
}
defaultType.accept(this);
}
return PROCESS_SKIP;
}
private int visit(ICPPASTTemplatedTypeTemplateParameter node) {
scribe.printNextToken(Token.t_template, scribe.printComment());
scribe.printNextToken(Token.tLT, preferences.insert_space_before_opening_angle_bracket_in_template_parameters);
if (preferences.insert_space_after_opening_angle_bracket_in_template_parameters) {
scribe.space();
}
final ICPPASTTemplateParameter[] templateParameters = node.getTemplateParameters();
if (templateParameters.length > 0) {
final ListOptions options = new ListOptions(Alignment.M_COMPACT_SPLIT);
options.fSpaceAfterSeparator = preferences.insert_space_after_comma_in_template_parameters;
options.fSpaceBeforeSeparator = preferences.insert_space_before_comma_in_template_parameters;
options.fTieBreakRule = Alignment.R_OUTERMOST;
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);
if (preferences.insert_space_after_closing_angle_bracket_in_template_parameters) {
scribe.space();
}
IASTName name = node.getName();
if (name != null) {
name.accept(this);
}
IASTExpression defaultValue = node.getDefaultValue();
if (defaultValue != null) {
scribe.printNextToken(Token.tASSIGN, preferences.insert_space_before_assignment_operator);
if (preferences.insert_space_after_assignment_operator) {
scribe.space();
}
defaultValue.accept(this);
}
return PROCESS_SKIP;
}
private int visit(ICPPASTConstructorInitializer node) {
if (!enterNode(node)) {
return PROCESS_SKIP;
}
// Format like a function call
formatFunctionCallArguments(node.getArguments());
exitNode(node);
return PROCESS_SKIP;
}
private int visit(ICPPASTConstructorChainInitializer node) {
final IASTName member = node.getMemberInitializerId();
final IASTInitializer init = node.getInitializer();
if (member != null && init != null) {
member.accept(this);
init.accept(this);
} else {
formatRaw(node);
}
return PROCESS_SKIP;
}
private int visit(IASTFunctionDefinition node) {
scribe.printComment();
final int line = scribe.line;
// decl-specifier
final IASTDeclSpecifier declSpec = node.getDeclSpecifier();
declSpec.accept(this);
// declarator
final IASTFunctionDeclarator 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)
&& !hasMemberInitializers(node) && !(node instanceof ICPPASTFunctionWithTryBlock)
&& 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);
if (node instanceof ICPPASTFunctionWithTryBlock) {
scribe.startNewLine();
scribe.printNextToken(Token.t_try, false);
scribe.printTrailingComment();
}
if (node instanceof ICPPASTFunctionDefinition) {
ICPPASTFunctionDefinition cppFunctionDefinition = (ICPPASTFunctionDefinition) node;
final ICPPASTConstructorChainInitializer[] constructorChain = cppFunctionDefinition.getMemberInitializers();
if (constructorChain != null && constructorChain.length > 0) {
if (preferences.insert_new_line_before_colon_in_constructor_initializer_list) {
scribe.printTrailingComment();
scribe.startNewLine();
scribe.indentForContinuation();
}
scribe.printNextToken(Token.tCOLON,
!preferences.insert_new_line_before_colon_in_constructor_initializer_list);
if (!preferences.insert_new_line_after_colon_in_constructor_initializer_list) {
scribe.space();
}
if (preferences.insert_new_line_after_colon_in_constructor_initializer_list) {
scribe.printTrailingComment();
scribe.startNewLine();
if (!preferences.insert_new_line_before_colon_in_constructor_initializer_list)
scribe.indentForContinuation();
}
final ListOptions options = new ListOptions(preferences.alignment_for_constructor_initializer_list);
options.fTieBreakRule = Alignment.R_OUTERMOST;
formatList(Arrays.asList(constructorChain), options, false, false, null);
if (preferences.insert_new_line_after_colon_in_constructor_initializer_list
|| preferences.insert_new_line_before_colon_in_constructor_initializer_list) {
scribe.unIndentForContinuation();
}
}
if (cppFunctionDefinition.isDefaulted() || cppFunctionDefinition.isDeleted()) {
int token = peekNextToken();
if (token == Token.tASSIGN) {
if (preferences.insert_space_before_assignment_operator)
scribe.space();
scribe.printNextToken(token);
if (preferences.insert_space_after_assignment_operator)
scribe.space();
}
token = peekNextToken();
if (token == Token.t_default || token == Token.t_delete) {
scribe.printNextToken(token);
}
if (bodyStmt == null) {
tailFormatter = new TrailingSemicolonFormatter(node);
scribe.setTailFormatter(tailFormatter);
}
}
}
if (tailFormatter != null) {
scribe.runTailFormatter();
scribe.setTailFormatter(null);
}
// 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();
scribe.startNewLine();
if (node instanceof ICPPASTFunctionWithTryBlock) {
ICPPASTCatchHandler[] catchHandlers = ((ICPPASTFunctionWithTryBlock) node).getCatchHandlers();
for (ICPPASTCatchHandler catchHandler : catchHandlers) {
catchHandler.accept(this);
scribe.printTrailingComment();
scribe.startNewLine();
}
}
return PROCESS_SKIP;
}
private int visit(IASTASMDeclaration node) {
// TLETODO implement formatting
formatRaw(node);
return PROCESS_SKIP;
}
private int visit(ICPPASTFunctionDeclarator node) {
final List<ICPPASTParameterDeclaration> parameters = Arrays.asList(node.getParameters());
final ListOptions options = createListOptionsForFunctionDeclarationParameters();
Runnable tailFormatter = scribe.takeTailFormatter();
formatList(parameters, options, true, node.takesVarArgs(),
new FunctionDeclaratorTailFormatter(node, tailFormatter));
return PROCESS_SKIP;
}
private void formatExceptionSpecification(final IASTTypeId[] exceptionSpecification) {
if (exceptionSpecification.length > 0) {
Alignment alignment = scribe.createAlignment(Alignment.EXCEPTION_SPECIFICATION,
preferences.alignment_for_throws_clause_in_method_declaration, exceptionSpecification.length,
getCurrentPosition());
scribe.enterAlignment(alignment);
boolean ok = false;
do {
try {
scribe.alignFragment(alignment, 0);
scribe.printNextToken(Token.t_throw, true);
scribe.printNextToken(Token.tLPAREN,
preferences.insert_space_before_opening_paren_in_exception_specification);
if (preferences.insert_space_after_opening_paren_in_exception_specification) {
scribe.space();
}
exceptionSpecification[0].accept(this);
for (int i = 1; i < exceptionSpecification.length; i++) {
scribe.printNextToken(Token.tCOMMA,
preferences.insert_space_before_comma_in_method_declaration_throws);
scribe.printTrailingComment();
if (preferences.insert_space_after_comma_in_method_declaration_throws) {
scribe.space();
}
scribe.alignFragment(alignment, i);
exceptionSpecification[i].accept(this);
}
if (peekNextToken() == Token.tRPAREN) {
scribe.printNextToken(Token.tRPAREN,
preferences.insert_space_before_closing_paren_in_exception_specification);
}
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(alignment, true);
} else {
scribe.printNextToken(Token.t_throw, true);
scribe.printNextToken(Token.tLPAREN,
preferences.insert_space_before_opening_paren_in_exception_specification);
scribe.printNextToken(Token.tRPAREN,
preferences.insert_space_between_empty_parens_in_exception_specification);
}
}
private void formatExceptionSpecification(final ICPPASTExpression noexceptSpecification) {
if (noexceptSpecification != null && noexceptSpecification != ICPPASTFunctionDeclarator.NOEXCEPT_DEFAULT) {
Alignment alignment = scribe.createAlignment(Alignment.EXCEPTION_SPECIFICATION,
preferences.alignment_for_throws_clause_in_method_declaration, 1, getCurrentPosition());
scribe.enterAlignment(alignment);
boolean ok = false;
do {
try {
scribe.alignFragment(alignment, 0);
scribe.printNextToken(Token.t_noexcept, true);
scribe.printNextToken(Token.tLPAREN,
preferences.insert_space_before_opening_paren_in_exception_specification);
if (preferences.insert_space_after_opening_paren_in_exception_specification) {
scribe.space();
}
noexceptSpecification.accept(this);
if (peekNextToken() == Token.tRPAREN) {
scribe.printNextToken(Token.tRPAREN,
preferences.insert_space_before_closing_paren_in_exception_specification);
}
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(alignment, true);
} else {
scribe.printNextToken(Token.t_noexcept, true);
}
}
private boolean skipConstVolatileRestrict(boolean spaceBefore) {
return skipTokenWhile(token -> token == Token.t_const || token == Token.t_volatile || token == Token.t_restrict,
spaceBefore);
}
private boolean skipMutableConstexpr() {
return skipTokenWhile(token -> token == Token.t_mutable || token == Token.t_constexpr, true);
}
private boolean skipTokenWhile(Predicate<Integer> pred, boolean spaceBefore) {
boolean skipped = false;
int token = peekNextToken();
while (pred.test(token)) {
scribe.printNextToken(token, spaceBefore);
token = peekNextToken();
if (!spaceBefore && pred.test(token)) {
scribe.space();
}
skipped = true;
}
return skipped;
}
private int visit(IASTStandardFunctionDeclarator node) {
final List<IASTParameterDeclaration> parameters = Arrays.asList(node.getParameters());
final ListOptions options = createListOptionsForFunctionDeclarationParameters();
formatList(parameters, options, true, node.takesVarArgs(), new TrailingSemicolonFormatter(node));
return PROCESS_SKIP;
}
private ListOptions createListOptionsForFunctionDeclarationParameters() {
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;
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.
*
* @param node an AST node
* @return the position of the last character of a node, or -1 if that character is part of
* a macro expansion.
*/
private static int getLastNodeCharacterPosition(IASTNode node) {
IASTNodeLocation[] locations = node.getNodeLocations();
if (locations.length > 0) {
IASTNodeLocation lastLocation = locations[locations.length - 1];
if (!(lastLocation instanceof IASTMacroExpansionLocation)) {
IASTFileLocation fileLocation = lastLocation.asFileLocation();
return fileLocation.getNodeOffset() + fileLocation.getNodeLength() - 1;
}
}
return -1;
}
private void formatLeadingAttributes(IASTAttributeOwner owner) {
formatAttributes(owner, false, true);
}
/**
* Formats the attributes leading a node.
* Same as {@code formatAttributes(owner, false, true);}
* @param owner Node containing attributes
* @param filter Filter predicate for specifying which attributes to print
*/
private void formatLeadingAttributes(IASTAttributeOwner owner,
InstanceOfPredicate<IASTAttributeSpecifier> predicate) {
formatAttributes(owner, false, true, predicate);
}
private void formatAttributes(IASTAttributeOwner owner, boolean printLeadingSpace, boolean printTrailingSpace) {
formatAttributes(owner, printLeadingSpace, printTrailingSpace, unsused -> true);
}
/**
* Formats the attributes of a given attribute owner.
*
* @param owner Node containing attributes
* @param printLeadingSpace Print a space before the first attribute
* @param printTrailingSpace Print a space after the last attribute
* @param filter Filter predicate for specifying which attributes to print
*/
private void formatAttributes(IASTAttributeOwner owner, boolean printLeadingSpace, boolean printTrailingSpace,
IUnaryPredicate<IASTAttributeSpecifier> filter) {
if (owner == null) {
return;
}
IASTAttributeSpecifier[] attributeSpecifiers = owner.getAttributeSpecifiers();
if (attributeSpecifiers.length > 0) {
if (printLeadingSpace) {
scribe.space();
}
for (IASTAttributeSpecifier attributeSpecifier : attributeSpecifiers) {
if (filter.apply(attributeSpecifier)) {
formatRaw(attributeSpecifier);
}
}
if (printTrailingSpace) {
scribe.space();
}
}
}
/**
* Align pointers according to user formatter rule. Pointers (or references) can be
* left, center or right alignment. Pointers with implicit name will be always left
* aligned unless they have nested declarators.
* @param pointers The list of all pointers
* @param pointer The pointer to be formatted
* @param token The token to be used: and, amper, star.
*/
private boolean alignPointer(IASTPointerOperator[] pointers, IASTPointerOperator pointer, int token) {
boolean firstPtr = pointer == pointers[0];
boolean lastPtr = pointers.length == 1 || pointer == pointers[pointers.length - 1];
TrailingTokenFormatter tailFormatter = null;
IASTNode parent = pointer.getParent();
boolean needSpace = false;
if (parent instanceof IASTFunctionDeclarator) {
tailFormatter = new TrailingTokenFormatter(token, pointer.getParent(), false, true);
tailFormatter.run();
} else {
if (parent instanceof IASTDeclarator) {
char[] simpleId = ((IASTDeclarator) parent).getName().getSimpleID();
IASTDeclarator nested = ((IASTDeclarator) parent).getNestedDeclarator();
if ((simpleId == null || simpleId.length == 0) && nested == null) {
needSpace = true;
tailFormatter = new TrailingTokenFormatter(token, pointer.getParent(), false, false);
tailFormatter.run();
return needSpace;
}
}
if (parent != null && parent.getParent() instanceof IASTParameterDeclaration) {
needSpace = this.preferences.insert_space_after_pointer_in_method_declaration && lastPtr;
tailFormatter = new TrailingTokenFormatter(token, pointer.getParent(),
this.preferences.insert_space_before_pointer_in_method_declaration && firstPtr,
this.preferences.insert_space_after_pointer_in_method_declaration && lastPtr);
tailFormatter.run();
} else if (parent != null && parent.getParent() instanceof IASTSimpleDeclaration) {
needSpace = this.preferences.insert_space_after_pointer_in_declarator_list && lastPtr;
IASTSimpleDeclaration simple = (IASTSimpleDeclaration) parent.getParent();
IASTDeclarator[] declarators = simple.getDeclarators();
boolean first = declarators.length == 0 || declarators[0].getPointerOperators() == pointers;
tailFormatter = new TrailingTokenFormatter(token, pointer.getParent(),
first ? this.preferences.insert_space_before_pointer_in_declarator_list && firstPtr
: (this.preferences.insert_space_before_pointer_in_declarator_list
|| this.preferences.insert_space_after_comma_in_declarator_list) && firstPtr,
this.preferences.insert_space_after_pointer_in_declarator_list && lastPtr);
tailFormatter.run();
} else
scribe.printNextToken(token, false);
}
return needSpace;
}
/**
* Format pointers operators
* @param pointers The list of pointers
*/
private void formatPointers(IASTPointerOperator[] pointers) {
for (IASTPointerOperator pointer : pointers) {
if (scribe.printComment()) {
scribe.space();
}
if (scribe.printModifiers()) {
scribe.space();
}
if (pointer instanceof ICPPASTReferenceOperator) {
if (((ICPPASTReferenceOperator) pointer).isRValueReference()) {
alignPointer(pointers, pointer, Token.tAND);
} else {
alignPointer(pointers, pointer, Token.tAMPER);
}
} else if (pointer instanceof ICPPASTPointerToMember) {
final ICPPASTPointerToMember ptrToMember = (ICPPASTPointerToMember) pointer;
final IASTName name = ptrToMember.getName();
if (name != null) {
name.accept(this);
}
scribe.printNextToken(Token.tSTAR, false);
if (skipConstVolatileRestrict(false)) {
scribe.space();
}
} else {
boolean needSpace = alignPointer(pointers, pointer, Token.tSTAR);
if (skipConstVolatileRestrict(needSpace)) {
scribe.space();
}
}
}
}
private int visit(ICASTKnRFunctionDeclarator node) {
final List<IASTName> parameters = Arrays.asList(node.getParameterNames());
ListOptions options = createListOptionsForFunctionDeclarationParameters();
formatList(parameters, options, true, false, null);
IASTDeclaration[] parameterDecls = node.getParameterDeclarations();
scribe.startNewLine();
scribe.indent();
try {
for (IASTDeclaration declaration : parameterDecls) {
declaration.accept(this);
}
} finally {
scribe.unIndent();
}
return PROCESS_SKIP;
}
private int visit(IASTFieldDeclarator node) {
IASTExpression bitFieldSizeExpr = node.getBitFieldSize();
if (bitFieldSizeExpr != null) {
scribe.printNextToken(Token.tCOLON, true);
bitFieldSizeExpr.accept(this);
}
return PROCESS_SKIP;
}
private int visit(IASTArrayDeclarator node) {
IASTArrayModifier[] arrayModifiers = node.getArrayModifiers();
if (arrayModifiers != null) {
for (IASTArrayModifier arrayModifier : arrayModifiers) {
scribe.printNextToken(Token.tLBRACKET, preferences.insert_space_before_opening_bracket);
boolean emptyBrackets = arrayModifier.getConstantExpression() == null
&& !(arrayModifier instanceof ICASTArrayModifier);
if (!emptyBrackets) {
if (preferences.insert_space_after_opening_bracket) {
scribe.space();
}
}
if (arrayModifier instanceof ICASTArrayModifier) {
final ICASTArrayModifier cArrayModifier = (ICASTArrayModifier) arrayModifier;
if (scribe.printModifiers()) {
scribe.space();
}
if (cArrayModifier.isVariableSized()) {
scribe.printNextToken(Token.tSTAR, scribe.printComment());
}
if (scribe.printComment()) {
scribe.space();
}
}
Runnable tailFormatter = scribe.takeTailFormatter();
try {
arrayModifier.accept(this);
} catch (ASTProblemException e) {
scribe.skipToToken(Token.tRBRACKET);
} finally {
scribe.setTailFormatter(tailFormatter);
}
boolean insertSpace = emptyBrackets ? preferences.insert_space_between_empty_brackets
: preferences.insert_space_before_closing_bracket;
scribe.printNextToken(Token.tRBRACKET, insertSpace);
}
}
return PROCESS_SKIP;
}
private int visit(ICPPASTStructuredBindingDeclaration node) {
formatLeadingAttributes(node);
IASTDeclSpecifier declSpec = node.getDeclSpecifier();
declSpec.accept(this);
RefQualifier refQualifier = node.getRefQualifier();
if (refQualifier != null) {
int expectedToken = refQualifier == RefQualifier.LVALUE ? Token.tAMPER : Token.tAND;
if (peekNextToken() == expectedToken) {
scribe.printNextToken(expectedToken,
preferences.insert_space_before_ref_qualifier_in_structured_binding);
}
}
IASTInitializer initializer = node.getInitializer();
if (peekNextToken() == Token.tLBRACKET) {
List<IASTName> names = Arrays.asList(node.getNames());
final ListOptions options = new ListOptions(preferences.alignment_for_declarator_list);
options.leftToken = Token.tLBRACKET;
options.rightToken = Token.tRBRACKET;
options.fSpaceBeforeOpeningParen = preferences.insert_space_before_opening_structured_binding_name_list;
options.fSpaceAfterOpeningParen = preferences.insert_space_after_opening_structured_binding_name_list;
options.fSpaceBeforeClosingParen = preferences.insert_space_before_closing_structured_binding_name_list;
options.fSpaceAfterSeparator = preferences.insert_space_after_comma_in_structured_binding_name_list;
options.fSpaceBeforeSeparator = preferences.insert_space_before_comma_in_structured_binding_name_list;
formatList(names, options, true, false, null);
} else if (initializer != null) {
skipToNode(initializer);
}
if (initializer != null) {
initializer.accept(this);
}
if (fExpectSemicolonAfterDeclaration && peekNextToken() == Token.tSEMI) {
scribe.printNextToken(Token.tSEMI);
}
return PROCESS_SKIP;
}
private int visit(ICPPASTDeductionGuide node) {
node.getTemplateName().accept(this);
final List<IASTParameterDeclaration> parameters = Arrays.asList(node.getParameters());
Runnable tailFormatter = new TrailingSemicolonFormatter(node);
final ListOptions options = new ListOptions(preferences.alignment_for_declarator_list);
options.fSpaceAfterSeparator = preferences.insert_space_after_comma_in_declarator_list;
options.fSpaceBeforeSeparator = preferences.insert_space_before_comma_in_declarator_list;
formatList(parameters, options, true, false, null);
if (peekNextToken() == Token.tARROW) {
scribe.printNextToken(Token.tARROW, preferences.insert_space_before_deduction_guide_arrow);
if (preferences.insert_space_after_deduction_guide_arrow) {
scribe.space();
}
}
node.getSimpleTemplateId().accept(this);
tailFormatter.run();
return PROCESS_SKIP;
}
private int visit(IASTSimpleDeclaration node) {
if (node instanceof ICPPASTStructuredBindingDeclaration) {
return visit((ICPPASTStructuredBindingDeclaration) node);
}
formatLeadingAttributes(node);
IASTDeclSpecifier declSpec = node.getDeclSpecifier();
declSpec.accept(this);
final List<IASTDeclarator> declarators = Arrays.asList(node.getDeclarators());
if (!declarators.isEmpty()) {
if (declarators.size() == 1 && declarators.get(0) instanceof IASTFunctionDeclarator) {
if (scribe.printCommentPreservingNewLines()) {
scribe.space();
}
} else {
if (scribe.printComment()) {
scribe.space();
}
}
Runnable tailFormatter = fExpectSemicolonAfterDeclaration ? new TrailingSemicolonFormatter(node) : null;
if (declarators.size() == 1) {
if (tailFormatter != null) {
scribe.setTailFormatter(tailFormatter);
try {
visit(declarators.get(0));
scribe.runTailFormatter();
} finally {
scribe.setTailFormatter(null);
}
} else {
visit(declarators.get(0));
}
} else {
final ListOptions options = new ListOptions(preferences.alignment_for_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);
}
}
return PROCESS_SKIP;
}
private int visit(ICPPASTTemplateDeclaration node) {
if (node.isExported()) {
scribe.printNextToken(Token.t_export);
scribe.space();
}
scribe.printNextToken(Token.t_template);
scribe.printNextToken(Token.tLT, preferences.insert_space_before_opening_angle_bracket_in_template_parameters);
if (preferences.insert_space_after_opening_angle_bracket_in_template_parameters) {
scribe.space();
}
// Template parameters
final ICPPASTTemplateParameter[] templateParameters = node.getTemplateParameters();
if (templateParameters.length > 0) {
final ListOptions options = new ListOptions(Alignment.M_COMPACT_SPLIT);
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);
}
int nextToken = peekNextToken();
if (nextToken == Token.tGT || nextToken == Token.tSHIFTR) {
scribe.printNextToken(new int[] { Token.tGT, Token.tSHIFTR },
preferences.insert_space_before_closing_angle_bracket_in_template_parameters);
if (preferences.insert_space_after_closing_angle_bracket_in_template_parameters) {
scribe.space();
}
}
// Declaration
final IASTDeclaration declaration = node.getDeclaration();
if (preferences.insert_new_line_after_template_declaration) {
scribe.startNewLine();
if (preferences.indent_declaration_compare_to_template_header) {
scribe.indent();
}
} else {
// Preserve newline if not explicitly requested
scribe.printCommentPreservingNewLines();
}
declaration.accept(this);
if (preferences.insert_new_line_after_template_declaration) {
if (preferences.indent_declaration_compare_to_template_header) {
scribe.unIndent();
}
}
return PROCESS_SKIP;
}
/**
* <pre>
* explicit-specialization:
* template < > declaration
* </pre>
*/
private int visit(ICPPASTTemplateSpecialization node) {
scribe.printNextToken(Token.t_template);
scribe.printNextToken(Token.tLT, preferences.insert_space_before_opening_angle_bracket_in_template_parameters);
scribe.printNextToken(Token.tGT, scribe.printComment());
if (preferences.insert_space_after_closing_angle_bracket_in_template_parameters) {
scribe.space();
}
node.getDeclaration().accept(this);
return PROCESS_SKIP;
}
private int visit(ICPPASTExplicitTemplateInstantiation node) {
node.getDeclaration().accept(this);
return PROCESS_SKIP;
}
private int visit(IASTSimpleDeclSpecifier node) {
formatRaw(node);
return PROCESS_SKIP;
}
private int visit(IASTNamedTypeSpecifier node) {
if (scribe.printModifiers()) {
scribe.space();
}
if (node instanceof ICPPASTNamedTypeSpecifier) {
if (((ICPPASTNamedTypeSpecifier) node).isTypename()) {
scribe.printNextToken(Token.t_typename);
scribe.space();
}
}
node.getName().accept(this);
return PROCESS_SKIP;
}
private int visit(ICASTCompositeTypeSpecifier node) {
boolean formatAttributes = false;
scribe.printComment();
final int line = scribe.line;
// storage class and other modifiers
if (scribe.printModifiers()) {
scribe.space();
}
// Consider macro expansion
if (withinMacroExpansion(node, getCurrentPosition())) {
scribe.printNextToken(peekNextToken());
continueNode(node);
if (scribe.printComment())
scribe.space();
}
switch (node.getKey()) {
case IASTCompositeTypeSpecifier.k_struct:
scribe.printNextToken(Token.t_struct, true);
break;
case IASTCompositeTypeSpecifier.k_union:
scribe.printNextToken(Token.t_union, true);
break;
default:
assert false : "Unexpected composite type specifier"; //$NON-NLS-1$
}
final IASTName name = node.getName();
if (name != null) {
IASTAttributeSpecifier[] attributes = node.getAttributeSpecifiers();
if (attributes.length > 0) {
/**
* According to GCC docs, attributes can be defined just after struct
* or union keywords or just after the closing brace.
*/
int token = peekTokenAtPosition(nodeEndOffset(attributes[0]));
if (token == Token.tLBRACE
|| (name.getFileLocation() != null && nodeOffset(name) > nodeOffset(attributes[0]))) {
formatAttributes(node, true, false, IGCCASTAttributeList.TYPE_FILTER);
} else {
formatAttributes = true;
}
}
scribe.space();
name.accept(this);
}
// Member declarations
IASTDeclaration[] memberDecls = node.getMembers();
formatLeftCurlyBrace(line, preferences.brace_position_for_type_declaration);
formatOpeningBrace(preferences.brace_position_for_type_declaration,
preferences.insert_space_before_opening_brace_in_type_declaration);
if (preferences.indent_body_declarations_compare_to_access_specifier) {
scribe.indent();
}
scribe.startNewLine();
for (IASTDeclaration declaration : memberDecls) {
declaration.accept(this);
scribe.startNewLine();
}
if (preferences.indent_body_declarations_compare_to_access_specifier) {
scribe.unIndent();
}
formatClosingBrace(preferences.brace_position_for_type_declaration);
if (formatAttributes)
formatAttributes(node, true, false, IGCCASTAttributeList.TYPE_FILTER);
return PROCESS_SKIP;
}
private int visit(ICPPASTCompositeTypeSpecifier node) {
boolean formatAttributes = false;
scribe.printComment();
final int line = scribe.line;
// Storage class and other modifiers
if (scribe.printModifiers()) {
scribe.space();
}
final int headerIndent = scribe.numberOfIndentations;
// Consider macro expansion
if (withinMacroExpansion(node, getCurrentPosition())) {
scribe.printNextToken(peekNextToken());
continueNode(node);
if (scribe.printComment())
scribe.space();
}
int token = peekNextToken();
if (token == Token.t_struct || token == Token.t_class || token == Token.t_union) {
scribe.printNextToken(token, false);
}
final IASTName name = node.getName();
if (name != null) {
if (token == Token.t_struct || token == Token.t_union) {
IASTAttributeSpecifier[] attributes = node.getAttributeSpecifiers();
if (attributes.length > 0) {
/**
* According to GCC docs, attributes can be defined just after struct
* or union keywords or just after the closing brace.
*/
token = peekTokenAtPosition(nodeEndOffset(attributes[0]));
if (token == Token.tLBRACE
|| (name.getFileLocation() != null && nodeOffset(name) > nodeOffset(attributes[0]))) {
formatAttributes(node, true, false, IGCCASTAttributeList.TYPE_FILTER);
} else {
formatAttributes = true;
}
}
}
scribe.space();
name.accept(this);
}
ICPPASTClassVirtSpecifier virtSpecifier = node.getVirtSpecifier();
if (virtSpecifier != null) {
scribe.space();
virtSpecifier.accept(this);
}
// Base specifiers
final List<ICPPASTBaseSpecifier> baseSpecifiers = Arrays.asList(node.getBaseSpecifiers());
if (baseSpecifiers.size() > 0) {
ICPPASTBaseSpecifier baseSpecifier = baseSpecifiers.get(0);
try {
if (baseSpecifier.getLeadingSyntax().getType() == IToken.tCOLON) {
scribe.printNextToken(Token.tCOLON, preferences.insert_space_before_colon_in_base_clause);
if (preferences.insert_space_after_colon_in_base_clause) {
scribe.space();
}
}
} catch (UnsupportedOperationException e) {
} catch (ExpansionOverlapsBoundaryException e) {
}
final ListOptions options = new ListOptions(preferences.alignment_for_base_clause_in_type_declaration);
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);
}
// Member declarations
formatLeftCurlyBrace(line, preferences.brace_position_for_type_declaration);
formatOpeningBrace(preferences.brace_position_for_type_declaration,
preferences.insert_space_before_opening_brace_in_type_declaration);
final int braceIndent = scribe.numberOfIndentations;
if (braceIndent > headerIndent) {
scribe.unIndent();
}
if (preferences.indent_access_specifier_compare_to_type_header) {
scribe.indent();
}
if (getCurrentPosition() >= nodeEndOffset(node)) {
return PROCESS_SKIP;
}
scribe.startNewLine();
IASTDeclaration[] memberDecls = node.getMembers();
for (int i = 0; i < memberDecls.length; i++) {
IASTDeclaration declaration = memberDecls[i];
if (preferences.indent_body_declarations_compare_to_access_specifier) {
scribe.indent();
}
scribe.printComment();
if (declaration instanceof ICPPASTVisibilityLabel) {
if (preferences.indent_body_declarations_compare_to_access_specifier) {
scribe.unIndent();
}
IASTDeclaration next = null;
if (i < memberDecls.length - 1 && !(memberDecls[i + 1] instanceof IASTProblemHolder))
next = memberDecls[i + 1];
if (i == memberDecls.length - 1 || next == null || !doNodeLocationsOverlap(declaration, next)) {
if (getCurrentPosition() <= nodeOffset(declaration))
scribe.startNewLine();
}
declaration.accept(this);
} else {
if (!(declaration instanceof IASTProblemHolder)) {
IASTDeclaration next = null;
if (i < memberDecls.length - 1 && !(memberDecls[i + 1] instanceof IASTProblemHolder))
next = memberDecls[i + 1];
if (i == memberDecls.length - 1 || next == null || !doNodeLocationsOverlap(declaration, next)) {
if (getCurrentPosition() <= nodeOffset(declaration))
scribe.startNewLine();
}
declaration.accept(this);
} else {
skipNode(declaration);
}
if (preferences.indent_body_declarations_compare_to_access_specifier) {
scribe.unIndent();
}
}
}
scribe.startNewLine();
if (preferences.indent_body_declarations_compare_to_access_specifier) {
scribe.indent();
}
scribe.printComment();
if (preferences.indent_body_declarations_compare_to_access_specifier) {
scribe.unIndent();
}
if (preferences.indent_access_specifier_compare_to_type_header) {
scribe.unIndent();
}
if (scribe.numberOfIndentations < braceIndent) {
scribe.indent();
}
formatClosingBrace(preferences.brace_position_for_type_declaration);
if (formatAttributes)
formatAttributes(node, true, false, IGCCASTAttributeList.TYPE_FILTER);
return PROCESS_SKIP;
}
private int visit(ICPPASTVisibilityLabel node) {
if (node.getNodeLocations()[0] instanceof IASTMacroExpansionLocation) {
skipNode(node);
} else {
scribe.printSpaces(preferences.indent_access_specifier_extra_spaces);
switch (node.getVisibility()) {
case ICPPASTVisibilityLabel.v_private:
scribe.printNextToken(Token.t_private, false);
break;
case ICPPASTVisibilityLabel.v_protected:
scribe.printNextToken(Token.t_protected, false);
break;
case ICPPASTVisibilityLabel.v_public:
scribe.printNextToken(Token.t_public, false);
break;
}
if (peekNextToken() != Token.tCOLON) {
scribe.skipToToken(Token.tCOLON);
}
scribe.printNextToken(Token.tCOLON, false/*preferences.insert_space_before_colon_in_access specifier*/);
}
return PROCESS_SKIP;
}
private int visit(IASTElaboratedTypeSpecifier node) {
// Storage class and other modifiers
if (scribe.printModifiers()) {
scribe.space();
}
switch (node.getKind()) {
case IASTElaboratedTypeSpecifier.k_enum:
scribe.printNextToken(Token.t_enum, false);
break;
case IASTElaboratedTypeSpecifier.k_struct:
scribe.printNextToken(Token.t_struct, false);
break;
case IASTElaboratedTypeSpecifier.k_union:
scribe.printNextToken(Token.t_union, false);
break;
case ICPPASTElaboratedTypeSpecifier.k_class:
scribe.printNextToken(Token.t_class, false);
break;
default:
assert false : "Unexpected elaborated type specifier"; //$NON-NLS-1$
}
scribe.space();
node.getName().accept(this);
return PROCESS_SKIP;
}
private int visit(IASTEnumerationSpecifier node) {
scribe.printComment();
final int line = scribe.line;
// Storage class and other modifiers
if (scribe.printModifiers()) {
scribe.space();
}
final int headerIndent = scribe.numberOfIndentations;
scribe.printNextToken(Token.t_enum, true);
final IASTName name = node.getName();
if (name != null) {
scribe.space();
name.accept(this);
}
ICPPASTEnumerationSpecifier cppNode = null;
if (node instanceof ICPPASTEnumerationSpecifier) {
cppNode = (ICPPASTEnumerationSpecifier) node;
formatLeadingAttributes(cppNode);
ICPPASTDeclSpecifier baseType = cppNode.getBaseType();
if (baseType != null) {
scribe.space();
scribe.printNextToken(Token.tCOLON);
scribe.space();
baseType.accept(this);
}
}
formatLeftCurlyBrace(line, preferences.brace_position_for_type_declaration);
formatOpeningBrace(preferences.brace_position_for_type_declaration,
preferences.insert_space_before_opening_brace_in_type_declaration);
final int braceIndent = scribe.numberOfIndentations;
scribe.startNewLine();
if (braceIndent == headerIndent) {
scribe.indent();
}
final int enumIndent = scribe.numberOfIndentations;
final IASTEnumerator[] enumerators = node.getEnumerators();
final ListOptions options = new ListOptions(preferences.alignment_for_enumerator_list);
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.fSpaceBeforeSeparator);
if (options.fSpaceAfterSeparator) {
scribe.space();
}
}
scribe.printTrailingComment();
if (enumIndent > braceIndent) {
scribe.unIndent();
}
scribe.startNewLine();
formatClosingBrace(preferences.brace_position_for_type_declaration);
return PROCESS_SKIP;
}
/**
* 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.
*/
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) {
if (peekNextToken() == options.leftToken)
scribe.printNextToken(options.leftToken, options.fSpaceBeforeOpeningParen);
}
final int elementsLength = elements.size();
if (encloseInParen) {
boolean spaceBeforeClosingParen = elements.isEmpty() && !addEllipsis
&& options.captureDefault == CaptureDefault.UNSPECIFIED ? options.fSpaceBetweenEmptyParen
: options.fSpaceBeforeClosingParen;
tailFormatter = new ClosingParensesisTailFormatter(spaceBeforeClosingParen, tailFormatter,
options.rightToken);
}
if (prefix != null)
prefix.run();
if (!elements.isEmpty() || addEllipsis) {
if (options.fSpaceAfterOpeningParen) {
scribe.space();
}
final int continuationIndentation = options.fContinuationIndentation >= 0 ? options.fContinuationIndentation
: preferences.continuation_indentation;
Alignment alignment = scribe.createAlignment(
Alignment.LIST_ELEMENTS_PREFIX
+ (elements.isEmpty() ? "ellipsis" : elements.get(0).getClass().getSimpleName()), //$NON-NLS-1$
options.fMode, options.fTieBreakRule, elementsLength + (addEllipsis ? 1 : 0), getCurrentPosition(),
continuationIndentation, false);
scribe.enterAlignment(alignment);
boolean ok = false;
do {
try {
int i;
for (i = 0; i < elementsLength; i++) {
final Object element = elements.get(i);
if (i < elementsLength - 1) {
scribe.setTailFormatter(new TrailingTokenFormatter(options.fSeparatorToken,
findTokenAfterNodeOrTokenRange(options.fSeparatorToken, element),
options.fSpaceBeforeSeparator, options.fSpaceAfterSeparator));
} else {
scribe.setTailFormatter(tailFormatter);
}
scribe.alignFragment(alignment, i);
if (element instanceof IASTNode) {
if (element instanceof ICPPASTConstructorChainInitializer) {
// Constructor chain initializer is a special case.
visit((ICPPASTConstructorChainInitializer) element);
} else {
((IASTNode) element).accept(this);
}
} else {
formatTokenRange((TokenRange) element);
}
if (i < elementsLength - 1) {
scribe.runTailFormatter();
}
}
if (addEllipsis) {
if (i > 0) {
scribe.printNextToken(options.fSeparatorToken, options.fSpaceBeforeSeparator);
scribe.printTrailingComment();
}
scribe.alignFragment(alignment, i);
if (i > 0 && options.fSpaceAfterSeparator) {
scribe.space();
}
scribe.printNextToken(Token.tELIPSE);
}
scribe.runTailFormatter();
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
} catch (ASTProblemException e) {
}
} while (!ok);
scribe.exitAlignment(alignment, true);
} else if (tailFormatter != null) {
tailFormatter.run();
}
}
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();
if (tryBody != null) {
tryBody.accept(this);
}
scribe.printTrailingComment();
ICPPASTCatchHandler[] catchHandlers = node.getCatchHandlers();
for (ICPPASTCatchHandler catchHandler : catchHandlers) {
catchHandler.accept(this);
scribe.printTrailingComment();
}
return PROCESS_SKIP;
}
private int visit(ICPPASTCatchHandler node) {
int token = peekNextToken();
if (token == Token.t_catch) {
if (preferences.insert_new_line_before_catch_in_try_statement) {
scribe.startNewLine();
}
scribe.printNextToken(token, true);
}
token = peekNextToken();
if (token == Token.tLPAREN) {
scribe.printNextToken(token, preferences.insert_space_before_opening_paren_in_catch);
if (preferences.insert_space_after_opening_paren_in_catch) {
scribe.space();
}
}
final IASTDeclaration decl = node.getDeclaration();
if (decl != null) {
formatInlineDeclaration(decl);
} else if (node.isCatchAll()) {
token = peekNextToken();
if (token == Token.tELIPSE) {
scribe.printNextToken(token, false /* preferences.insert_space_before_ellipsis */);
// if (false /* preferences.insert_space_after_ellipsis */) {
// scribe.space();
// }
}
}
token = peekNextToken();
if (token == Token.tRPAREN) {
scribe.printNextToken(token, preferences.insert_space_before_closing_paren_in_catch);
}
final IASTStatement catchBody = node.getCatchBody();
if (catchBody != null) {
catchBody.accept(this);
}
return PROCESS_SKIP;
}
private void formatInlineDeclaration(final IASTDeclaration decl) {
boolean previousExpectSemicolonAfterDeclaration = fExpectSemicolonAfterDeclaration;
fExpectSemicolonAfterDeclaration = false;
try {
decl.accept(this);
} finally {
fExpectSemicolonAfterDeclaration = previousExpectSemicolonAfterDeclaration;
}
}
private int visit(IASTCompoundStatement node) {
formatBlock(node, preferences.brace_position_for_block, preferences.insert_space_before_opening_brace_in_block,
preferences.indent_statements_compare_to_block);
return PROCESS_SKIP;
}
private int visit(IASTBreakStatement node) {
formatLeadingAttributes(node);
scribe.printNextToken(Token.t_break);
scribe.printNextToken(Token.tSEMI, preferences.insert_space_before_semicolon);
scribe.printTrailingComment();
return PROCESS_SKIP;
}
private int visit(IASTConditionalExpression node) {
// Count nested conditional expressions.
int numConditions = 0;
for (IASTExpression expression = node; expression instanceof IASTConditionalExpression; expression = ((IASTConditionalExpression) expression)
.getNegativeResultExpression()) {
numConditions++;
}
Runnable tailFormatter = scribe.takeTailFormatter();
Alignment alignment = scribe.createAlignment(Alignment.CONDITIONAL_EXPRESSION_CHAIN,
preferences.alignment_for_conditional_expression_chain, Alignment.R_OUTERMOST, numConditions,
getCurrentPosition());
scribe.enterAlignment(alignment);
boolean ok = false;
do {
try {
IASTConditionalExpression expression = node;
for (int i = 0;; i++) {
scribe.alignFragment(alignment, i);
boolean last = i == numConditions - 1;
formatConditionalExpression(expression, last ? tailFormatter : null);
if (last)
break;
expression = (IASTConditionalExpression) expression.getNegativeResultExpression();
}
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(alignment, true);
return PROCESS_SKIP;
}
private void formatConditionalExpression(IASTConditionalExpression node, Runnable tailFormatter) {
scribe.setTailFormatter(new TrailingTokenFormatter(Token.tQUESTION, node,
preferences.insert_space_before_question_in_conditional,
preferences.insert_space_after_question_in_conditional));
node.getLogicalConditionExpression().accept(this);
scribe.runTailFormatter();
final IASTExpression positiveExpression = node.getPositiveResultExpression();
final IASTExpression negativeExpression = node.getNegativeResultExpression();
Alignment alignment = scribe.createAlignment(Alignment.CONDITIONAL_EXPRESSION,
preferences.alignment_for_conditional_expression, Alignment.R_OUTERMOST,
negativeExpression instanceof IASTConditionalExpression ? 1 : 2, getCurrentPosition());
scribe.enterAlignment(alignment);
boolean ok = false;
do {
try {
// In case of macros we may have already passed the expression position.
if (positiveExpression != null && getCurrentPosition() <= nodeOffset(positiveExpression)) {
scribe.alignFragment(alignment, 0);
}
scribe.setTailFormatter(new TrailingTokenFormatter(Token.tCOLON, node,
preferences.insert_space_before_colon_in_conditional,
preferences.insert_space_after_colon_in_conditional));
// A gcc extension allows the positive expression to be omitted.
if (positiveExpression != null) {
positiveExpression.accept(this);
}
scribe.runTailFormatter();
if (!(negativeExpression instanceof IASTConditionalExpression)) {
// In case of macros we may have already passed the expression position.
if (getCurrentPosition() <= nodeOffset(negativeExpression)) {
scribe.alignFragment(alignment, 1);
}
scribe.setTailFormatter(tailFormatter);
negativeExpression.accept(this);
scribe.runTailFormatter();
}
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(alignment, true);
}
private int visit(IASTFunctionCallExpression node) {
Runnable tailFormatter = scribe.takeTailFormatter();
try {
node.getFunctionNameExpression().accept(this);
} finally {
scribe.setTailFormatter(tailFormatter);
}
IASTInitializerClause[] paramExpr = node.getArguments();
if (peekNextToken() == Token.tIDENTIFIER) {
skipNode(node);
} else {
formatFunctionCallArguments(paramExpr);
}
return PROCESS_SKIP;
}
/**
* Formats given expressions as a function call, ie. enclosed in parenthesis.
*
* @param args the argument expressions, may be <code>null</code>
*/
private void formatFunctionCallArguments(IASTInitializerClause[] args) {
// check for macro
if (peekNextToken() != Token.tLPAREN) {
if (args == null || args.length == 0 || enclosedInMacroExpansion(args[0])) {
return;
}
}
final List<IASTInitializerClause> expressions;
if (args != null) {
expressions = Arrays.asList(args);
} else {
// No arguments
expressions = Collections.emptyList();
}
final ListOptions options = new ListOptions(preferences.alignment_for_arguments_in_method_invocation);
options.fSeparatorToken = Token.tCOMMA;
options.fSpaceBeforeOpeningParen = preferences.insert_space_before_opening_paren_in_method_invocation;
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;
formatList(expressions, options, true, false, scribe.takeTailFormatter());
}
private int visit(IASTExpressionList node) {
final List<IASTExpression> expressions = Arrays.asList(node.getExpressions());
final ListOptions options = new ListOptions(preferences.alignment_for_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;
}
private int visit(IASTIdExpression node) {
node.getName().accept(this);
return PROCESS_SKIP;
}
private int visit(IASTCastExpression node) {
Runnable tailFormatter = null;
switch (node.getOperator()) {
case IASTCastExpression.op_cast:
scribe.printNextToken(Token.tLPAREN, false);
if (preferences.insert_space_after_opening_paren_in_cast) {
scribe.space();
}
tailFormatter = scribe.takeTailFormatter();
try {
node.getTypeId().accept(this);
} finally {
scribe.setTailFormatter(tailFormatter);
}
try {
if (node.getTypeId().getTrailingSyntax().getType() == IToken.tRPAREN) {
scribe.printNextToken(Token.tRPAREN, preferences.insert_space_before_closing_paren_in_cast);
if (preferences.insert_space_after_closing_paren_in_cast) {
scribe.space();
}
}
} catch (UnsupportedOperationException exc) {
} catch (ExpansionOverlapsBoundaryException exc) {
scribe.space();
}
// operand
node.getOperand().accept(this);
break;
case ICPPASTCastExpression.op_const_cast:
case ICPPASTCastExpression.op_dynamic_cast:
case ICPPASTCastExpression.op_reinterpret_cast:
case ICPPASTCastExpression.op_static_cast:
scribe.printNextToken(peekNextToken(), false);
scribe.printNextToken(Token.tLT,
preferences.insert_space_before_opening_angle_bracket_in_template_arguments);
if (preferences.insert_space_after_opening_angle_bracket_in_template_arguments) {
scribe.space();
}
tailFormatter = scribe.takeTailFormatter();
try {
node.getTypeId().accept(this);
} finally {
scribe.setTailFormatter(tailFormatter);
}
scribe.printNextToken(Token.tGT,
preferences.insert_space_before_closing_angle_bracket_in_template_arguments);
if (preferences.insert_space_before_opening_paren_in_method_invocation) {
scribe.space();
}
// operand
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_method_invocation);
if (preferences.insert_space_after_opening_paren_in_method_invocation) {
scribe.space();
}
tailFormatter = scribe.takeTailFormatter();
try {
node.getOperand().accept(this);
} finally {
scribe.setTailFormatter(tailFormatter);
}
scribe.printNextToken(Token.tRPAREN, preferences.insert_space_before_closing_paren_in_method_invocation);
break;
default:
skipToNode(node.getOperand());
}
return PROCESS_SKIP;
}
private int visit(IASTTypeIdExpression node) {
if (enclosedInMacroExpansion(node)) {
return PROCESS_SKIP;
}
scribe.printNextToken(peekNextToken());
if (peekNextToken() == IToken.tELLIPSIS) {
scribe.printNextToken(IToken.tELLIPSIS);
}
scribe.printNextToken(Token.tLPAREN);
node.getTypeId().accept(this);
if (peekNextToken() == Token.tCOMMA) {
scribe.printNextToken(Token.tCOMMA, preferences.insert_space_before_comma_in_method_invocation_arguments);
scribe.printNextToken(peekNextToken(), preferences.insert_space_after_comma_in_method_invocation_arguments);
scribe.skipToToken(Token.tRPAREN);
}
scribe.printNextToken(Token.tRPAREN);
return PROCESS_SKIP;
}
private int visit(IASTEqualsInitializer node) {
if (node.getPropertyInParent() == IASTInitializerList.NESTED_INITIALIZER) {
assert false;
// Nested initializer expression, no need to apply extra alignment
// node.getExpression().accept(this);
} else {
// Declaration initializer
Alignment alignment = scribe.createAlignment(Alignment.DECLARATION_INITIALIZER,
preferences.alignment_for_assignment, Alignment.R_INNERMOST, 1, getCurrentPosition());
Runnable tailFormatter = scribe.getTailFormatter();
scribe.enterAlignment(alignment);
scribe.setTailFormatter(tailFormatter); // Inherit tail formatter from the enclosing alignment
boolean ok = false;
do {
try {
scribe.alignFragment(alignment, 0);
node.getInitializerClause().accept(this);
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(alignment, true);
}
return PROCESS_SKIP;
}
private int visit(ICASTDesignatedInitializer node) {
scribe.printComment();
ICASTDesignator[] designators = node.getDesignators();
for (ICASTDesignator designator : designators) {
designator.accept(this);
if (scribe.printComment()) {
scribe.space();
}
}
if (peekNextToken() == Token.tASSIGN) {
scribe.printNextToken(Token.tASSIGN, preferences.insert_space_before_assignment_operator);
if (preferences.insert_space_after_assignment_operator) {
scribe.space();
}
}
Alignment expressionAlignment = scribe.createAlignment(Alignment.DESIGNATED_INITIALIZER,
preferences.alignment_for_assignment, 1, getCurrentPosition());
scribe.enterAlignment(expressionAlignment);
boolean ok = false;
do {
try {
scribe.alignFragment(expressionAlignment, 0);
IASTInitializerClause initializer = node.getOperand();
initializer.accept(this);
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(expressionAlignment, true);
return PROCESS_SKIP;
}
private int visit(ICPPASTDesignatedInitializer node) {
scribe.printComment();
ICPPASTDesignator[] designators = node.getDesignators();
for (ICPPASTDesignator designator : designators) {
designator.accept(this);
if (scribe.printComment()) {
scribe.space();
}
}
if (peekNextToken() == Token.tASSIGN) {
scribe.printNextToken(Token.tASSIGN, preferences.insert_space_before_assignment_operator);
if (preferences.insert_space_after_assignment_operator) {
scribe.space();
}
}
Alignment expressionAlignment = scribe.createAlignment(Alignment.DESIGNATED_INITIALIZER,
preferences.alignment_for_assignment, 1, getCurrentPosition());
scribe.enterAlignment(expressionAlignment);
boolean ok = false;
do {
try {
scribe.alignFragment(expressionAlignment, 0);
IASTInitializerClause initializer = node.getOperand();
initializer.accept(this);
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(expressionAlignment, true);
return PROCESS_SKIP;
}
private int visit(IASTInitializerList node) {
scribe.printComment();
final List<IASTInitializerClause> initializers = Arrays.asList(node.getClauses());
if (initializers.isEmpty() && preferences.keep_empty_initializer_list_on_one_line) {
scribe.printNextToken(Token.tLBRACE, preferences.insert_space_before_opening_brace_in_initializer_list);
scribe.printNextToken(Token.tRBRACE, preferences.insert_space_between_empty_braces_in_initializer_list);
} else {
final int line = scribe.line;
final String brace_position = preferences.brace_position_for_initializer_list;
formatLeftCurlyBrace(line, brace_position);
formatOpeningBrace(brace_position, preferences.insert_space_before_opening_brace_in_initializer_list);
if (preferences.insert_new_line_after_opening_brace_in_initializer_list) {
scribe.startNewLine();
}
if (preferences.insert_space_after_opening_brace_in_initializer_list) {
scribe.space();
}
final ListOptions options = new ListOptions(preferences.alignment_for_expressions_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.fSpaceBeforeSeparator);
if (options.fSpaceAfterSeparator) {
scribe.space();
}
}
if (preferences.insert_new_line_before_closing_brace_in_initializer_list) {
scribe.startNewLine();
}
if (preferences.insert_space_before_closing_brace_in_initializer_list) {
scribe.space();
}
formatClosingBrace(brace_position);
}
scribe.printTrailingComment();
return PROCESS_SKIP;
}
private int visit(IASTUnaryExpression node) {
if (enclosedInMacroExpansion(node)) {
return PROCESS_SKIP;
}
final IASTExpression operand = node.getOperand();
final int operator = node.getOperator();
switch (operator) {
case IASTUnaryExpression.op_bracketedPrimary:
formatParenthesizedExpression(operand);
break;
case IASTUnaryExpression.op_prefixIncr:
case IASTUnaryExpression.op_prefixDecr:
scribe.printNextToken(peekNextToken(), preferences.insert_space_before_prefix_operator);
if (preferences.insert_space_after_prefix_operator) {
scribe.space();
}
operand.accept(this);
break;
case IASTUnaryExpression.op_postFixIncr:
case IASTUnaryExpression.op_postFixDecr:
operand.accept(this);
scribe.printNextToken(peekNextToken(), preferences.insert_space_before_postfix_operator);
if (preferences.insert_space_after_postfix_operator) {
scribe.space();
}
break;
case IASTUnaryExpression.op_sizeof:
scribe.printNextToken(Token.t_sizeof, scribe.printComment());
if (peekNextToken() != Token.tLPAREN) {
scribe.space();
}
operand.accept(this);
break;
case IASTUnaryExpression.op_sizeofParameterPack:
scribe.printNextToken(Token.t_sizeof, scribe.printComment());
scribe.printNextToken(Token.tELIPSE, scribe.printComment());
scribe.printNextToken(Token.tLPAREN);
operand.accept(this);
break;
case IASTUnaryExpression.op_throw:
scribe.printNextToken(Token.t_throw, scribe.printComment());
if (operand != null) {
if (peekNextToken() != Token.tLPAREN) {
scribe.space();
}
operand.accept(this);
}
break;
case IASTUnaryExpression.op_noexcept:
scribe.printNextToken(Token.t_noexcept, scribe.printComment());
if (operand != null) {
if (peekNextToken() != Token.tLPAREN) {
scribe.space();
}
operand.accept(this);
}
break;
case IASTUnaryExpression.op_typeid:
scribe.printNextToken(Token.t_typeid, scribe.printComment());
if (peekNextToken() != Token.tLPAREN) {
scribe.space();
}
operand.accept(this);
break;
case IASTUnaryExpression.op_alignOf:
default:
int operatorToken = peekNextToken();
boolean forceSpace = Character.isJavaIdentifierStart(peekNextChar());
scribe.printNextToken(operatorToken, preferences.insert_space_before_unary_operator);
if (forceSpace || preferences.insert_space_after_unary_operator) {
scribe.space();
} else if (operatorToken == Token.tIDENTIFIER && peekNextToken() != Token.tLPAREN) {
scribe.space();
}
operand.accept(this);
break;
}
return PROCESS_SKIP;
}
private int visit(IASTBinaryExpression node) {
if (enclosedInMacroExpansion(node)) {
return PROCESS_SKIP;
}
IASTNode op2 = node.getOperand2();
if (op2 == null)
op2 = node.getInitOperand2();
if (doNodeLocationsOverlap(node.getOperand1(), op2)) {
// 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);
op2.accept(this);
return PROCESS_SKIP;
}
if (isAssignment(node)) {
return formatAssignment(node);
}
if (isOverloadedLeftShift(node)) {
return formatOverloadedLeftShiftChain(node);
}
// To improve speed of the algorithm we flatten homogeneous nested binary expressions
// to reduce overall depth of the expression tree.
IASTExpression[] operands = CPPVisitor.getOperandsOfMultiExpression(node);
Runnable tailFormatter = endsWithMacroExpansion(node) ? null : scribe.takeTailFormatter();
Alignment alignment = scribe.createAlignment(Alignment.BINARY_EXPRESSION,
preferences.alignment_for_binary_expression, Alignment.R_OUTERMOST, operands.length,
getCurrentPosition());
scribe.enterAlignment(alignment);
boolean ok = false;
do {
try {
for (int i = 0; i < operands.length; i++) {
final IASTExpression operand = operands[i];
// In case of macros we may have already passed the operator position.
if (i > 0 && getCurrentPosition() < nodeOffset(operand)) {
scribe.alignFragment(alignment, i);
// Operator
final int nextToken = peekNextToken();
// In case of C++ alternative operators, like 'and', 'or', etc. a space
boolean forceSpace = Character.isJavaIdentifierStart(peekNextChar());
switch (node.getOperator()) {
case IASTBinaryExpression.op_pmdot:
case IASTBinaryExpression.op_pmarrow:
scribe.printNextToken(nextToken, false);
break;
default:
scribe.printNextToken(nextToken,
forceSpace || preferences.insert_space_before_binary_operator);
if (forceSpace || preferences.insert_space_after_binary_operator) {
scribe.space();
}
}
scribe.printTrailingComment();
}
if (i == alignment.fragmentCount - 1) {
scribe.setTailFormatter(tailFormatter);
}
operand.accept(this);
scribe.restartAtOffset(nodeEndOffset(operand));
scribe.printTrailingComment();
}
scribe.runTailFormatter();
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(alignment, true);
return PROCESS_SKIP;
}
private int formatAssignment(IASTBinaryExpression node) {
Runnable tailFormatter = scribe.takeTailFormatter();
final IASTExpression op1 = node.getOperand1();
// Operand 1
op1.accept(this);
// In case of macros we may have already passed the equal sign position.
IASTNode op2 = node.getOperand2();
if (op2 == null)
op2 = node.getInitOperand2();
if (getCurrentPosition() < nodeOffset(op2)) {
// Operator
final int nextToken = peekNextToken();
// In case of C++ alternative operators, like 'and', 'not', etc. a space
boolean forceSpace = Character.isJavaIdentifierStart(peekNextChar());
scribe.printNextToken(nextToken, forceSpace || preferences.insert_space_before_assignment_operator);
if (forceSpace || preferences.insert_space_after_assignment_operator) {
scribe.space();
}
}
Alignment expressionAlignment = scribe.createAlignment(Alignment.ASSIGNMENT_EXPRESSION,
preferences.alignment_for_assignment, Alignment.R_INNERMOST, 1, getCurrentPosition());
scribe.enterAlignment(expressionAlignment);
boolean ok = false;
do {
try {
scribe.alignFragment(expressionAlignment, 0);
scribe.setTailFormatter(tailFormatter);
// Operand 2
op2 = node.getOperand2();
if (op2 == null)
op2 = node.getInitOperand2();
op2.accept(this);
scribe.runTailFormatter();
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(expressionAlignment, true);
return PROCESS_SKIP;
}
private boolean isAssignment(IASTBinaryExpression node) {
switch (node.getOperator()) {
case IASTBinaryExpression.op_assign:
case IASTBinaryExpression.op_binaryAndAssign:
case IASTBinaryExpression.op_binaryOrAssign:
case IASTBinaryExpression.op_binaryXorAssign:
case IASTBinaryExpression.op_divideAssign:
case IASTBinaryExpression.op_minusAssign:
case IASTBinaryExpression.op_moduloAssign:
case IASTBinaryExpression.op_multiplyAssign:
case IASTBinaryExpression.op_plusAssign:
case IASTBinaryExpression.op_shiftLeftAssign:
case IASTBinaryExpression.op_shiftRightAssign:
return true;
}
return false;
}
private int formatOverloadedLeftShiftChain(IASTBinaryExpression binaryExpression) {
List<IASTExpression> elements = new ArrayList<>();
IASTExpression node;
do {
elements.add(binaryExpression.getOperand2());
node = binaryExpression.getOperand1();
if (!(node instanceof IASTBinaryExpression)) {
break;
}
binaryExpression = (IASTBinaryExpression) node;
} while (isOverloadedLeftShift(binaryExpression));
Collections.reverse(elements);
Runnable tailFormatter = scribe.takeTailFormatter();
node.accept(this);
scribe.printComment();
if (preferences.insert_space_before_binary_operator) {
scribe.space();
}
Alignment alignment = scribe.createAlignment(Alignment.OVERLOADED_LEFT_SHIFT_CHAIN,
preferences.alignment_for_overloaded_left_shift_chain, Alignment.R_OUTERMOST, elements.size(),
getCurrentPosition(), preferences.continuation_indentation, false);
scribe.enterAlignment(alignment);
boolean ok = false;
do {
try {
for (int i = 0; i < elements.size(); i++) {
node = elements.get(i);
// In case of macros we may have already passed the operator position.
if (getCurrentPosition() < nodeOffset(node)) {
scribe.alignFragment(alignment, i);
int token = peekNextToken();
if (token == Token.tSHIFTL) {
scribe.printNextToken(token, preferences.insert_space_before_binary_operator);
scribe.printTrailingComment();
if (preferences.insert_space_after_binary_operator) {
scribe.space();
}
}
}
if (i == alignment.fragmentCount - 1) {
scribe.setTailFormatter(tailFormatter);
}
node.accept(this);
}
scribe.runTailFormatter();
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
} catch (ASTProblemException e) {
}
} while (!ok);
scribe.exitAlignment(alignment, true);
return PROCESS_SKIP;
}
private boolean isOverloadedLeftShift(IASTBinaryExpression node) {
return node.getOperator() == IASTBinaryExpression.op_shiftLeft && node instanceof ICPPASTBinaryExpression
&& ((ICPPASTBinaryExpression) node).getOverload() != null;
}
private int visit(IASTLiteralExpression node) {
if (node.getKind() == IASTLiteralExpression.lk_string_literal) {
// Handle concatenation of string literals
int token;
boolean needSpace = false;
final int line = scribe.line;
boolean indented = false;
int indentationLevel = scribe.indentationLevel;
int numberOfIndentations = scribe.numberOfIndentations;
try {
final int[] stringLiterals = { Token.tSTRING, Token.tLSTRING, Token.tRSTRING };
while (true) {
scribe.printNextToken(stringLiterals, needSpace);
token = peekNextToken();
if (token != Token.tSTRING && token != Token.tLSTRING && token != Token.tRSTRING) {
break;
}
scribe.printCommentPreservingNewLines();
if (!indented && line != scribe.line) {
Alignment alignment = scribe.currentAlignment;
if (alignment != null && (alignment.mode & Alignment.M_INDENT_ON_COLUMN) != 0) {
scribe.indentationLevel = alignment.breakIndentationLevel;
} else if (alignment != null && (alignment.mode & Alignment.M_INDENT_BY_ONE) != 0) {
indented = true;
scribe.indent();
} else {
indented = true;
scribe.indentForContinuation();
}
}
needSpace = true;
}
} finally {
// Restore indentation.
scribe.indentationLevel = indentationLevel;
scribe.numberOfIndentations = numberOfIndentations;
}
} else {
scribe.printNextToken(peekNextToken());
}
return PROCESS_SKIP;
}
private int visit(IASTFieldReference node) {
IASTExpression expr = node.getFieldOwner();
if (expr != null) {
Runnable tailFormatter = scribe.takeTailFormatter();
try {
expr.accept(this);
} finally {
scribe.setTailFormatter(tailFormatter);
}
}
final IASTName fieldName = node.getFieldName();
if (fieldName != null) {
Alignment alignment = scribe.createAlignment(Alignment.FIELD_REFERENCE,
preferences.alignment_for_member_access, Alignment.R_OUTERMOST, 1, getCurrentPosition());
scribe.enterAlignment(alignment);
boolean ok = false;
do {
try {
scribe.alignFragment(alignment, 0);
scribe.printComment();
int token = peekNextToken();
if (token == Token.tARROW || token == Token.tDOT)
scribe.printNextToken(token, false);
scribe.printComment();
if (node instanceof ICPPASTFieldReference) {
if (((ICPPASTFieldReference) node).isTemplate()) {
scribe.printNextToken(Token.t_template);
scribe.space();
}
}
fieldName.accept(this);
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(alignment, true);
}
return PROCESS_SKIP;
}
private int visit(IASTArraySubscriptExpression node) {
Runnable tailFormatter = scribe.takeTailFormatter();
try {
node.getArrayExpression().accept(this);
scribe.printNextToken(Token.tLBRACKET, preferences.insert_space_before_opening_bracket);
if (preferences.insert_space_after_opening_bracket) {
scribe.space();
}
node.getArgument().accept(this);
scribe.printNextToken(Token.tRBRACKET, preferences.insert_space_before_closing_bracket);
} finally {
scribe.setTailFormatter(tailFormatter);
}
return PROCESS_SKIP;
}
private int visit(IASTTypeIdInitializerExpression node) {
scribe.printComment();
final int line = scribe.line;
node.getTypeId().accept(this);
final String brace_position = preferences.brace_position_for_initializer_list;
formatLeftCurlyBrace(line, brace_position);
formatOpeningBrace(brace_position, preferences.insert_space_before_opening_brace_in_initializer_list);
if (preferences.insert_new_line_after_opening_brace_in_initializer_list) {
scribe.printNewLine();
}
if (preferences.insert_space_after_opening_brace_in_initializer_list) {
scribe.space();
}
node.getInitializer().accept(this);
if (preferences.insert_new_line_before_closing_brace_in_initializer_list) {
scribe.startNewLine();
}
if (preferences.insert_space_before_closing_brace_in_initializer_list) {
scribe.space();
}
formatClosingBrace(brace_position);
scribe.printTrailingComment();
return PROCESS_SKIP;
}
/**
* <pre>
* new-expression:
* ::<sub>opt</sub> new new-placement<sub>opt</sub> new-type-id new-initializer<sub>opt</sub>
* ::<sub>opt</sub> new new-placement<sub>opt</sub> ( type-id ) new-initializer<sub>opt</sub>
* new-placement:
* ( expression-list )
* new-type-id:
* type-specifier-seq new-declarator<sub>opt</sub>
* new-declarator:
* ptr-operator new-declarator<sub>opt</sub>
* direct-new-declarator
* direct-new-declarator:
* [ expression ]
* direct-new-declarator [ constant-expression ]
* new-initializer:
* ( expression-list<sub>opt</sub> )
* </pre>
*/
private int visit(ICPPASTNewExpression node) {
if (node.isGlobal()) {
scribe.printNextToken(Token.tCOLONCOLON);
}
scribe.printNextToken(Token.t_new);
scribe.space();
// Placement
final IASTInitializerClause[] newPlacement = node.getPlacementArguments();
if (newPlacement != null) {
Runnable tailFormatter = scribe.takeTailFormatter();
formatFunctionCallArguments(newPlacement);
scribe.setTailFormatter(tailFormatter);
}
// type-id
scribe.space();
final IASTTypeId typeId = node.getTypeId();
final boolean expectParen = !node.isNewTypeId() && peekNextToken() == Token.tLPAREN;
if (expectParen) {
scribe.printNextToken(Token.tLPAREN, false);
}
typeId.accept(this);
if (expectParen) {
scribe.printNextToken(Token.tRPAREN);
}
// initializer
final IASTInitializer newInitializer = node.getInitializer();
if (newInitializer != null) {
visit(newInitializer);
}
return PROCESS_SKIP;
}
/**
* <pre>
* delete-expression:
* ::<sub>opt</sub> delete cast-expression
* ::<sub>opt</sub> delete [ ] cast-expression
* </pre>
*/
private int visit(ICPPASTDeleteExpression node) {
if (node.isGlobal()) {
scribe.printNextToken(Token.tCOLONCOLON);
}
scribe.printNextToken(Token.t_delete);
if (node.isVectored()) {
scribe.printNextToken(Token.tLBRACKET, preferences.insert_space_before_opening_bracket);
scribe.printNextToken(Token.tRBRACKET, preferences.insert_space_between_empty_brackets);
}
scribe.space();
node.getOperand().accept(this);
return PROCESS_SKIP;
}
private int visit(ICPPASTSimpleTypeConstructorExpression node) {
IASTDeclSpecifier declSpec = node.getDeclSpecifier();
declSpec.accept(this);
IASTInitializer initializer = node.getInitializer();
initializer.accept(this);
return PROCESS_SKIP;
}
private int visit(IASTContinueStatement node) {
formatLeadingAttributes(node);
scribe.printNextToken(Token.t_continue);
scribe.printNextToken(Token.tSEMI, preferences.insert_space_before_semicolon);
scribe.printTrailingComment();
return PROCESS_SKIP;
}
private int visit(IASTDoStatement node) {
int token = peekNextToken();
if (token == Token.t_do) {
scribe.printNextToken(token);
}
final int line = scribe.line;
final IASTStatement action = node.getBody();
formatAction(line, action, preferences.brace_position_for_block);
if (getCurrentPosition() < nodeEndOffset(node)) {
if (peekNextToken() == Token.t_while) {
if (preferences.insert_new_line_before_while_in_do_statement) {
scribe.startNewLine();
}
scribe.printNextToken(Token.t_while, preferences.insert_space_after_closing_brace_in_block);
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_while);
if (preferences.insert_space_after_opening_paren_in_while) {
scribe.space();
}
node.getCondition().accept(this);
scribe.printNextToken(Token.tRPAREN, preferences.insert_space_before_closing_paren_in_while);
}
scribe.printNextToken(Token.tSEMI, preferences.insert_space_before_semicolon);
}
scribe.printTrailingComment();
return PROCESS_SKIP;
}
private int visit(IASTNullStatement node) {
if (!fHasClauseInitStatement && nodeOffset(node) == getCurrentPosition()) {
formatAttributes(node, false, false);
scribe.printNextToken(Token.tSEMI, preferences.insert_space_before_semicolon);
scribe.printTrailingComment();
}
return PROCESS_SKIP;
}
private int visit(IASTDeclarationStatement node) {
node.getDeclaration().accept(this);
if (!fHasClauseInitStatement) {
scribe.startNewLine();
}
return PROCESS_SKIP;
}
private int visit(IASTExpressionStatement node) {
Runnable semicolonFormatter = null;
semicolonFormatter = new TrailingSemicolonFormatter(node);
scribe.setTailFormatter(semicolonFormatter);
node.getExpression().accept(this);
semicolonFormatter.run();
scribe.setTailFormatter(null);
if (!fHasClauseInitStatement) {
scribe.startNewLine();
}
return PROCESS_SKIP;
}
private int visit(IASTForStatement node) {
if (!startsWithMacroExpansion(node)) {
scribe.printNextToken(Token.t_for);
}
final int line = scribe.line;
IASTStatement initializerStmt = node.getInitializerStatement();
IASTStatement body = node.getBody();
Runnable tailFormatter = null;
if (!doNodesHaveSameOffset(node, initializerStmt)) {
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_for);
fHasClauseInitStatement = true;
if (preferences.insert_space_after_opening_paren_in_for) {
scribe.space();
}
if (DefaultCodeFormatterConstants.END_OF_LINE.equals(preferences.brace_position_for_block)
&& body instanceof IASTCompoundStatement && !startsWithMacroExpansion(body)) {
tailFormatter = new TrailingTokenFormatter(Token.tLBRACE, nodeOffset(body),
preferences.insert_space_before_opening_brace_in_block, false);
}
tailFormatter = new ClosingParensesisTailFormatter(preferences.insert_space_before_closing_paren_in_for,
tailFormatter);
}
initializerStmt.accept(this);
if (peekNextToken() == Token.tSEMI) {
scribe.printNextToken(Token.tSEMI, preferences.insert_space_before_semicolon_in_for);
}
Alignment alignment = scribe.createAlignment(Alignment.FOR, Alignment.M_COMPACT_SPLIT, Alignment.R_OUTERMOST, 2,
getCurrentPosition());
scribe.enterAlignment(alignment);
boolean ok = false;
do {
try {
try {
scribe.alignFragment(alignment, 0);
final IASTExpression condition = node.getConditionExpression();
if (condition != null) {
if (preferences.insert_space_after_semicolon_in_for) {
scribe.space();
}
condition.accept(this);
} else if (node instanceof ICPPASTForStatement) {
final IASTDeclaration conditionDecl = ((ICPPASTForStatement) node).getConditionDeclaration();
if (conditionDecl != null) {
if (preferences.insert_space_after_semicolon_in_for) {
scribe.space();
}
conditionDecl.accept(this);
}
}
if (peekNextToken() == Token.tSEMI) {
scribe.printNextToken(Token.tSEMI, preferences.insert_space_before_semicolon_in_for);
}
scribe.setTailFormatter(tailFormatter);
scribe.alignFragment(alignment, 1);
IASTExpression iterationExpr = node.getIterationExpression();
if (iterationExpr != null) {
if (preferences.insert_space_after_semicolon_in_for) {
scribe.space();
}
iterationExpr.accept(this);
}
if (tailFormatter != null) {
scribe.runTailFormatter();
scribe.setTailFormatter(null);
}
} finally {
fHasClauseInitStatement = false;
}
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(alignment, true);
if (body instanceof IASTCompoundStatement && !startsWithMacroExpansion(body)) {
if (enterNode(body)) {
if (getCurrentPosition() <= nodeOffset(body)) {
formatLeftCurlyBrace(line, preferences.brace_position_for_block);
}
formatBlock((IASTCompoundStatement) body, preferences.brace_position_for_block,
preferences.insert_space_before_opening_brace_in_block,
preferences.indent_statements_compare_to_block);
exitNode(body);
}
} else {
formatAction(line, body, preferences.brace_position_for_block);
}
scribe.printTrailingComment();
return PROCESS_SKIP;
}
private int visit(ICPPASTRangeBasedForStatement node) {
scribe.printNextToken(Token.t_for);
final int line = scribe.line;
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_for);
fHasClauseInitStatement = true;
try {
if (preferences.insert_space_after_opening_paren_in_for) {
scribe.space();
}
IASTDeclaration declaration = node.getDeclaration();
formatInlineDeclaration(declaration);
scribe.printNextToken(Token.tCOLON, true /* preferences.insert_space_before_colon_in_for */);
final IASTInitializerClause initializer = node.getInitializerClause();
if (true /*preferences.insert_space_after_colon_in_for*/) {
scribe.space();
}
initializer.accept(this);
} finally {
fHasClauseInitStatement = false;
}
if (peekNextToken() == Token.tRPAREN) {
scribe.printNextToken(Token.tRPAREN, preferences.insert_space_before_closing_paren_in_for);
}
formatAction(line, node.getBody(), preferences.brace_position_for_block);
return PROCESS_SKIP;
}
private void beginIfClause() {
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_if);
if (preferences.insert_space_after_opening_paren_in_if) {
scribe.space();
}
}
private int visit(IASTIfStatement node) {
if (!startsWithMacroExpansion(node)) {
scribe.printNextToken(Token.t_if);
}
IASTNode condition = node.getConditionExpression();
final IASTStatement thenStatement = node.getThenClause();
final IASTStatement elseStatement = node.getElseClause();
fExpectSemicolonAfterDeclaration = false;
try {
if (node instanceof ICPPASTIfStatement) {
ICPPASTIfStatement cppIfStatment = (ICPPASTIfStatement) node;
if (cppIfStatment.isConstexpr()) {
scribe.space();
scribe.printNextToken(Token.t_constexpr);
scribe.space();
}
IASTStatement initStatement = cppIfStatment.getInitializerStatement();
if (initStatement != null) {
beginIfClause();
fHasClauseInitStatement = true;
initStatement.accept(this);
if (preferences.insert_space_after_semicolon_in_for) {
scribe.space();
}
}
if (condition == null) {
condition = ((ICPPASTIfStatement) node).getConditionDeclaration();
}
}
if (condition == null || !doNodesHaveSameOffset(node, condition)) {
if (!fHasClauseInitStatement) {
beginIfClause();
}
Runnable tailFormatter = null;
if (DefaultCodeFormatterConstants.END_OF_LINE.equals(preferences.brace_position_for_block)
&& thenStatement instanceof IASTCompoundStatement && !startsWithMacroExpansion(thenStatement)) {
tailFormatter = new TrailingTokenFormatter(Token.tLBRACE, nodeOffset(thenStatement),
preferences.insert_space_before_opening_brace_in_block, false);
}
tailFormatter = new ClosingParensesisTailFormatter(preferences.insert_space_before_closing_paren_in_if,
tailFormatter);
scribe.setTailFormatter(tailFormatter);
if (condition == null || condition instanceof IASTProblemHolder) {
scribe.skipToToken(Token.tRPAREN);
} else {
condition.accept(this);
}
scribe.runTailFormatter();
scribe.setTailFormatter(null);
} else if (!(condition instanceof IASTProblemHolder)) {
condition.accept(this);
}
} finally {
fHasClauseInitStatement = false;
fExpectSemicolonAfterDeclaration = true;
}
boolean thenStatementIsBlock = false;
if (thenStatement != null) {
if (condition != null && doNodeLocationsOverlap(condition, thenStatement)) {
thenStatement.accept(this);
} else if (thenStatement instanceof IASTCompoundStatement && !startsWithMacroExpansion(thenStatement)) {
final IASTCompoundStatement block = (IASTCompoundStatement) thenStatement;
thenStatementIsBlock = true;
final List<IASTStatement> statements = Arrays.asList(block.getStatements());
if (isGuardClause(block, statements) && elseStatement == null
&& preferences.keep_guardian_clause_on_one_line) {
// Specific formatting for guard clauses. A guard clause is a block
// with a single return or throw statement.
if (getCurrentPosition() <= nodeOffset(thenStatement)) {
scribe.printNextToken(Token.tLBRACE, preferences.insert_space_before_opening_brace_in_block);
scribe.space();
}
statements.get(0).accept(this);
scribe.printNextToken(Token.tRBRACE, true);
scribe.printTrailingComment();
} else {
if (getCurrentPosition() <= nodeOffset(thenStatement)) {
formatLeftCurlyBrace(scribe.line, preferences.brace_position_for_block);
}
thenStatement.accept(this);
if (elseStatement != null && preferences.insert_new_line_before_else_in_if_statement) {
scribe.startNewLine();
}
}
} else {
if (doNodesHaveSameOffset(node, thenStatement)) {
enterNode(thenStatement);
}
if (elseStatement == null && preferences.keep_simple_if_on_one_line) {
Alignment compactIfAlignment = scribe.createAlignment(Alignment.COMPACT_IF,
preferences.alignment_for_compact_if, Alignment.R_OUTERMOST, 1, getCurrentPosition(), 1,
false);
scribe.enterAlignment(compactIfAlignment);
boolean ok = false;
do {
try {
scribe.alignFragment(compactIfAlignment, 0);
scribe.space();
thenStatement.accept(this);
ok = true;
} catch (AlignmentException e) {
scribe.redoAlignment(e);
}
} while (!ok);
scribe.exitAlignment(compactIfAlignment, true);
} else if (preferences.keep_then_statement_on_same_line) {
scribe.space();
thenStatement.accept(this);
if (elseStatement != null) {
scribe.startNewLine();
}
} else if (thenStatement instanceof IASTCompoundStatement && !enclosedInMacroExpansion(thenStatement)) {
thenStatement.accept(this);
} else {
scribe.printTrailingComment();
scribe.startNewLine();
scribe.indent();
thenStatement.accept(this);
if (elseStatement != null) {
scribe.startNewLine();
}
scribe.unIndent();
}
}
}
if (elseStatement != null) {
if (condition != null && doNodeLocationsOverlap(condition, elseStatement)) {
elseStatement.accept(this);
} else {
if (peekNextToken() == Token.t_else) {
if (thenStatementIsBlock) {
scribe.printNextToken(Token.t_else, preferences.insert_space_after_closing_brace_in_block);
} else {
scribe.printNextToken(Token.t_else, true);
}
}
if (elseStatement instanceof IASTCompoundStatement && !enclosedInMacroExpansion(elseStatement)) {
elseStatement.accept(this);
} else if (elseStatement instanceof IASTIfStatement) {
if (!preferences.compact_else_if) {
scribe.startNewLine();
scribe.indent();
}
scribe.space();
elseStatement.accept(this);
if (!preferences.compact_else_if) {
scribe.unIndent();
}
} else if (preferences.keep_else_statement_on_same_line) {
scribe.space();
elseStatement.accept(this);
} else {
scribe.startNewLine();
scribe.indent();
elseStatement.accept(this);
scribe.unIndent();
}
}
}
return PROCESS_SKIP;
}
private int visit(ICPPASTQualifiedName node) {
if (node.isFullyQualified()) {
scribe.printNextToken(Token.tCOLONCOLON);
}
for (ICPPASTNameSpecifier nameSpec : node.getQualifier()) {
nameSpec.accept(this);
if (peekNextToken() == Token.tCOLONCOLON)
scribe.printNextToken(Token.tCOLONCOLON);
}
if (peekNextToken() == Token.tCOMPL) {
// destructor
scribe.printNextToken(Token.tCOMPL, false);
}
node.getLastName().accept(this);
return PROCESS_SKIP;
}
private int visit(ICPPASTTemplateId node) {
IASTName name = node.getTemplateName();
name.accept(this);
if (peekNextToken() == Token.tLT) {
char[] simpleId = name.getSimpleID();
if (simpleId[simpleId.length - 1] == '<')
scribe.printNextToken(Token.tLT, true);
else
scribe.printNextToken(Token.tLT,
preferences.insert_space_before_opening_angle_bracket_in_template_arguments);
if (preferences.insert_space_after_opening_angle_bracket_in_template_arguments) {
scribe.space();
}
}
final IASTNode[] templateArguments = node.getTemplateArguments();
if (templateArguments.length > 0) {
final ListOptions options = new ListOptions(Alignment.M_COMPACT_SPLIT);
options.fSpaceAfterSeparator = preferences.insert_space_after_comma_in_template_arguments;
options.fSpaceBeforeSeparator = preferences.insert_space_before_comma_in_template_arguments;
options.fTieBreakRule = Alignment.R_OUTERMOST;
formatList(Arrays.asList(templateArguments), options, false, false, null);
}
if (peekNextToken() == Token.tSHIFTR) {
scribe.printComment();
if (preferences.insert_space_before_closing_angle_bracket_in_template_arguments) {
scribe.space();
}
return PROCESS_SKIP;
}
int nextToken = peekNextToken();
if (nextToken == Token.tGT)
scribe.printNextToken(Token.tGT,
preferences.insert_space_before_closing_angle_bracket_in_template_arguments);
nextToken = peekNextToken();
if (node.getPropertyInParent() != ICPPASTQualifiedName.SEGMENT_NAME || nextToken == Token.tGT) {
if (nextToken == Token.tLPAREN) {
if (preferences.insert_space_before_opening_paren_in_method_invocation)
scribe.space();
} else if (preferences.insert_space_after_closing_angle_bracket_in_template_arguments) {
// Avoid explicit space if followed by '*' or '&'.
if (nextToken != Token.tSTAR && nextToken != Token.tAMPER)
scribe.space();
} else {
scribe.printComment();
scribe.needSpace = false;
scribe.pendingSpace = false;
}
}
return PROCESS_SKIP;
}
@Override
public int visit(ICPPASTClassVirtSpecifier node) {
if (node.getKind() == ICPPASTClassVirtSpecifier.SpecifierKind.Final) {
scribe.printNextToken(Token.t_final);
}
return PROCESS_SKIP;
}
private int visit(IASTReturnStatement node) {
formatLeadingAttributes(node);
scribe.printNextToken(Token.t_return);
final IASTExpression expression = node.getReturnValue();
if (expression != null) {
scribe.space();
expression.accept(this);
}
// Sometimes the return expression is null, when it should not be.
if (expression == null && peekNextToken() != Token.tSEMI) {
scribe.skipToToken(Token.tSEMI);
}
if (peekNextToken() == Token.tSEMI) {
scribe.printNextToken(Token.tSEMI, preferences.insert_space_before_semicolon);
scribe.printTrailingComment();
}
return PROCESS_SKIP;
}
private int visit(IASTLabelStatement node) {
int indentationLevel = scribe.indentationLevel;
if (!preferences.indent_label_compare_to_statements) {
scribe.indentationLevel = 0;
}
formatLeadingAttributes(node);
node.getName().accept(this);
scribe.printNextToken(Token.tCOLON, preferences.insert_space_before_colon_in_labeled_statement);
if (preferences.insert_space_after_colon_in_labeled_statement) {
scribe.space();
}
if (preferences.insert_new_line_after_label) {
scribe.startNewLine();
}
scribe.indentationLevel = indentationLevel;
node.getNestedStatement().accept(this);
return PROCESS_SKIP;
}
private int visit(IASTCaseStatement node) {
IASTExpression constant = node.getExpression();
formatLeadingAttributes(node);
if (constant == null) {
scribe.printNextToken(Token.t_default);
scribe.printNextToken(Token.tCOLON, preferences.insert_space_before_colon_in_default);
} else {
scribe.printNextToken(Token.t_case);
scribe.space();
constant.accept(this);
scribe.printNextToken(Token.tCOLON, preferences.insert_space_before_colon_in_case);
}
return PROCESS_SKIP;
}
private int visit(IASTDefaultStatement node) {
formatLeadingAttributes(node);
scribe.printNextToken(Token.t_default);
scribe.printNextToken(Token.tCOLON, preferences.insert_space_before_colon_in_default);
return PROCESS_SKIP;
}
private int visit(IASTGotoStatement node) {
formatLeadingAttributes(node);
formatRaw(node);
return PROCESS_SKIP;
}
private void beginSwitchClause() {
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_switch);
if (preferences.insert_space_after_opening_paren_in_switch) {
scribe.space();
}
}
private int visit(IASTSwitchStatement node) {
final int headerIndent = scribe.numberOfIndentations;
formatLeadingAttributes(node);
// 'switch' keyword
if (!startsWithMacroExpansion(node)) {
scribe.printNextToken(Token.t_switch);
}
IASTNode controller = node.getControllerExpression();
try {
// optional init-statement
if (node instanceof ICPPASTSwitchStatement) {
ICPPASTSwitchStatement cppSwitchStatement = ((ICPPASTSwitchStatement) node);
IASTStatement initStatement = cppSwitchStatement.getInitializerStatement();
if (initStatement != null) {
beginSwitchClause();
fHasClauseInitStatement = true;
initStatement.accept(this);
if (preferences.insert_space_after_semicolon_in_for) {
scribe.space();
}
}
if (controller == null) {
controller = cppSwitchStatement.getControllerDeclaration();
}
}
// Controller expression
if (!doNodesHaveSameOffset(node, controller) && !fHasClauseInitStatement) {
beginSwitchClause();
}
controller.accept(this);
if (peekNextToken() == Token.tRPAREN) {
scribe.printNextToken(Token.tRPAREN, preferences.insert_space_before_closing_paren_in_switch);
}
} finally {
fHasClauseInitStatement = false;
}
// switch body
String brace_position = preferences.brace_position_for_switch;
boolean hasOpenBrace = false;
int braceIndent = -1;
IASTStatement bodyStmt = node.getBody();
if (!startsWithMacroExpansion(bodyStmt)) {
boolean insertSpaceBeforeOpeningBrace = preferences.insert_space_before_opening_brace_in_switch;
formatAttributes(bodyStmt, insertSpaceBeforeOpeningBrace, false);
hasOpenBrace = peekNextToken() == Token.tLBRACE;
formatOpeningBrace(brace_position, insertSpaceBeforeOpeningBrace);
scribe.startNewLine();
braceIndent = scribe.numberOfIndentations;
if (braceIndent > headerIndent) {
scribe.unIndent();
}
if (preferences.indent_switchstatements_compare_to_switch) {
scribe.indent();
}
}
final List<IASTStatement> statements;
if (bodyStmt instanceof IASTCompoundStatement) {
statements = Arrays.asList(((IASTCompoundStatement) bodyStmt).getStatements());
} else {
statements = Collections.singletonList(bodyStmt);
}
if (!enterNode(bodyStmt)) {
return PROCESS_SKIP;
}
final int statementsLength = statements.size();
if (statementsLength != 0) {
boolean wasACase = false;
boolean wasAStatement = false;
for (int i = 0; i < statementsLength; i++) {
final IASTStatement statement = statements.get(i);
if (doNodeLocationsOverlap(controller, statement)) {
statement.accept(this);
continue;
}
if (statement instanceof IASTCaseStatement || statement instanceof IASTDefaultStatement) {
if (wasACase) {
scribe.startNewLine();
}
if ((wasACase || wasAStatement) && preferences.indent_switchstatements_compare_to_cases) {
scribe.unIndent();
}
statement.accept(this);
scribe.printTrailingComment();
wasACase = true;
wasAStatement = false;
if (preferences.indent_switchstatements_compare_to_cases) {
scribe.indent();
}
} else if (statement instanceof IASTBreakStatement) {
if (preferences.indent_breaks_compare_to_cases) {
if (!preferences.indent_switchstatements_compare_to_cases) {
scribe.indent();
}
} else {
if ((wasACase || wasAStatement) && preferences.indent_switchstatements_compare_to_cases) {
scribe.unIndent();
}
}
if (wasACase) {
scribe.startNewLine();
}
statement.accept(this);
if (preferences.indent_breaks_compare_to_cases) {
if (!preferences.indent_switchstatements_compare_to_cases) {
scribe.unIndent();
}
} else if (preferences.indent_switchstatements_compare_to_cases) {
scribe.indent();
}
wasACase = false;
wasAStatement = true;
} else if (statement instanceof IASTCompoundStatement && !startsWithMacroExpansion(statement)) {
String bracePosition;
if (wasACase) {
if (preferences.indent_switchstatements_compare_to_cases) {
scribe.unIndent();
}
bracePosition = preferences.brace_position_for_block_in_case;
try {
enterNode(statement);
formatBlock((IASTCompoundStatement) statement, bracePosition,
preferences.insert_space_after_colon_in_case,
preferences.indent_statements_compare_to_block);
exitNode(statement);
} catch (ASTProblemException e) {
if (i < statementsLength - 1) {
final IASTStatement nextStatement = statements.get(i + 1);
skipToNode(nextStatement);
}
exitNode(statement);
}
if (preferences.indent_switchstatements_compare_to_cases) {
scribe.indent();
}
} else {
bracePosition = preferences.brace_position_for_block;
try {
enterNode(statement);
formatBlock((IASTCompoundStatement) statement, bracePosition,
preferences.insert_space_before_opening_brace_in_block,
preferences.indent_statements_compare_to_block);
exitNode(statement);
} catch (ASTProblemException e) {
if (i < statementsLength - 1) {
final IASTStatement nextStatement = statements.get(i + 1);
skipToNode(nextStatement);
}
exitNode(statement);
}
}
wasAStatement = true;
wasACase = false;
} else {
scribe.startNewLine();
try {
statement.accept(this);
} catch (ASTProblemException e) {
if (i < statementsLength - 1) {
final IASTStatement nextStatement = statements.get(i + 1);
skipToNode(nextStatement);
}
}
wasAStatement = true;
wasACase = false;
}
if (!wasACase) {
scribe.startNewLine();
}
scribe.printComment();
}
if ((wasACase || wasAStatement) && preferences.indent_switchstatements_compare_to_cases) {
scribe.unIndent();
}
}
if (!startsWithMacroExpansion(bodyStmt)) {
if (preferences.indent_switchstatements_compare_to_switch) {
scribe.unIndent();
}
if (scribe.numberOfIndentations < braceIndent) {
scribe.indent();
}
scribe.startNewLine();
if (hasOpenBrace)
formatClosingBrace(brace_position);
}
exitNode(bodyStmt);
return PROCESS_SKIP;
}
private int visit(IASTWhileStatement node) {
scribe.printNextToken(Token.t_while);
final int line = scribe.line;
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_while);
if (preferences.insert_space_after_opening_paren_in_while) {
scribe.space();
}
final IASTExpression condition = node.getCondition();
if (condition != null) {
condition.accept(this);
} else if (node instanceof ICPPASTWhileStatement) {
final IASTDeclaration conditionDecl = ((ICPPASTWhileStatement) node).getConditionDeclaration();
if (conditionDecl != null) {
conditionDecl.accept(this);
}
}
if (peekNextToken() == Token.tRPAREN) {
scribe.printNextToken(Token.tRPAREN, preferences.insert_space_before_closing_paren_in_while);
}
formatAction(line, node.getBody(), preferences.brace_position_for_block);
return PROCESS_SKIP;
}
private int visit(IASTProblemStatement node) {
throw new ASTProblemException(node.getProblem());
}
private int visit(IASTProblemExpression node) {
throw new ASTProblemException(node.getProblem());
}
private int visit(IASTProblemDeclaration node) {
throw new ASTProblemException(node.getProblem());
}
private void formatRaw(IASTNode node) {
scribe.printComment();
skipNode(node);
}
private void exitAlignments() {
while (scribe.currentAlignment != null) {
scribe.exitAlignment(scribe.currentAlignment, true);
}
}
/**
* Test whether the next node location is inside a macro expansion. If it is
* a macro expansion, formatting will be skipped until the next node outside
* the expansion is reached.
*
* @param node the AST node to be tested
* @return <code>false</code> if the node should be skipped
*/
private boolean enterNode(IASTNode node) {
int currentPosition = getCurrentPosition();
IASTFileLocation nodeLocation = getFileLocation(node);
int nodeEndOffset = -1;
if (nodeLocation != null) {
nodeEndOffset = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
if (currentPosition > nodeEndOffset)
return false; // We have already passed the end of the node.
}
scribe.enterNode();
if (node instanceof IASTProblemHolder)
return false;
IASTNodeLocation[] locations = node.getNodeLocations();
if (locations.length == 0) {
return true;
} else if (!fInsideMacroArguments && locations[0] instanceof IASTMacroExpansionLocation) {
IASTMacroExpansionLocation location = (IASTMacroExpansionLocation) locations[0];
if (locations.length <= 2 && (node instanceof IASTStatement || node instanceof IASTExpression)) {
IASTPreprocessorMacroExpansion macroExpansion = location.getExpansion();
IASTFileLocation macroLocation = macroExpansion.getFileLocation();
int macroOffset = macroLocation.getNodeOffset();
if (macroOffset >= currentPosition && !scribe.shouldSkip(macroOffset)
&& (nodeEndOffset == macroOffset + 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;
}
}
IASTFileLocation expansionLocation = location.asFileLocation();
int startOffset = expansionLocation.getNodeOffset();
int endOffset = startOffset + expansionLocation.getNodeLength();
scribe.skipRange(startOffset, endOffset);
if (locations.length == 1 && endOffset <= currentPosition) {
scribe.restartAtOffset(endOffset);
continueNode(node.getParent());
return false;
}
} else if (nodeLocation != null) {
scribe.restartAtOffset(nodeLocation.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.
*
* @param node
*/
private void exitNode(IASTNode node) {
if (node instanceof IASTProblemHolder) {
return;
}
if (scribe.skipRange()) {
IASTFileLocation fileLocation = getFileLocation(node);
if (fileLocation != null) {
int nodeEndOffset = fileLocation.getNodeOffset() + fileLocation.getNodeLength();
scribe.restartAtOffset(nodeEndOffset);
}
} else if (scribe.currentAlignmentException == null) {
// print rest of node if any
skipNode(node);
}
continueNode(node.getParent());
}
/**
* Formatting of node continues after completion of a child node. Establish next skip region.
*
* @param node
*/
private void continueNode(IASTNode node) {
if (node instanceof IASTProblemHolder || node instanceof IASTTranslationUnit) {
return;
}
IASTFileLocation fileLocation = getFileLocation(node);
if (fileLocation == null) {
return;
}
int nodeOffset = fileLocation.getNodeOffset();
int nodeEndOffset = nodeOffset + fileLocation.getNodeLength();
int currentOffset = getCurrentPosition();
if (currentOffset > nodeEndOffset) {
return;
}
if (!fInsideMacroArguments) {
IASTNodeLocation[] locations = node.getNodeLocations();
for (int i = 0; i < locations.length; i++) {
IASTNodeLocation nodeLocation = locations[i];
if (nodeLocation instanceof IASTMacroExpansionLocation) {
IASTFileLocation expansionLocation = nodeLocation.asFileLocation();
int startOffset = expansionLocation.getNodeOffset();
int endOffset = startOffset + expansionLocation.getNodeLength();
if (currentOffset <= startOffset) {
break;
}
if (currentOffset < endOffset || currentOffset == endOffset && i == locations.length - 1) {
scribe.skipRange(startOffset, endOffset);
break;
}
}
}
}
}
private int getNextTokenOffset() {
localScanner.resetTo(getCurrentPosition(), scribe.scannerEndPosition);
localScanner.getNextToken();
return localScanner.getCurrentTokenStartPosition();
}
private void skipNode(IASTNode node) {
final IASTNodeLocation fileLocation = getFileLocation(node);
if (fileLocation != null && fileLocation.getNodeLength() > 0) {
final int endOffset = fileLocation.getNodeOffset() + fileLocation.getNodeLength();
final int currentOffset = getCurrentPosition();
final int restLength = endOffset - currentOffset;
if (restLength > 0) {
scribe.printRaw(currentOffset, restLength);
}
}
}
private void skipToNode(IASTNode node) {
final IASTNodeLocation fileLocation = getFileLocation(node);
if (fileLocation != null) {
final int startOffset = fileLocation.getNodeOffset();
final int currentOffset = getCurrentPosition();
final int restLength = startOffset - currentOffset;
if (restLength > 0) {
scribe.printRaw(currentOffset, restLength);
}
}
}
private void skipNonWhitespaceToNode(IASTNode node) {
final IASTNodeLocation fileLocation = getFileLocation(node);
if (fileLocation != null) {
final int startOffset = fileLocation.getNodeOffset();
final int nextTokenOffset = getNextTokenOffset();
if (nextTokenOffset < startOffset) {
final int currentOffset = getCurrentPosition();
final int restLength = startOffset - currentOffset;
if (restLength > 0) {
scribe.printRaw(currentOffset, restLength);
}
}
}
}
/**
* Format an expression nested in parenthesis. If the operand is
* <code>null</code>, empty parenthesis are expected.
*
* @param operand
*/
private void formatParenthesizedExpression(final IASTExpression operand) {
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_parenthesized_expression);
if (preferences.insert_space_after_opening_paren_in_parenthesized_expression) {
scribe.space();
}
Runnable tailFormatter = scribe.takeTailFormatter();
try {
if (operand != null) {
operand.accept(this);
}
} finally {
scribe.setTailFormatter(tailFormatter);
}
if (peekNextToken() != Token.tRPAREN) {
if (!enclosedInMacroExpansion(operand)) {
scribe.skipToToken(Token.tRPAREN);
}
}
if (peekNextToken() == Token.tRPAREN) {
scribe.printNextToken(Token.tRPAREN,
preferences.insert_space_before_closing_paren_in_parenthesized_expression);
}
}
private void formatAction(final int line, final IASTStatement stmt, String brace_position) {
if (stmt != null) {
if (stmt instanceof IASTCompoundStatement && !startsWithMacroExpansion(stmt)) {
formatLeftCurlyBrace(line, brace_position);
if (enterNode(stmt)) {
formatBlock((IASTCompoundStatement) stmt, brace_position,
preferences.insert_space_before_opening_brace_in_block,
preferences.indent_statements_compare_to_block);
exitNode(stmt);
}
} else if (stmt instanceof IASTNullStatement) {
scribe.indent();
if (preferences.put_empty_statement_on_new_line) {
scribe.startNewLine();
}
stmt.accept(this);
scribe.unIndent();
} else {
// Don't insert a line break if we have already passed the start of the statement.
// This is possible with macro expansions.
boolean indented = false;
if (getCurrentPosition() <= nodeOffset(stmt)) {
scribe.printTrailingComment();
scribe.startNewLine();
scribe.indent();
indented = true;
}
stmt.accept(this);
if (indented)
scribe.unIndent();
}
}
}
private boolean isEmptyStatement(IASTNode node) {
IASTNodeLocation[] locations = node.getNodeLocations();
if (locations.length == 1 && node instanceof ASTNode) {
ASTNode statement = (ASTNode) node;
IASTFileLocation fileLocation = locations[0].asFileLocation();
return fileLocation.getNodeLength() == 1 && fileLocation.getNodeOffset() == statement.getOffset();
}
return false;
}
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 = getFileLocation(node);
return expansionLocation.getNodeOffset() == fileLocation.getNodeOffset();
}
return false;
}
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) {
return true;
}
return false;
}
private boolean enclosedInMacroExpansion(IASTNode node) {
if (fInsideMacroArguments)
return false;
IASTNodeLocation[] locations = node.getNodeLocations();
return locations.length == 1 && locations[0] instanceof IASTMacroExpansionLocation;
}
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;
}
IASTNodeLocation[] locations = node.getNodeLocations();
for (IASTNodeLocation location : locations) {
IASTFileLocation fileLocation = location.asFileLocation();
if (fileLocation != null) {
final int nodeOffset = fileLocation.getNodeOffset();
final int endOffset = nodeOffset + fileLocation.getNodeLength();
if (offset >= nodeOffset && offset < endOffset) {
return location instanceof IASTMacroExpansionLocation;
}
}
}
return true;
}
private int getCurrentPosition() {
return scribe.scanner.getCurrentPosition();
}
/**
* Returns <code>true</code> if the given macro expansion is followed by a semicolon on the same
* line.
*/
private boolean looksLikeStatement(IASTMacroExpansionLocation location) {
IASTFileLocation fileLocation = location.asFileLocation();
if (fileLocation == null)
return false;
int pos = fileLocation.getNodeOffset() + fileLocation.getNodeLength();
localScanner.resetTo(pos, scribe.scannerEndPosition);
Token token = localScanner.nextToken();
if (token == null || token.getType() != Token.tSEMI)
return false;
// Check if the semicolon is on the same line.
localScanner.resetTo(pos, token.getOffset());
int c;
while ((c = localScanner.getNextChar()) != -1) {
if (c == '\n')
return false;
}
return true;
}
/**
* Returns true if the two given nodes have overlapping file locations. For nodes that are
* normally separated by other tokens this is an indication that they were produced by the same
* macro expansion.
*/
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();
}
/**
* Returns true if the two given nodes have the same offset. For nodes that are normally
* separated by other tokens this is an indication that they were produced by the same macro
* expansion.
*/
private boolean doNodesHaveSameOffset(IASTNode node1, IASTNode node2) {
return nodeOffset(node1) == nodeOffset(node2);
}
private int nodeOffset(IASTNode node) {
return getFileLocation(node).getNodeOffset();
}
private int nodeEndOffset(IASTNode node) {
IASTFileLocation loc = getFileLocation(node);
return loc.getNodeOffset() + loc.getNodeLength();
}
private void formatBlock(IASTCompoundStatement block, String block_brace_position,
boolean insertSpaceBeforeOpeningBrace, boolean indentStatements) {
formatBlockOpening(block, block_brace_position, insertSpaceBeforeOpeningBrace);
formatOpenedBlock(block, block_brace_position, indentStatements);
}
private void formatBlockOpening(IASTCompoundStatement block, String block_brace_position,
boolean insertSpaceBeforeOpeningBrace) {
if (startsWithMacroExpansion(block)) {
if (!looksLikeStatement((IASTMacroExpansionLocation) block.getNodeLocations()[0])) {
scribe.startNewLine();
scribe.printComment();
}
} else if (getCurrentPosition() <= nodeOffset(block)) {
formatOpeningBrace(block_brace_position, insertSpaceBeforeOpeningBrace);
}
}
private void formatOpenedBlock(IASTCompoundStatement block, String block_brace_position, boolean indentStatements) {
final boolean startsWithStatementLikeMacro = startsWithMacroExpansion(block)
&& looksLikeStatement((IASTMacroExpansionLocation) block.getNodeLocations()[0]);
final boolean endsWithMacroExpansion = endsWithMacroExpansion(block);
IASTStatement[] statements = block.getStatements();
final int statementsLength = statements.length;
if (statementsLength != 0) {
if (!startsWithStatementLikeMacro) {
scribe.startNewLine();
if (indentStatements)
scribe.indent();
}
formatStatements(Arrays.asList(statements), !endsWithMacroExpansion);
} else {
if (!startsWithStatementLikeMacro) {
if (preferences.insert_new_line_in_empty_block)
scribe.startNewLine();
if (indentStatements)
scribe.indent();
}
}
scribe.printComment();
if (indentStatements && !startsWithStatementLikeMacro)
scribe.unIndent();
if (!endsWithMacroExpansion) {
formatClosingBrace(block_brace_position);
} else if (!startsWithMacroExpansion(block)) {
if (DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(block_brace_position)) {
scribe.unIndent();
}
}
}
private void formatLeftCurlyBrace(final int line, final String bracePosition) {
scribe.formatBrace = true;
try {
// Deal with (quite unexpected) comments right before left curly brace.
scribe.printComment();
if (DefaultCodeFormatterConstants.NEXT_LINE_ON_WRAP.equals(bracePosition)
&& (scribe.line > line || scribe.column >= preferences.page_width)) {
scribe.startNewLine();
}
} finally {
scribe.formatBrace = false;
}
}
private void formatOpeningBrace(String bracePosition, boolean insertSpaceBeforeBrace) {
if (DefaultCodeFormatterConstants.NEXT_LINE.equals(bracePosition)) {
scribe.startNewLine();
} else if (DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(bracePosition)) {
scribe.startNewLine();
scribe.indent();
}
int token = peekNextToken();
if (token == Token.tLBRACE) {
scribe.printNextToken(token, insertSpaceBeforeBrace);
}
scribe.printTrailingComment();
}
private void formatClosingBrace(String brace_position) {
int token = peekNextToken();
if (token == Token.tRBRACE) {
scribe.printNextToken(token);
}
scribe.printTrailingComment();
if (DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(brace_position)) {
scribe.unIndent();
}
}
private void formatStatements(final List<IASTStatement> statements, boolean insertNewLineAfterLastStatement) {
final int statementsLength = statements.size();
if (statementsLength > 1) {
IASTStatement firstStatement = statements.get(0);
try {
firstStatement.accept(this);
} catch (ASTProblemException e) {
skipToNode(statements.get(1));
}
final int indentLevel = scribe.indentationLevel;
for (int i = 1; i < statementsLength - 1; i++) {
final IASTStatement statement = statements.get(i);
if ((!(statement instanceof IASTNullStatement) || isEmptyStatement(statement))
&& !doNodeLocationsOverlap(statement, statements.get(i - 1))) {
scribe.startNewLine();
}
if (!enterNode(statement)) {
continue;
}
try {
statement.accept(this);
} catch (RuntimeException e) {
if (i >= statementsLength - 1) {
throw e;
}
reportFormattingProblem(e);
exitAlignments();
skipToNode(statements.get(i + 1));
while (scribe.indentationLevel < indentLevel) {
scribe.indent();
}
while (scribe.indentationLevel > indentLevel) {
scribe.unIndent();
}
}
}
final IASTStatement statement = statements.get(statementsLength - 1);
if (!(statement instanceof IASTNullStatement) && (!startsWithMacroExpansion(statement)
|| !looksLikeStatement((IASTMacroExpansionLocation) statement.getNodeLocations()[0]))) {
scribe.startNewLine();
}
statement.accept(this);
} else {
final IASTStatement statement = statements.get(0);
statement.accept(this);
}
if (insertNewLineAfterLastStatement) {
scribe.startNewLine();
}
}
private boolean commentStartsBlock(int start, int end) {
localScanner.resetTo(start, end);
if (localScanner.getNextToken() == Token.tLBRACE) {
switch (localScanner.getNextToken()) {
case Token.tBLOCKCOMMENT:
case Token.tLINECOMMENT:
return true;
}
}
return false;
}
private char peekNextChar() {
if (peekNextToken() != Token.tBADCHAR) {
char[] text = localScanner.getCurrentTokenSource();
if (text.length > 0) {
return text[0];
}
}
return 0;
}
private int peekTokenAtPosition(int pos) {
localScanner.resetTo(pos, scribe.scannerEndPosition);
int token = localScanner.getNextToken();
while (token == Token.tBLOCKCOMMENT || token == Token.tLINECOMMENT) {
token = localScanner.getNextToken();
}
return token;
}
private int peekNextToken() {
return peekNextToken(false);
}
/**
* It returns a position range if offset is included into an inactive
* preprocessor region.
* @param offset The offset to be checked
* @return The region if found, null otherwise
*/
private Position getInactivePosAt(int offset) {
for (Iterator<InactivePosition> iter = fInactivePreprocessorPositions.iterator(); iter.hasNext();) {
Position pos = iter.next();
if (pos.includes(offset)) {
return pos;
}
}
return null;
}
private int peekNextToken(boolean ignoreSkip) {
if (!ignoreSkip && scribe.shouldSkip(getCurrentPosition())) {
return Token.tBADCHAR;
}
localScanner.resetTo(getCurrentPosition(), scribe.scannerEndPosition);
int token = localScanner.getNextToken();
int currentStart = localScanner.getCurrentTokenStartPosition();
Position p = getInactivePosAt(currentStart);
while ((token == Token.tBLOCKCOMMENT || token == Token.tLINECOMMENT) || p != null) {
token = localScanner.getNextToken();
currentStart = localScanner.getCurrentTokenStartPosition();
p = getInactivePosAt(currentStart);
}
return token;
}
private boolean isSemicolonLocation(IASTNodeLocation location) {
return location instanceof IASTFileLocation && location.getNodeLength() == 1
&& peekTokenAtPosition(location.getNodeOffset()) == Token.tSEMI
&& localScanner.getCurrentTokenEndPosition() + 1 == location.getNodeOffset() + location.getNodeLength();
}
private boolean isSemicolonAtPosition(int pos) {
return peekTokenAtPosition(pos) == Token.tSEMI && localScanner.getCurrentTokenStartPosition() == pos;
}
private boolean isGuardClause(IASTCompoundStatement block, List<IASTStatement> statements) {
IASTNodeLocation fileLocation = block.getFileLocation();
if (fileLocation == null) {
return false;
}
int blockStartPosition = nodeOffset(block);
int blockLength = block.getFileLocation().getNodeLength();
if (commentStartsBlock(blockStartPosition, blockLength))
return false;
final int statementsLength = statements.size();
if (statementsLength != 1)
return false;
if (statements.get(0) instanceof IASTReturnStatement) {
return true;
}
return false;
}
/**
* Collect source positions of no-format sections in the given translation unit.
*
* @param translationUnit the {@link IASTTranslationUnit}, may be <code>null</code>
* @return a {@link List} of {@link Position}s
*/
private List<InactivePosition> collectNoFormatCodePositions(IASTTranslationUnit translationUnit) {
if (translationUnit == null || !this.preferences.use_fomatter_comment_tag) {
return Collections.emptyList();
}
String fileName = translationUnit.getFilePath();
if (fileName == null) {
return Collections.emptyList();
}
List<InactivePosition> positions = new ArrayList<>();
int inactiveCodeStart = -1;
boolean inInactiveCode = false;
IASTComment[] commentsStmts = translationUnit.getComments();
for (IASTComment commentStmt : commentsStmts) {
IASTComment statement = commentStmt;
if (!statement.isPartOfTranslationUnitFile()) {
// comment is from a different file
continue;
}
IASTNodeLocation nodeLocation = statement.getFileLocation();
if (nodeLocation == null) {
continue;
}
String comment = new String(statement.getComment());
/**
* According to JDT formatter rules, we need to evaluate the latest tag if both
* are defined at the same time in the comment.
*/
int offPos = comment.lastIndexOf(this.preferences.comment_formatter_off_tag);
int onPos = comment.lastIndexOf(this.preferences.comment_formatter_on_tag);
if (offPos != -1 && offPos > onPos) {
if (!inInactiveCode) {
inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
inInactiveCode = true;
}
} else if (onPos != -1 && onPos > offPos) {
if (inInactiveCode) {
int inactiveCodeEnd = nodeLocation.getNodeOffset();
positions.add(new InactivePosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, false));
}
inInactiveCode = false;
}
}
if (inInactiveCode) {
positions.add(
new InactivePosition(inactiveCodeStart, translationUnit.getFileLocation().getNodeLength(), false));
inInactiveCode = false;
}
return positions;
}
/**
* Collect source positions of preprocessor-hidden branches
* in the given translation unit.
*
* @param translationUnit the {@link IASTTranslationUnit}, may be <code>null</code>
* @return a {@link List} of {@link Position}s
*/
private static List<InactivePosition> collectInactiveCodePositions(IASTTranslationUnit translationUnit) {
if (translationUnit == null) {
return Collections.emptyList();
}
String fileName = translationUnit.getFilePath();
if (fileName == null) {
return Collections.emptyList();
}
List<InactivePosition> positions = new ArrayList<>();
int inactiveCodeStart = -1;
boolean inInactiveCode = false;
Stack<Boolean> inactiveCodeStack = new Stack<>();
IASTPreprocessorStatement[] preprocStmts = translationUnit.getAllPreprocessorStatements();
for (IASTPreprocessorStatement preprocStmt : preprocStmts) {
IASTPreprocessorStatement statement = preprocStmt;
if (!statement.isPartOfTranslationUnitFile()) {
// preprocessor directive is from a different file
continue;
}
IASTNodeLocation nodeLocation = statement.getFileLocation();
if (nodeLocation == null) {
continue;
}
if (statement instanceof IASTPreprocessorIfStatement) {
IASTPreprocessorIfStatement ifStmt = (IASTPreprocessorIfStatement) statement;
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifStmt.taken()) {
if (!inInactiveCode) {
inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
inInactiveCode = true;
}
}
} else if (statement instanceof IASTPreprocessorIfdefStatement) {
IASTPreprocessorIfdefStatement ifdefStmt = (IASTPreprocessorIfdefStatement) statement;
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifdefStmt.taken()) {
if (!inInactiveCode) {
inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
inInactiveCode = true;
}
}
} else if (statement instanceof IASTPreprocessorIfndefStatement) {
IASTPreprocessorIfndefStatement ifndefStmt = (IASTPreprocessorIfndefStatement) statement;
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifndefStmt.taken()) {
if (!inInactiveCode) {
inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
inInactiveCode = true;
}
}
} else if (statement instanceof IASTPreprocessorElseStatement) {
IASTPreprocessorElseStatement elseStmt = (IASTPreprocessorElseStatement) statement;
if (!elseStmt.taken() && !inInactiveCode) {
inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
inInactiveCode = true;
} else if (elseStmt.taken() && inInactiveCode) {
int inactiveCodeEnd = nodeLocation.getNodeOffset();
positions.add(new InactivePosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, true));
inInactiveCode = false;
}
} else if (statement instanceof IASTPreprocessorElifStatement) {
IASTPreprocessorElifStatement elifStmt = (IASTPreprocessorElifStatement) statement;
if (!elifStmt.taken() && !inInactiveCode) {
inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
inInactiveCode = true;
} else if (elifStmt.taken() && inInactiveCode) {
int inactiveCodeEnd = nodeLocation.getNodeOffset();
positions.add(new InactivePosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, true));
inInactiveCode = false;
}
} else if (statement instanceof IASTPreprocessorEndifStatement) {
try {
boolean wasInInactiveCode = inactiveCodeStack.pop().booleanValue();
if (inInactiveCode && !wasInInactiveCode) {
int inactiveCodeEnd = nodeLocation.getNodeOffset();
positions.add(
new InactivePosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, true));
}
inInactiveCode = wasInInactiveCode;
} catch (EmptyStackException e) {
}
}
}
if (inInactiveCode) {
// handle dangling #if?
}
return positions;
}
private boolean hasMemberInitializers(IASTFunctionDefinition node) {
return node instanceof ICPPASTFunctionDefinition
&& ((ICPPASTFunctionDefinition) node).getMemberInitializers().length > 0;
}
private int findTokenWithinNode(int tokenType, IASTNode node) {
IASTFileLocation location = getFileLocation(node);
int endOffset = location.getNodeOffset() + location.getNodeLength();
return scribe.findToken(tokenType, endOffset);
}
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);
}
}