| /******************************************************************************* |
| * Copyright (c) 2014, 2021 Mateusz Matela 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/ |
| * |
| * |
| * Contributors: |
| * Mateusz Matela <mateusz.matela@gmail.com> - [formatter] Formatter does not format Java code correctly, especially when max line width is set - https://bugs.eclipse.org/303519 |
| * Mateusz Matela <mateusz.matela@gmail.com> - [formatter] IndexOutOfBoundsException in TokenManager - https://bugs.eclipse.org/462945 |
| * Mateusz Matela <mateusz.matela@gmail.com> - [formatter] follow up bug for comments - https://bugs.eclipse.org/458208 |
| * IBM Corporation - DOM AST changes for JEP 354 |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.formatter; |
| |
| import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.*; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.function.Predicate; |
| |
| import org.eclipse.jdt.core.dom.AST; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.ASTVisitor; |
| import org.eclipse.jdt.core.dom.Annotation; |
| import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; |
| import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; |
| import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; |
| import org.eclipse.jdt.core.dom.ArrayAccess; |
| import org.eclipse.jdt.core.dom.ArrayCreation; |
| import org.eclipse.jdt.core.dom.ArrayInitializer; |
| import org.eclipse.jdt.core.dom.ArrayType; |
| import org.eclipse.jdt.core.dom.AssertStatement; |
| import org.eclipse.jdt.core.dom.Assignment; |
| import org.eclipse.jdt.core.dom.BaseCallMessageSend; |
| import org.eclipse.jdt.core.dom.Block; |
| import org.eclipse.jdt.core.dom.CallinMappingDeclaration; |
| import org.eclipse.jdt.core.dom.CalloutMappingDeclaration; |
| import org.eclipse.jdt.core.dom.CastExpression; |
| import org.eclipse.jdt.core.dom.CatchClause; |
| import org.eclipse.jdt.core.dom.ClassInstanceCreation; |
| import org.eclipse.jdt.core.dom.ConditionalExpression; |
| import org.eclipse.jdt.core.dom.ConstructorInvocation; |
| import org.eclipse.jdt.core.dom.CreationReference; |
| import org.eclipse.jdt.core.dom.Dimension; |
| import org.eclipse.jdt.core.dom.DoStatement; |
| import org.eclipse.jdt.core.dom.EmptyStatement; |
| import org.eclipse.jdt.core.dom.EnhancedForStatement; |
| import org.eclipse.jdt.core.dom.EnumConstantDeclaration; |
| import org.eclipse.jdt.core.dom.EnumDeclaration; |
| import org.eclipse.jdt.core.dom.ExportsDirective; |
| import org.eclipse.jdt.core.dom.Expression; |
| import org.eclipse.jdt.core.dom.ExpressionMethodReference; |
| import org.eclipse.jdt.core.dom.ExpressionStatement; |
| import org.eclipse.jdt.core.dom.FieldDeclaration; |
| import org.eclipse.jdt.core.dom.ForStatement; |
| import org.eclipse.jdt.core.dom.GuardPredicateDeclaration; |
| import org.eclipse.jdt.core.dom.GuardedPattern; |
| import org.eclipse.jdt.core.dom.IfStatement; |
| import org.eclipse.jdt.core.dom.ImportDeclaration; |
| import org.eclipse.jdt.core.dom.InfixExpression; |
| import org.eclipse.jdt.core.dom.InfixExpression.Operator; |
| import org.eclipse.jdt.core.dom.InstanceofExpression; |
| import org.eclipse.jdt.core.dom.IntersectionType; |
| import org.eclipse.jdt.core.dom.LabeledStatement; |
| import org.eclipse.jdt.core.dom.LambdaExpression; |
| import org.eclipse.jdt.core.dom.MarkerAnnotation; |
| import org.eclipse.jdt.core.dom.MemberValuePair; |
| import org.eclipse.jdt.core.dom.MethodDeclaration; |
| import org.eclipse.jdt.core.dom.MethodInvocation; |
| import org.eclipse.jdt.core.dom.MethodSpec; |
| import org.eclipse.jdt.core.dom.ModuleDeclaration; |
| import org.eclipse.jdt.core.dom.Name; |
| import org.eclipse.jdt.core.dom.NormalAnnotation; |
| import org.eclipse.jdt.core.dom.OpensDirective; |
| import org.eclipse.jdt.core.dom.PackageDeclaration; |
| import org.eclipse.jdt.core.dom.ParameterMapping; |
| import org.eclipse.jdt.core.dom.ParameterizedType; |
| import org.eclipse.jdt.core.dom.ParenthesizedExpression; |
| import org.eclipse.jdt.core.dom.PatternInstanceofExpression; |
| import org.eclipse.jdt.core.dom.PostfixExpression; |
| import org.eclipse.jdt.core.dom.PrefixExpression; |
| import org.eclipse.jdt.core.dom.RoleTypeDeclaration; |
| import org.eclipse.jdt.core.dom.ProvidesDirective; |
| import org.eclipse.jdt.core.dom.RecordDeclaration; |
| import org.eclipse.jdt.core.dom.ReturnStatement; |
| import org.eclipse.jdt.core.dom.SingleMemberAnnotation; |
| import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.jdt.core.dom.Statement; |
| import org.eclipse.jdt.core.dom.SuperConstructorInvocation; |
| import org.eclipse.jdt.core.dom.SuperMethodInvocation; |
| import org.eclipse.jdt.core.dom.SuperMethodReference; |
| import org.eclipse.jdt.core.dom.SwitchCase; |
| import org.eclipse.jdt.core.dom.SwitchExpression; |
| import org.eclipse.jdt.core.dom.SwitchStatement; |
| import org.eclipse.jdt.core.dom.SynchronizedStatement; |
| import org.eclipse.jdt.core.dom.ThrowStatement; |
| import org.eclipse.jdt.core.dom.TryStatement; |
| import org.eclipse.jdt.core.dom.Type; |
| import org.eclipse.jdt.core.dom.TypeDeclaration; |
| import org.eclipse.jdt.core.dom.TypeMethodReference; |
| import org.eclipse.jdt.core.dom.TypeParameter; |
| import org.eclipse.jdt.core.dom.UnionType; |
| import org.eclipse.jdt.core.dom.VariableDeclaration; |
| import org.eclipse.jdt.core.dom.VariableDeclarationExpression; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.jdt.core.dom.VariableDeclarationStatement; |
| import org.eclipse.jdt.core.dom.WhileStatement; |
| import org.eclipse.jdt.core.dom.WildcardType; |
| import org.eclipse.jdt.core.dom.WithinStatement; |
| import org.eclipse.jdt.core.dom.YieldStatement; |
| import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; |
| |
| public class SpacePreparator extends ASTVisitor { |
| |
| private static final Map<Operator, Predicate<DefaultCodeFormatterOptions>> SPACE_BEFORE_OPERATOR; |
| private static final Map<Operator, Predicate<DefaultCodeFormatterOptions>> SPACE_AFTER_OPERATOR; |
| |
| static { |
| Map<Operator, Predicate<DefaultCodeFormatterOptions>> spaceBeforeOperator = new HashMap<>(); |
| Map<Operator, Predicate<DefaultCodeFormatterOptions>> spaceAfterOperator = new HashMap<>(); |
| for (Operator op : Arrays.asList(Operator.TIMES, Operator.DIVIDE, Operator.REMAINDER)) { |
| spaceBeforeOperator.put(op, o -> o.insert_space_before_multiplicative_operator); |
| spaceAfterOperator.put(op, o -> o.insert_space_after_multiplicative_operator); |
| } |
| for (Operator op : Arrays.asList(Operator.PLUS, Operator.MINUS)) { |
| spaceBeforeOperator.put(op, o -> o.insert_space_before_additive_operator); |
| spaceAfterOperator.put(op, o -> o.insert_space_after_additive_operator); |
| } |
| for (Operator op : Arrays.asList(Operator.LEFT_SHIFT, Operator.RIGHT_SHIFT_SIGNED, |
| Operator.RIGHT_SHIFT_UNSIGNED)) { |
| spaceBeforeOperator.put(op, o -> o.insert_space_before_shift_operator); |
| spaceAfterOperator.put(op, o -> o.insert_space_after_shift_operator); |
| } |
| for (Operator op : Arrays.asList(Operator.LESS, Operator.GREATER, Operator.LESS_EQUALS, |
| Operator.GREATER_EQUALS, Operator.EQUALS, Operator.NOT_EQUALS)) { |
| spaceBeforeOperator.put(op, o -> o.insert_space_before_relational_operator); |
| spaceAfterOperator.put(op, o -> o.insert_space_after_relational_operator); |
| } |
| for (Operator op : Arrays.asList(Operator.AND, Operator.XOR, Operator.OR)) { |
| spaceBeforeOperator.put(op, o -> o.insert_space_before_bitwise_operator); |
| spaceAfterOperator.put(op, o -> o.insert_space_after_bitwise_operator); |
| } |
| for (Operator op : Arrays.asList(Operator.CONDITIONAL_AND, Operator.CONDITIONAL_OR)) { |
| spaceBeforeOperator.put(op, o -> o.insert_space_before_logical_operator); |
| spaceAfterOperator.put(op, o -> o.insert_space_after_logical_operator); |
| } |
| SPACE_BEFORE_OPERATOR = Collections.unmodifiableMap(spaceBeforeOperator); |
| SPACE_AFTER_OPERATOR = Collections.unmodifiableMap(spaceAfterOperator); |
| } |
| |
| TokenManager tm; |
| private DefaultCodeFormatterOptions options; |
| |
| public SpacePreparator(TokenManager tokenManager, DefaultCodeFormatterOptions options) { |
| this.tm = tokenManager; |
| this.options = options; |
| } |
| |
| @Override |
| public boolean preVisit2(ASTNode node) { |
| boolean isMalformed = (node.getFlags() & ASTNode.MALFORMED) != 0; |
| return !isMalformed; |
| } |
| |
| @Override |
| public boolean visit(PackageDeclaration node) { |
| handleSemicolon(node); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ImportDeclaration node) { |
| handleSemicolon(node); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(TypeDeclaration node) { |
| if (this.tm.isFake(node)) |
| return true; |
| |
| handleToken(node.getName(), TokenNameIdentifier, true, false); |
| |
| List<TypeParameter> typeParameters = node.typeParameters(); |
| handleTypeParameters(typeParameters); |
| |
| if (!node.isInterface() && !node.superInterfaceTypes().isEmpty()) { |
| // fix for: class A<E> extends ArrayList<String>implements Callable<String> |
| handleToken(node.getName(), TokenNameimplements, true, false); |
| } |
| |
| handleToken(node.getName(), TokenNameLBRACE, |
| this.options.insert_space_before_opening_brace_in_type_declaration, false); |
| handleCommas(node.superInterfaceTypes(), this.options.insert_space_before_comma_in_superinterfaces, |
| this.options.insert_space_after_comma_in_superinterfaces); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(EnumDeclaration node) { |
| handleToken(node.getName(), TokenNameLBRACE, |
| this.options.insert_space_before_opening_brace_in_enum_declaration, false); |
| handleCommas(node.superInterfaceTypes(), this.options.insert_space_before_comma_in_superinterfaces, |
| this.options.insert_space_after_comma_in_superinterfaces); |
| handleCommas(node.enumConstants(), this.options.insert_space_before_comma_in_enum_declarations, |
| this.options.insert_space_after_comma_in_enum_declarations); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(EnumConstantDeclaration node) { |
| List<Expression> arguments = node.arguments(); |
| Token openingParen = null; |
| if (!arguments.isEmpty()) { |
| openingParen = this.tm.firstTokenIn(node, TokenNameLPAREN); |
| if (this.options.insert_space_after_opening_paren_in_enum_constant) |
| openingParen.spaceAfter(); |
| handleTokenAfter(arguments.get(arguments.size() - 1), TokenNameRPAREN, |
| this.options.insert_space_before_closing_paren_in_enum_constant, false); |
| } else { |
| // look for empty parenthesis, may not be there |
| int from = this.tm.firstIndexIn(node.getName(), TokenNameIdentifier) + 1; |
| AnonymousClassDeclaration classDeclaration = node.getAnonymousClassDeclaration(); |
| int to = classDeclaration != null ? this.tm.firstIndexBefore(classDeclaration, -1) |
| : this.tm.lastIndexIn(node, -1); |
| for (int i = from; i <= to; i++) { |
| if (this.tm.get(i).tokenType == TokenNameLPAREN) { |
| openingParen = this.tm.get(i); |
| if (this.options.insert_space_between_empty_parens_in_enum_constant) |
| openingParen.spaceAfter(); |
| break; |
| } |
| } |
| } |
| if (openingParen != null && this.options.insert_space_before_opening_paren_in_enum_constant) |
| openingParen.spaceBefore(); |
| handleCommas(arguments, this.options.insert_space_before_comma_in_enum_constant_arguments, |
| this.options.insert_space_after_comma_in_enum_constant_arguments); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(AnonymousClassDeclaration node) { |
| boolean spaceBeforeOpenBrace = this.options.insert_space_before_opening_brace_in_anonymous_type_declaration; |
| if (node.getParent() instanceof EnumConstantDeclaration) |
| spaceBeforeOpenBrace = this.options.insert_space_before_opening_brace_in_enum_constant; |
| handleToken(node, TokenNameLBRACE, spaceBeforeOpenBrace, false); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(RecordDeclaration node) { |
| handleToken(node.getName(), TokenNameIdentifier, true, false); |
| |
| List<TypeParameter> typeParameters = node.typeParameters(); |
| handleTypeParameters(typeParameters); |
| |
| handleToken(node.getName(), TokenNameLBRACE, |
| this.options.insert_space_before_opening_brace_in_record_declaration, false); |
| List<Type> superInterfaces = node.superInterfaceTypes(); |
| if (!superInterfaces.isEmpty()) { |
| handleTokenBefore(superInterfaces.get(0), TokenNameimplements, true, true); |
| handleCommas(superInterfaces, this.options.insert_space_before_comma_in_superinterfaces, |
| this.options.insert_space_after_comma_in_superinterfaces); |
| } |
| |
| List<SingleVariableDeclaration> components = node.recordComponents(); |
| if (handleEmptyParens(node, this.options.insert_space_between_empty_parens_in_constructor_declaration)) { |
| handleToken(node, TokenNameLPAREN, |
| this.options.insert_space_before_opening_paren_in_record_declaration, false); |
| } else { |
| handleToken(node, TokenNameLPAREN, |
| this.options.insert_space_before_opening_paren_in_record_declaration, |
| this.options.insert_space_after_opening_paren_in_record_declaration); |
| |
| if (this.options.insert_space_before_closing_paren_in_record_declaration) { |
| ASTNode nodeBeforeBrace = components.isEmpty() ? node.getName() : components.get(components.size() - 1); |
| handleTokenAfter(nodeBeforeBrace, TokenNameRPAREN, true, false); |
| } |
| } |
| handleCommas(components, this.options.insert_space_before_comma_in_record_components, |
| this.options.insert_space_after_comma_in_record_components); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(MethodDeclaration node) { |
| handleToken(node.getName(), TokenNameIdentifier, true, false); |
| |
| List<SingleVariableDeclaration> params = node.parameters(); |
| if (!node.isCompactConstructor()) { |
| boolean beforeOpenParen = node.isConstructor() |
| ? this.options.insert_space_before_opening_paren_in_constructor_declaration |
| : this.options.insert_space_before_opening_paren_in_method_declaration; |
| boolean afterOpenParen = node.isConstructor() |
| ? this.options.insert_space_after_opening_paren_in_constructor_declaration |
| : this.options.insert_space_after_opening_paren_in_method_declaration; |
| boolean betweenEmptyParens = node.isConstructor() |
| ? this.options.insert_space_between_empty_parens_in_constructor_declaration |
| : this.options.insert_space_between_empty_parens_in_method_declaration; |
| if (handleEmptyParens(node.getName(), betweenEmptyParens)) { |
| handleToken(node.getName(), TokenNameLPAREN, beforeOpenParen, false); |
| } else { |
| handleToken(node.getName(), TokenNameLPAREN, beforeOpenParen, afterOpenParen); |
| |
| boolean beforeCloseParen = node.isConstructor() |
| ? this.options.insert_space_before_closing_paren_in_constructor_declaration |
| : this.options.insert_space_before_closing_paren_in_method_declaration; |
| if (beforeCloseParen) { |
| ASTNode nodeBeforeBrace = params.isEmpty() ? node.getName() : params.get(params.size() - 1); |
| handleTokenAfter(nodeBeforeBrace, TokenNameRPAREN, true, false); |
| } |
| } |
| |
| boolean beforeComma = node.isConstructor() |
| ? this.options.insert_space_before_comma_in_constructor_declaration_parameters |
| : this.options.insert_space_before_comma_in_method_declaration_parameters; |
| boolean afterComma = node.isConstructor() |
| ? this.options.insert_space_after_comma_in_constructor_declaration_parameters |
| : this.options.insert_space_after_comma_in_method_declaration_parameters; |
| if (node.getReceiverType() != null) { |
| params = new ArrayList<>(params); |
| params.add(0, null); // space for explicit receiver, null OK - first value not read in handleCommas |
| } |
| handleCommas(params, beforeComma, afterComma); |
| } |
| |
| boolean beforeOpeningBrace = node.isCompactConstructor() |
| ? this.options.insert_space_before_opening_brace_in_record_constructor |
| : node.isConstructor() ? this.options.insert_space_before_opening_brace_in_constructor_declaration |
| : this.options.insert_space_before_opening_brace_in_method_declaration; |
| if (beforeOpeningBrace && node.getBody() != null) |
| this.tm.firstTokenIn(node.getBody(), TokenNameLBRACE).spaceBefore(); |
| |
| if (node.getReceiverType() != null) |
| this.tm.lastTokenIn(node.getReceiverType(), -1).spaceAfter(); |
| |
| List<Type> thrownExceptionTypes = node.thrownExceptionTypes(); |
| if (!thrownExceptionTypes.isEmpty()) { |
| handleTokenBefore(thrownExceptionTypes.get(0), TokenNamethrows, true, false); |
| |
| boolean beforeComma = node.isConstructor() |
| ? this.options.insert_space_before_comma_in_constructor_declaration_throws |
| : this.options.insert_space_before_comma_in_method_declaration_throws; |
| boolean afterComma = node.isConstructor() |
| ? this.options.insert_space_after_comma_in_constructor_declaration_throws |
| : this.options.insert_space_after_comma_in_method_declaration_throws; |
| handleCommas(thrownExceptionTypes, beforeComma, afterComma); |
| } |
| |
| List<TypeParameter> typeParameters = node.typeParameters(); |
| if (!typeParameters.isEmpty()) { |
| handleTypeParameters(typeParameters); |
| handleTokenBefore(typeParameters.get(0), TokenNameLESS, true, false); |
| handleTokenAfter(typeParameters.get(typeParameters.size() - 1), TokenNameGREATER, false, true); |
| } |
| |
| handleSemicolon(node); |
| return true; |
| } |
| |
| private void handleTypeParameters(List<TypeParameter> typeParameters) { |
| if (!typeParameters.isEmpty()) { |
| handleTokenBefore(typeParameters.get(0), TokenNameLESS, |
| this.options.insert_space_before_opening_angle_bracket_in_type_parameters, |
| this.options.insert_space_after_opening_angle_bracket_in_type_parameters); |
| handleTokenAfter(typeParameters.get(typeParameters.size() - 1), TokenNameGREATER, |
| this.options.insert_space_before_closing_angle_bracket_in_type_parameters, |
| this.options.insert_space_after_closing_angle_bracket_in_type_parameters); |
| handleCommas(typeParameters, this.options.insert_space_before_comma_in_type_parameters, |
| this.options.insert_space_after_comma_in_type_parameters); |
| } |
| } |
| |
| @Override |
| public boolean visit(FieldDeclaration node) { |
| handleToken((ASTNode) node.fragments().get(0), TokenNameIdentifier, true, false); |
| handleCommas(node.fragments(), this.options.insert_space_before_comma_in_multiple_field_declarations, |
| this.options.insert_space_after_comma_in_multiple_field_declarations); |
| handleSemicolon(node); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(VariableDeclarationStatement node) { |
| handleToken((ASTNode) node.fragments().get(0), TokenNameIdentifier, true, false); |
| handleCommas(node.fragments(), this.options.insert_space_before_comma_in_multiple_local_declarations, |
| this.options.insert_space_after_comma_in_multiple_local_declarations); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(VariableDeclarationFragment node) { |
| if (node.getInitializer() != null) { |
| handleToken(node.getName(), TokenNameEQUAL, this.options.insert_space_before_assignment_operator, |
| this.options.insert_space_after_assignment_operator); |
| } |
| return true; |
| } |
| |
| @Override |
| public void endVisit(SingleVariableDeclaration node) { |
| // this must be endVisit in case a space added by a visit on a child node needs to be cleared |
| if (node.isVarargs()) { |
| handleTokenBefore(node.getName(), TokenNameELLIPSIS, this.options.insert_space_before_ellipsis, |
| this.options.insert_space_after_ellipsis); |
| List<Annotation> varargsAnnotations = node.varargsAnnotations(); |
| if (!varargsAnnotations.isEmpty()) { |
| this.tm.firstTokenIn(varargsAnnotations.get(0), TokenNameAT).spaceBefore(); |
| this.tm.lastTokenIn(varargsAnnotations.get(varargsAnnotations.size() - 1), -1).clearSpaceAfter(); |
| } |
| } else { |
| handleToken(node.getName(), TokenNameIdentifier, true, false); |
| } |
| } |
| |
| @Override |
| public boolean visit(SwitchStatement node) { |
| handleToken(node, TokenNameLPAREN, this.options.insert_space_before_opening_paren_in_switch, |
| this.options.insert_space_after_opening_paren_in_switch); |
| handleTokenAfter(node.getExpression(), TokenNameRPAREN, |
| this.options.insert_space_before_closing_paren_in_switch, false); |
| handleTokenAfter(node.getExpression(), TokenNameLBRACE, |
| this.options.insert_space_before_opening_brace_in_switch, false); |
| handleSemicolon(node.statements()); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(SwitchExpression node) { |
| handleToken(node, TokenNameLPAREN, this.options.insert_space_before_opening_paren_in_switch, |
| this.options.insert_space_after_opening_paren_in_switch); |
| handleTokenAfter(node.getExpression(), TokenNameRPAREN, |
| this.options.insert_space_before_closing_paren_in_switch, false); |
| handleTokenAfter(node.getExpression(), TokenNameLBRACE, |
| this.options.insert_space_before_opening_brace_in_switch, false); |
| handleSemicolon(node.statements()); |
| return true; |
| } |
| |
| @SuppressWarnings("deprecation") |
| @Override |
| public boolean visit(SwitchCase node) { |
| if (node.getAST().apiLevel() > AST.JLS13 && node.isSwitchLabeledRule()) { |
| handleToken(this.tm.lastTokenIn(node, TokenNameARROW), |
| node.isDefault() ? this.options.insert_space_before_arrow_in_switch_default |
| : this.options.insert_space_before_arrow_in_switch_case, |
| node.isDefault() ? this.options.insert_space_after_arrow_in_switch_default |
| : this.options.insert_space_after_arrow_in_switch_case); |
| } else { |
| handleToken(this.tm.lastTokenIn(node, TokenNameCOLON), |
| node.isDefault() ? this.options.insert_space_before_colon_in_default |
| : this.options.insert_space_before_colon_in_case, |
| false); |
| } |
| if (!node.isDefault()) { |
| handleToken(node, TokenNamecase, false, true); |
| if (node.getAST().apiLevel() > AST.JLS13) { |
| handleCommas(node.expressions(), this.options.insert_space_before_comma_in_switch_case_expressions, |
| this.options.insert_space_after_comma_in_switch_case_expressions); |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(GuardedPattern node) { |
| handleTokenAfter(node.getPattern(), TokenNameAND_AND, this.options.insert_space_before_logical_operator, |
| this.options.insert_space_after_logical_operator); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(YieldStatement node) { |
| if (node.getExpression() != null && !node.isImplicit()) { |
| this.tm.firstTokenIn(node, -1).spaceAfter(); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(DoStatement node) { |
| handleTokenBefore(node.getExpression(), TokenNameLPAREN, |
| this.options.insert_space_before_opening_paren_in_while, |
| this.options.insert_space_after_opening_paren_in_while); |
| handleTokenBefore(node.getExpression(), TokenNamewhile, |
| !(node.getBody() instanceof Block) || this.options.insert_space_after_closing_brace_in_block, false); |
| handleTokenAfter(node.getExpression(), TokenNameRPAREN, |
| this.options.insert_space_before_closing_paren_in_while, false); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(WhileStatement node) { |
| handleToken(node, TokenNameLPAREN, this.options.insert_space_before_opening_paren_in_while, |
| this.options.insert_space_after_opening_paren_in_while); |
| handleTokenBefore(node.getBody(), TokenNameRPAREN, this.options.insert_space_before_closing_paren_in_while, |
| false); |
| handleLoopBody(node.getBody()); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(SynchronizedStatement node) { |
| handleToken(node, TokenNameLPAREN, this.options.insert_space_before_opening_paren_in_synchronized, |
| this.options.insert_space_after_opening_paren_in_synchronized); |
| handleTokenBefore(node.getBody(), TokenNameRPAREN, |
| this.options.insert_space_before_closing_paren_in_synchronized, false); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(TryStatement node) { |
| List<Expression> resources = node.resources(); |
| if (!resources.isEmpty()) { |
| handleToken(node, TokenNameLPAREN, this.options.insert_space_before_opening_paren_in_try, |
| this.options.insert_space_after_opening_paren_in_try); |
| handleTokenBefore(node.getBody(), TokenNameRPAREN, this.options.insert_space_before_closing_paren_in_try, |
| false); |
| for (int i = 1; i < resources.size(); i++) { |
| handleTokenBefore(resources.get(i), TokenNameSEMICOLON, |
| this.options.insert_space_before_semicolon_in_try_resources, |
| this.options.insert_space_after_semicolon_in_try_resources); |
| } |
| // there can be a semicolon after the last resource |
| int index = this.tm.firstIndexAfter(resources.get(resources.size() - 1), -1); |
| while (index < this.tm.size()) { |
| Token token = this.tm.get(index++); |
| if (token.tokenType == TokenNameSEMICOLON) { |
| handleToken(token, this.options.insert_space_before_semicolon_in_try_resources, false); |
| } else if (token.tokenType == TokenNameRPAREN) { |
| break; |
| } |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(CatchClause node) { |
| handleToken(node, TokenNameLPAREN, this.options.insert_space_before_opening_paren_in_catch, |
| this.options.insert_space_after_opening_paren_in_catch); |
| handleTokenBefore(node.getBody(), TokenNameRPAREN, this.options.insert_space_before_closing_paren_in_catch, |
| false); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(AssertStatement node) { |
| this.tm.firstTokenIn(node, TokenNameassert).spaceAfter(); |
| if (node.getMessage() != null) { |
| handleTokenBefore(node.getMessage(), TokenNameCOLON, this.options.insert_space_before_colon_in_assert, |
| this.options.insert_space_after_colon_in_assert); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ReturnStatement node) { |
| if (node.getExpression() != null) { |
| int returnTokenIndex = this.tm.firstIndexIn(node, TokenNamereturn); |
| if (!(node.getExpression() instanceof ParenthesizedExpression) |
| || this.options.insert_space_before_parenthesized_expression_in_return) { |
| this.tm.get(returnTokenIndex).spaceAfter(); |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ThrowStatement node) { |
| int returnTokenIndex = this.tm.firstIndexIn(node, TokenNamethrow); |
| if (this.tm.get(returnTokenIndex + 1).tokenType != TokenNameLPAREN |
| || this.options.insert_space_before_parenthesized_expression_in_throw) { |
| this.tm.get(returnTokenIndex).spaceAfter(); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(LabeledStatement node) { |
| handleToken(node, TokenNameCOLON, this.options.insert_space_before_colon_in_labeled_statement, |
| this.options.insert_space_after_colon_in_labeled_statement); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(AnnotationTypeDeclaration node) { |
| handleToken(node, TokenNameAT, this.options.insert_space_before_at_in_annotation_type_declaration, |
| this.options.insert_space_after_at_in_annotation_type_declaration); |
| handleToken(node.getName(), TokenNameLBRACE, |
| this.options.insert_space_before_opening_brace_in_annotation_type_declaration, false); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(AnnotationTypeMemberDeclaration node) { |
| handleToken(node.getName(), TokenNameIdentifier, true, false); |
| handleToken(node.getName(), TokenNameLPAREN, |
| this.options.insert_space_before_opening_paren_in_annotation_type_member_declaration, false); |
| handleEmptyParens(node.getName(), |
| this.options.insert_space_between_empty_parens_in_annotation_type_member_declaration); |
| if (node.getDefault() != null) |
| handleTokenBefore(node.getDefault(), TokenNamedefault, true, true); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(NormalAnnotation node) { |
| handleAnnotation(node, true); |
| handleCommas(node.values(), this.options.insert_space_before_comma_in_annotation, |
| this.options.insert_space_after_comma_in_annotation); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(MemberValuePair node) { |
| handleToken(node, TokenNameEQUAL, this.options.insert_space_before_assignment_operator, |
| this.options.insert_space_after_assignment_operator); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(SingleMemberAnnotation node) { |
| handleAnnotation(node, true); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(MarkerAnnotation node) { |
| handleAnnotation(node, false); |
| return true; |
| } |
| |
| private void handleAnnotation(Annotation node, boolean handleParenthesis) { |
| handleToken(node, TokenNameAT, false, this.options.insert_space_after_at_in_annotation); |
| if (handleParenthesis) { |
| handleToken(node, TokenNameLPAREN, this.options.insert_space_before_opening_paren_in_annotation, |
| this.options.insert_space_after_opening_paren_in_annotation); |
| if (this.options.insert_space_before_closing_paren_in_annotation) |
| this.tm.lastTokenIn(node, TokenNameRPAREN).spaceBefore(); |
| } |
| |
| ASTNode parent = node.getParent(); |
| boolean skipSpaceAfter = parent instanceof Annotation || parent instanceof MemberValuePair |
| || (parent instanceof AnnotationTypeMemberDeclaration |
| && ((AnnotationTypeMemberDeclaration) parent).getDefault() == node) |
| || parent instanceof ArrayInitializer; |
| if (!skipSpaceAfter) |
| this.tm.lastTokenIn(node, -1).spaceAfter(); |
| } |
| |
| @Override |
| public boolean visit(LambdaExpression node) { |
| handleToken(node, TokenNameARROW, this.options.insert_space_before_lambda_arrow, |
| this.options.insert_space_after_lambda_arrow); |
| List<VariableDeclaration> parameters = node.parameters(); |
| if (node.hasParentheses()) { |
| if (handleEmptyParens(node, this.options.insert_space_between_empty_parens_in_method_declaration)) { |
| handleToken(node, TokenNameLPAREN, |
| this.options.insert_space_before_opening_paren_in_method_declaration, false); |
| } else { |
| handleToken(node, TokenNameLPAREN, |
| this.options.insert_space_before_opening_paren_in_method_declaration, |
| this.options.insert_space_after_opening_paren_in_method_declaration); |
| |
| handleTokenBefore(node.getBody(), TokenNameRPAREN, |
| this.options.insert_space_before_closing_paren_in_method_declaration, false); |
| } |
| handleCommas(parameters, this.options.insert_space_before_comma_in_method_declaration_parameters, |
| this.options.insert_space_after_comma_in_method_declaration_parameters); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(Block node) { |
| handleSemicolon(node.statements()); |
| |
| ASTNode parent = node.getParent(); |
| if (parent.getLength() == 0) |
| return true; // this is a fake block created by parsing in statements mode |
| if (parent instanceof MethodDeclaration) |
| return true; // spaces handled in #visit(MethodDeclaration) |
| |
| handleToken(node, TokenNameLBRACE, this.options.insert_space_before_opening_brace_in_block, false); |
| if (this.options.insert_space_after_closing_brace_in_block |
| && (parent instanceof Statement || parent instanceof CatchClause)) { |
| int closeBraceIndex = this.tm.lastIndexIn(node, TokenNameRBRACE); |
| this.tm.get(closeBraceIndex).spaceAfter(); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(IfStatement node) { |
| handleToken(node, TokenNameLPAREN, this.options.insert_space_before_opening_paren_in_if, |
| this.options.insert_space_after_opening_paren_in_if); |
| |
| Statement thenStatement = node.getThenStatement(); |
| handleTokenBefore(thenStatement, TokenNameRPAREN, this.options.insert_space_before_closing_paren_in_if, false); |
| |
| handleLoopBody(thenStatement); |
| handleSemicolon(thenStatement); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ForStatement node) { |
| handleToken(node, TokenNameLPAREN, this.options.insert_space_before_opening_paren_in_for, |
| this.options.insert_space_after_opening_paren_in_for); |
| handleTokenBefore(node.getBody(), TokenNameRPAREN, |
| this.options.insert_space_before_closing_paren_in_for, false); |
| handleCommas(node.initializers(), this.options.insert_space_before_comma_in_for_inits, |
| this.options.insert_space_after_comma_in_for_inits); |
| handleCommas(node.updaters(), this.options.insert_space_before_comma_in_for_increments, |
| this.options.insert_space_after_comma_in_for_increments); |
| |
| boolean part1Empty = node.initializers().isEmpty(); |
| boolean part2Empty = node.getExpression() == null; |
| boolean part3Empty = node.updaters().isEmpty(); |
| handleToken(node, TokenNameSEMICOLON, this.options.insert_space_before_semicolon_in_for && !part1Empty, |
| this.options.insert_space_after_semicolon_in_for && !part2Empty); |
| handleTokenBefore(node.getBody(), TokenNameSEMICOLON, |
| this.options.insert_space_before_semicolon_in_for && !part2Empty, |
| this.options.insert_space_after_semicolon_in_for && !part3Empty); |
| |
| handleLoopBody(node.getBody()); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(VariableDeclarationExpression node) { |
| ASTNode parent = node.getParent(); |
| if (parent instanceof ForStatement) { |
| handleCommas(node.fragments(), this.options.insert_space_before_comma_in_for_inits, |
| this.options.insert_space_after_comma_in_for_inits); |
| } else if (parent instanceof ExpressionStatement) { |
| handleCommas(node.fragments(), this.options.insert_space_before_comma_in_multiple_local_declarations, |
| this.options.insert_space_after_comma_in_multiple_local_declarations); |
| } |
| this.tm.firstTokenAfter(node.getType(), -1).spaceBefore(); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(EnhancedForStatement node) { |
| handleToken(node, TokenNameLPAREN, this.options.insert_space_before_opening_paren_in_for, |
| this.options.insert_space_after_opening_paren_in_for); |
| handleTokenBefore(node.getBody(), TokenNameRPAREN, |
| this.options.insert_space_before_closing_paren_in_for, false); |
| handleTokenAfter(node.getParameter(), TokenNameCOLON, this.options.insert_space_before_colon_in_for, |
| this.options.insert_space_after_colon_in_for); |
| handleLoopBody(node.getBody()); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(MethodInvocation node) { |
| handleTypeArguments(node.typeArguments()); |
| handleInvocation(node, node.getName()); |
| handleCommas(node.arguments(), this.options.insert_space_before_comma_in_method_invocation_arguments, |
| this.options.insert_space_after_comma_in_method_invocation_arguments); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(SuperMethodInvocation node) { |
| handleTypeArguments(node.typeArguments()); |
| handleInvocation(node, node.getName()); |
| handleCommas(node.arguments(), this.options.insert_space_before_comma_in_method_invocation_arguments, |
| this.options.insert_space_after_comma_in_method_invocation_arguments); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ClassInstanceCreation node) { |
| List<Type> typeArguments = node.typeArguments(); |
| handleTypeArguments(typeArguments); |
| handleInvocation(node, node.getType(), node.getAnonymousClassDeclaration()); |
| if (!typeArguments.isEmpty()) { |
| handleTokenBefore(typeArguments.get(0), TokenNamenew, false, true); // fix for: new<Integer>A<String>() |
| } |
| handleCommas(node.arguments(), this.options.insert_space_before_comma_in_allocation_expression, |
| this.options.insert_space_after_comma_in_allocation_expression); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ConstructorInvocation node) { |
| handleTypeArguments(node.typeArguments()); |
| handleInvocation(node, node); |
| handleCommas(node.arguments(), |
| this.options.insert_space_before_comma_in_explicit_constructor_call_arguments, |
| this.options.insert_space_after_comma_in_explicit_constructor_call_arguments); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(SuperConstructorInvocation node) { |
| handleTypeArguments(node.typeArguments()); |
| handleInvocation(node, node); |
| handleCommas(node.arguments(), |
| this.options.insert_space_before_comma_in_explicit_constructor_call_arguments, |
| this.options.insert_space_after_comma_in_explicit_constructor_call_arguments); |
| return true; |
| } |
| |
| private void handleInvocation(ASTNode invocationNode, ASTNode nodeBeforeOpeningParen) { |
| handleInvocation(invocationNode, nodeBeforeOpeningParen, null); |
| } |
| |
| private void handleInvocation(ASTNode invocationNode, ASTNode nodeBeforeOpeningParen, |
| ASTNode nodeAfterClosingParen) { |
| if (handleEmptyParens(nodeBeforeOpeningParen, |
| this.options.insert_space_between_empty_parens_in_method_invocation)) { |
| handleToken(nodeBeforeOpeningParen, TokenNameLPAREN, |
| this.options.insert_space_before_opening_paren_in_method_invocation, false); |
| } else { |
| handleToken(nodeBeforeOpeningParen, TokenNameLPAREN, |
| this.options.insert_space_before_opening_paren_in_method_invocation, |
| this.options.insert_space_after_opening_paren_in_method_invocation); |
| if (this.options.insert_space_before_closing_paren_in_method_invocation) { |
| Token closingParen = nodeAfterClosingParen == null |
| ? this.tm.lastTokenIn(invocationNode, TokenNameRPAREN) |
| : this.tm.firstTokenBefore(nodeAfterClosingParen, TokenNameRPAREN); |
| closingParen.spaceBefore(); |
| } |
| } |
| } |
| |
| @Override |
| public boolean visit(Assignment node) { |
| handleOperator(node.getOperator().toString(), node.getRightHandSide(), |
| this.options.insert_space_before_assignment_operator, |
| this.options.insert_space_after_assignment_operator); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(InfixExpression node) { |
| Operator operator = node.getOperator(); |
| boolean spaceBefore = SPACE_BEFORE_OPERATOR.get(operator).test(this.options); |
| boolean spaceAfter = SPACE_AFTER_OPERATOR.get(operator).test(this.options); |
| if (this.tm.isStringConcatenation(node)) { |
| spaceBefore = this.options.insert_space_before_string_concatenation; |
| spaceAfter = this.options.insert_space_after_string_concatenation; |
| } |
| handleOperator(operator.toString(), node.getRightOperand(), spaceBefore, spaceAfter); |
| List<Expression> extendedOperands = node.extendedOperands(); |
| for (Expression operand : extendedOperands) { |
| handleOperator(operator.toString(), operand, spaceBefore, spaceAfter); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(PrefixExpression node) { |
| PrefixExpression.Operator operator = node.getOperator(); |
| if (operator.equals(PrefixExpression.Operator.INCREMENT) |
| || operator.equals(PrefixExpression.Operator.DECREMENT)) { |
| handleOperator(operator.toString(), node.getOperand(), |
| this.options.insert_space_before_prefix_operator, |
| this.options.insert_space_after_prefix_operator); |
| } else if (operator.equals(PrefixExpression.Operator.NOT)) { |
| handleOperator(operator.toString(), node.getOperand(), |
| this.options.insert_space_before_unary_operator, |
| this.options.insert_space_after_not_operator); |
| } else { |
| handleOperator(operator.toString(), node.getOperand(), |
| this.options.insert_space_before_unary_operator, |
| this.options.insert_space_after_unary_operator); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(PostfixExpression node) { |
| if (this.options.insert_space_before_postfix_operator || this.options.insert_space_after_postfix_operator) { |
| String operator = node.getOperator().toString(); |
| int i = this.tm.firstIndexAfter(node.getOperand(), -1); |
| while (!operator.equals(this.tm.toString(i))) { |
| i++; |
| } |
| handleToken(this.tm.get(i), this.options.insert_space_before_postfix_operator, |
| this.options.insert_space_after_postfix_operator); |
| } |
| return true; |
| } |
| |
| private void handleOperator(String operator, ASTNode nodeAfter, boolean spaceBefore, boolean spaceAfter) { |
| if (spaceBefore || spaceAfter) { |
| int i = this.tm.firstIndexBefore(nodeAfter, -1); |
| while (!operator.equals(this.tm.toString(i))) { |
| i--; |
| } |
| handleToken(this.tm.get(i), spaceBefore, spaceAfter); |
| } |
| } |
| |
| @Override |
| public boolean visit(ParenthesizedExpression node) { |
| handleToken(node, TokenNameLPAREN, |
| this.options.insert_space_before_opening_paren_in_parenthesized_expression, |
| this.options.insert_space_after_opening_paren_in_parenthesized_expression); |
| handleTokenAfter(node.getExpression(), TokenNameRPAREN, |
| this.options.insert_space_before_closing_paren_in_parenthesized_expression, false); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(CastExpression node) { |
| handleToken(node, TokenNameLPAREN, false, this.options.insert_space_after_opening_paren_in_cast); |
| handleTokenBefore(node.getExpression(), TokenNameRPAREN, |
| this.options.insert_space_before_closing_paren_in_cast, |
| this.options.insert_space_after_closing_paren_in_cast); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(IntersectionType node) { |
| List<Type> types = node.types(); |
| for (int i = 1; i < types.size(); i++) |
| handleTokenBefore(types.get(i), TokenNameAND, this.options.insert_space_before_bitwise_operator, |
| this.options.insert_space_after_bitwise_operator); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ConditionalExpression node) { |
| handleTokenBefore(node.getThenExpression(), TokenNameQUESTION, |
| this.options.insert_space_before_question_in_conditional, |
| this.options.insert_space_after_question_in_conditional); |
| handleTokenBefore(node.getElseExpression(), TokenNameCOLON, |
| this.options.insert_space_before_colon_in_conditional, |
| this.options.insert_space_after_colon_in_conditional); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ArrayType node) { |
| ASTNode parent = node.getParent(); |
| boolean spaceBeofreOpening, spaceBetween; |
| if (parent instanceof ArrayCreation) { |
| spaceBeofreOpening = this.options.insert_space_before_opening_bracket_in_array_allocation_expression; |
| spaceBetween = this.options.insert_space_between_empty_brackets_in_array_allocation_expression; |
| } else { |
| spaceBeofreOpening = this.options.insert_space_before_opening_bracket_in_array_type_reference; |
| spaceBetween = this.options.insert_space_between_brackets_in_array_type_reference; |
| } |
| List<Dimension> dimensions = node.dimensions(); |
| for (Dimension dimension : dimensions) { |
| handleToken(dimension, TokenNameLBRACKET, spaceBeofreOpening, false); |
| handleEmptyBrackets(dimension, spaceBetween); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ArrayAccess node) { |
| handleTokenBefore(node.getIndex(), TokenNameLBRACKET, |
| this.options.insert_space_before_opening_bracket_in_array_reference, |
| this.options.insert_space_after_opening_bracket_in_array_reference); |
| handleTokenAfter(node.getIndex(), TokenNameRBRACKET, |
| this.options.insert_space_before_closing_bracket_in_array_reference, false); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ArrayCreation node) { |
| List<Expression> dimensions = node.dimensions(); |
| for (Expression dimension : dimensions) { |
| handleTokenBefore(dimension, TokenNameLBRACKET, false, |
| this.options.insert_space_after_opening_bracket_in_array_allocation_expression); |
| handleTokenAfter(dimension, TokenNameRBRACKET, |
| this.options.insert_space_before_closing_bracket_in_array_allocation_expression, false); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ArrayInitializer node) { |
| int openingBraceIndex = this.tm.firstIndexIn(node, TokenNameLBRACE); |
| int closingBraceIndex = this.tm.lastIndexIn(node, TokenNameRBRACE); |
| Token lastToken = this.tm.get(closingBraceIndex - 1); |
| if (lastToken.tokenType == TokenNameLBRACE) { |
| handleToken(this.tm.get(openingBraceIndex), |
| this.options.insert_space_before_opening_brace_in_array_initializer |
| && !(node.getParent() instanceof ArrayInitializer) |
| && !(node.getParent() instanceof SingleMemberAnnotation), |
| this.options.insert_space_between_empty_braces_in_array_initializer); |
| } else { |
| boolean endsWithComma = lastToken.tokenType == TokenNameCOMMA; |
| handleToken(this.tm.get(openingBraceIndex), |
| this.options.insert_space_before_opening_brace_in_array_initializer |
| && !(node.getParent() instanceof ArrayInitializer) |
| && !(node.getParent() instanceof SingleMemberAnnotation), |
| this.options.insert_space_after_opening_brace_in_array_initializer |
| && !(endsWithComma && node.expressions().isEmpty())); |
| handleCommas(node.expressions(), this.options.insert_space_before_comma_in_array_initializer, |
| this.options.insert_space_after_comma_in_array_initializer); |
| if (endsWithComma) { |
| handleToken(lastToken, this.options.insert_space_before_comma_in_array_initializer, |
| false); //this.options.insert_space_after_comma_in_array_initializer); |
| } |
| handleToken(this.tm.get(closingBraceIndex), |
| this.options.insert_space_before_closing_brace_in_array_initializer |
| && !(endsWithComma && node.expressions().isEmpty()), false); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ParameterizedType node) { |
| List<Type> typeArguments = node.typeArguments(); |
| boolean hasArguments = !typeArguments.isEmpty(); |
| handleTokenAfter(node.getType(), TokenNameLESS, |
| this.options.insert_space_before_opening_angle_bracket_in_parameterized_type_reference, |
| hasArguments && this.options.insert_space_after_opening_angle_bracket_in_parameterized_type_reference); |
| if (hasArguments) { |
| handleTokenAfter(typeArguments.get(typeArguments.size() - 1), TokenNameGREATER, |
| this.options.insert_space_before_closing_angle_bracket_in_parameterized_type_reference, false); |
| handleCommas(node.typeArguments(), |
| this.options.insert_space_before_comma_in_parameterized_type_reference, |
| this.options.insert_space_after_comma_in_parameterized_type_reference); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(TypeParameter node) { |
| List<Type> typeBounds = node.typeBounds(); |
| for (int i = 1; i < typeBounds.size(); i++) { |
| handleTokenBefore(typeBounds.get(i), TokenNameAND, |
| this.options.insert_space_before_and_in_type_parameter, |
| this.options.insert_space_after_and_in_type_parameter); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(WildcardType node) { |
| handleToken(node, TokenNameQUESTION, this.options.insert_space_before_question_in_wilcard, |
| this.options.insert_space_after_question_in_wilcard || node.getBound() != null); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(UnionType node) { |
| List<Type> types = node.types(); |
| for (int i = 1; i < types.size(); i++) |
| handleTokenBefore(types.get(i), TokenNameOR, this.options.insert_space_before_bitwise_operator, |
| this.options.insert_space_after_bitwise_operator); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(Dimension node) { |
| List<Annotation> annotations = node.annotations(); |
| if (!annotations.isEmpty()) |
| handleToken(annotations.get(0), TokenNameAT, true, false); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(TypeMethodReference node) { |
| handleTypeArguments(node.typeArguments()); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ExpressionMethodReference node) { |
| handleTypeArguments(node.typeArguments()); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(SuperMethodReference node) { |
| handleTypeArguments(node.typeArguments()); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(CreationReference node) { |
| handleTypeArguments(node.typeArguments()); |
| return true; |
| } |
| |
| //{ObjectTeams: more visits: |
| @Override |
| public boolean visit(RoleTypeDeclaration node) { |
| return visit((TypeDeclaration)node); |
| } |
| @Override |
| public boolean visit(BaseCallMessageSend node) { |
| // see MethodInvocation (sauf type arguments). |
| handleInvocation(node, node.getName()); |
| handleCommas(node.getArguments(), this.options.insert_space_before_comma_in_method_invocation_arguments, |
| this.options.insert_space_after_comma_in_method_invocation_arguments); |
| return true; |
| } |
| @Override |
| public boolean visit(CalloutMappingDeclaration node) { |
| handleTokenAfter(node.getRoleMappingElement(), node.isCalloutOverride() ? TokenNameCALLOUT_OVERRIDE : TokenNameBINDOUT, true, true); |
| if (node.hasParameterMapping()) |
| handleTokenAfter(node.getBaseMappingElement(), TokenNamewith, true, true); |
| return true; |
| } |
| @Override |
| public boolean visit(CallinMappingDeclaration node) { |
| handleTokenAfter(node.getRoleMappingElement(), TokenNameBINDIN, true, true); |
| List<ASTNode> baseMappingElements = node.getBaseMappingElements(); |
| handleCommas(baseMappingElements, false, true); |
| ASTNode lastBase = baseMappingElements.get(baseMappingElements.size()-1); |
| GuardPredicateDeclaration predicate = node.getGuardPredicate(); |
| if (predicate != null) |
| handleTokenAfter(lastBase, predicate.isBase() ? TokenNamebase : TokenNamewhen, true, true); |
| if (node.hasParameterMapping()) |
| handleTokenAfter(lastBase, TokenNamewith, true, true); |
| return true; |
| } |
| @Override |
| public boolean visit(MethodSpec node) { |
| handleCommas(node.parameters(), this.options.insert_space_before_comma_in_method_declaration_parameters, |
| this.options.insert_space_after_comma_in_method_declaration_parameters); |
| return true; |
| } |
| @Override |
| public boolean visit(ParameterMapping node) { |
| if (node.isBindIN()) |
| handleTokenAfter(node.getIdentifier(), TokenNameBINDIN, true, true); |
| else |
| handleTokenBefore(node.getIdentifier(), TokenNameBINDOUT, true, true); |
| return true; |
| } |
| @Override |
| public boolean visit(GuardPredicateDeclaration node) { |
| handleToken(node, TokenNamewhen, true, true); |
| return true; |
| } |
| @Override |
| public boolean visit(WithinStatement node) { // like while |
| handleToken(node, TokenNameLPAREN, this.options.insert_space_before_opening_paren_in_while, |
| this.options.insert_space_after_opening_paren_in_while); |
| handleTokenBefore(node.getBody(), TokenNameRPAREN, this.options.insert_space_before_closing_paren_in_while, |
| false); |
| return true; |
| } |
| // SH} |
| |
| private void handleTypeArguments(List<Type> typeArguments) { |
| if (typeArguments.isEmpty()) |
| return; |
| handleTokenBefore(typeArguments.get(0), TokenNameLESS, |
| this.options.insert_space_before_opening_angle_bracket_in_type_arguments, |
| this.options.insert_space_after_opening_angle_bracket_in_type_arguments); |
| handleTokenAfter(typeArguments.get(typeArguments.size() - 1), TokenNameGREATER, |
| this.options.insert_space_before_closing_angle_bracket_in_type_arguments, |
| this.options.insert_space_after_closing_angle_bracket_in_type_arguments); |
| handleCommas(typeArguments, this.options.insert_space_before_comma_in_type_arguments, |
| this.options.insert_space_after_comma_in_type_arguments); |
| } |
| |
| @Override |
| public boolean visit(InstanceofExpression node) { |
| handleTokenAfter(node.getLeftOperand(), TokenNameinstanceof, true, true); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(PatternInstanceofExpression node) { |
| handleTokenAfter(node.getLeftOperand(), TokenNameinstanceof, true, true); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ModuleDeclaration node) { |
| handleToken(node.getName(), TokenNameLBRACE, |
| this.options.insert_space_before_opening_brace_in_type_declaration, false); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ExportsDirective node) { |
| handleModuleStatementCommas(node.modules()); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(OpensDirective node) { |
| handleModuleStatementCommas(node.modules()); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ProvidesDirective node) { |
| handleModuleStatementCommas(node.implementations()); |
| return true; |
| } |
| |
| private void handleModuleStatementCommas(List<Name> names) { |
| // using settings for fields for now, add new settings if necessary |
| handleCommas(names, this.options.insert_space_before_comma_in_multiple_field_declarations, |
| this.options.insert_space_after_comma_in_multiple_field_declarations); |
| } |
| |
| private void handleCommas(List<? extends ASTNode> nodes, boolean spaceBefore, boolean spaceAfter) { |
| if (spaceBefore || spaceAfter) { |
| for (int i = 1; i < nodes.size(); i++) { |
| handleTokenBefore(nodes.get(i), TokenNameCOMMA, spaceBefore, spaceAfter); |
| } |
| } |
| } |
| |
| private void handleToken(ASTNode node, int tokenType, boolean spaceBefore, boolean spaceAfter) { |
| if (spaceBefore || spaceAfter) { |
| Token token = this.tm.get(this.tm.findIndex(node.getStartPosition(), tokenType, true)); |
| // ^not the same as "firstTokenIn(node, tokenType)" - do not assert the token is inside the node |
| handleToken(token, spaceBefore, spaceAfter); |
| } |
| } |
| |
| private void handleTokenBefore(ASTNode node, int tokenType, boolean spaceBefore, boolean spaceAfter) { |
| if (spaceBefore || spaceAfter) { |
| Token token = this.tm.firstTokenBefore(node, tokenType); |
| handleToken(token, spaceBefore, spaceAfter); |
| } |
| } |
| |
| private void handleTokenAfter(ASTNode node, int tokenType, boolean spaceBefore, boolean spaceAfter) { |
| if (tokenType == TokenNameGREATER) { |
| // there could be ">>" or ">>>" instead, get rid of them |
| int index = this.tm.lastIndexIn(node, -1); |
| for (int i = index; i < index + 2; i++) { |
| Token token = this.tm.get(i); |
| if (token.tokenType == TokenNameRIGHT_SHIFT || token.tokenType == TokenNameUNSIGNED_RIGHT_SHIFT) { |
| this.tm.remove(i); |
| for (int j = 0; j < (token.tokenType == TokenNameRIGHT_SHIFT ? 2 : 3); j++) { |
| this.tm.insert(i + j, new Token(token.originalStart + j, token.originalStart + j, |
| TokenNameGREATER)); |
| } |
| } |
| } |
| } |
| if (spaceBefore || spaceAfter) { |
| Token token = this.tm.firstTokenAfter(node, tokenType); |
| handleToken(token, spaceBefore, spaceAfter); |
| } |
| } |
| |
| private void handleToken(Token token, boolean spaceBefore, boolean spaceAfter) { |
| if (spaceBefore) |
| token.spaceBefore(); |
| if (spaceAfter) |
| token.spaceAfter(); |
| } |
| |
| private boolean handleEmptyParens(ASTNode nodeBeforeParens, boolean insertSpace) { |
| int openingIndex = this.tm.findIndex(nodeBeforeParens.getStartPosition(), TokenNameLPAREN, true); |
| if (this.tm.get(openingIndex + 1).tokenType == TokenNameRPAREN) { |
| if (insertSpace) |
| this.tm.get(openingIndex).spaceAfter(); |
| return true; |
| } |
| return false; |
| } |
| |
| private boolean handleEmptyBrackets(ASTNode nodeContainingBrackets, boolean insertSpace) { |
| int openingIndex = this.tm.firstIndexIn(nodeContainingBrackets, TokenNameLBRACKET); |
| if (this.tm.get(openingIndex + 1).tokenType == TokenNameRBRACKET) { |
| if (insertSpace) |
| this.tm.get(openingIndex).spaceAfter(); |
| return true; |
| } |
| return false; |
| } |
| |
| private void handleSemicolon(ASTNode node) { |
| if (this.options.insert_space_before_semicolon) { |
| Token lastToken = this.tm.lastTokenIn(node, -1); |
| if (lastToken.tokenType == TokenNameSEMICOLON) |
| lastToken.spaceBefore(); |
| } |
| } |
| |
| private void handleSemicolon(List<ASTNode> nodes) { |
| if (this.options.insert_space_before_semicolon) { |
| for (ASTNode node : nodes) |
| handleSemicolon(node); |
| } |
| } |
| |
| private void handleLoopBody(Statement loopBody) { |
| /* space before body statement may be needed if it will stay on the same line */ |
| int firstTokenIndex = this.tm.firstIndexIn(loopBody, -1); |
| if (!(loopBody instanceof Block) && !(loopBody instanceof EmptyStatement) |
| && !this.tm.get(firstTokenIndex - 1).isComment()) { |
| this.tm.get(firstTokenIndex).spaceBefore(); |
| } |
| } |
| |
| public void finishUp() { |
| this.tm.traverse(0, new TokenTraverser() { |
| boolean isPreviousJIDP = false; |
| |
| @Override |
| protected boolean token(Token token, int index) { |
| // put space between consecutive keywords, numbers or identifiers |
| char c = SpacePreparator.this.tm.charAt(token.originalStart); |
| boolean isJIDP = ScannerHelper.isJavaIdentifierPart(c); |
| if ((isJIDP || c == '@') && this.isPreviousJIDP) |
| getPrevious().spaceAfter(); |
| this.isPreviousJIDP = isJIDP; |
| |
| switch (token.tokenType) { |
| case TokenNamePLUS: |
| if (getNext().tokenType == TokenNamePLUS || getNext().tokenType == TokenNamePLUS_PLUS) |
| token.spaceAfter(); |
| break; |
| case TokenNameMINUS: |
| if (getNext().tokenType == TokenNameMINUS || getNext().tokenType == TokenNameMINUS_MINUS) |
| token.spaceAfter(); |
| break; |
| } |
| return true; |
| } |
| }); |
| } |
| } |