| /******************************************************************************* |
| * 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); |
| } |
| } |