blob: 5230805aa03c7e0162a6b65e7c5bdc024fca185b [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.formatter.java;
import com.intellij.formatting.Spacing;
import com.intellij.lang.ASTNode;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.lang.java.JavaParserDefinition;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.codeStyle.ImportHelper;
import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef;
import com.intellij.psi.impl.source.jsp.jspJava.JspClassLevelDeclarationStatement;
import com.intellij.psi.impl.source.jsp.jspJava.JspCodeBlock;
import com.intellij.psi.impl.source.jsp.jspJava.JspJavaComment;
import com.intellij.psi.impl.source.tree.*;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.tree.ChildRoleBase;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.java.IJavaElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ConcurrentHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
public class JavaSpacePropertyProcessor extends JavaElementVisitor {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.formatter.java.JavaSpacePropertyProcessor");
private PsiElement myParent;
private int myRole1;
private int myRole2;
private CommonCodeStyleSettings mySettings;
private JavaCodeStyleSettings myJavaSettings;
private Spacing myResult;
private ASTNode myChild1;
private ASTNode myChild2;
private IElementType myType1;
private IElementType myType2;
private ImportHelper myImportHelper;
private static final ThreadLocal<JavaSpacePropertyProcessor> mySharedProcessorAllocator = new ThreadLocal<JavaSpacePropertyProcessor>();
private void doInit(ASTNode child, CommonCodeStyleSettings settings, JavaCodeStyleSettings javaSettings) {
init(child);
mySettings = settings;
myJavaSettings = javaSettings;
if (myChild1 == null) {
// Given node corresponds to the first document block.
if (FormatterUtil.isFormatterCalledExplicitly()) {
createSpaceInCode(false);
}
return;
}
final PsiElement myChild1Psi1 = myChild1.getPsi();
final PsiElement myChild1Psi2 = myChild2.getPsi();
if (myChild1Psi1 == null || myChild1Psi1.getLanguage() != JavaLanguage.INSTANCE ||
myChild1Psi2 == null || myChild1Psi2.getLanguage() != JavaLanguage.INSTANCE) {
return;
}
if (myChild2 != null && StdTokenSets.COMMENT_BIT_SET.contains(myChild2.getElementType())) {
if (myChild2.getElementType() == JavaTokenType.C_STYLE_COMMENT) {
myResult = Spacing.getReadOnlySpacing();
}
else if (mySettings.KEEP_FIRST_COLUMN_COMMENT) {
myResult = Spacing.createKeepingFirstColumnSpacing(0, Integer.MAX_VALUE, true, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, 0, true, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
else {
if (myParent != null) {
myParent.accept(this);
if (myResult == null) {
final ASTNode prev = getPrevElementType(myChild2);
if (prev != null && prev.getElementType() == JavaTokenType.END_OF_LINE_COMMENT) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else if (!canStickChildrenTogether(myChild1, myChild2)) {
myResult = Spacing.createSpacing(1, Integer.MIN_VALUE, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else if (myChild1.getElementType() == JavaTokenType.C_STYLE_COMMENT){
myResult = null;
}
else if (!shouldKeepSpace(myParent)){
myResult = Spacing.createSpacing(0, 0, 0, true, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
}
}
}
private void clear() {
myResult = null;
myChild2 = myChild1 = null;
myParent = null;
myImportHelper = null;
myRole1 = myRole2 = -1;
myType1 = myType2 = null;
}
private static boolean shouldKeepSpace(final PsiElement parent) {
ASTNode node = parent.getNode();
if (node == null) {
return true;
}
final IElementType type = node.getElementType();
if (type == JavaDocElementType.DOC_TAG_VALUE_ELEMENT) {
return PsiTreeUtil.getParentOfType(parent, PsiDocMethodOrFieldRef.class) != null;
}
return type == JavaDocElementType.DOC_COMMENT || type == JavaDocElementType.DOC_TAG || type == JavaDocElementType.DOC_INLINE_TAG;
}
private void init(final ASTNode child) {
if (child == null) return;
ASTNode treePrev = child.getTreePrev();
while (treePrev != null && isWhiteSpace(treePrev)) {
treePrev = treePrev.getTreePrev();
}
if (treePrev == null) {
init(child.getTreeParent());
}
else {
myChild2 = child;
myChild1 = treePrev;
final CompositeElement parent = (CompositeElement)treePrev.getTreeParent();
myParent = SourceTreeToPsiMap.treeElementToPsi(parent);
myRole1 = parent.getChildRole(treePrev);
myType1 = treePrev.getElementType();
myRole2 = parent.getChildRole(child);
myType2 = child.getElementType();
}
}
private static boolean isWhiteSpace(final ASTNode treePrev) {
return treePrev != null && (treePrev.getElementType() == TokenType.WHITE_SPACE || treePrev.getTextLength() == 0);
}
private Spacing getResult() {
final Spacing result = myResult;
clear();
return result;
}
@Override
public void visitArrayAccessExpression(PsiArrayAccessExpression expression) {
if (myRole1 == ChildRole.ARRAY && myRole2 == ChildRole.LBRACKET) {
final boolean space = false;
createSpaceInCode(space);
}
else if (myRole1 == ChildRole.LBRACKET || myRole2 == ChildRole.RBRACKET) {
createSpaceInCode(mySettings.SPACE_WITHIN_BRACKETS);
}
}
private void createSpaceInCode(final boolean space) {
createSpaceProperty(space, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
@Override
public void visitNewExpression(PsiNewExpression expression) {
if (myRole2 == ChildRole.ARRAY_INITIALIZER) {
createSpaceInCode(mySettings.SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE);
}
else if (myRole1 == ChildRole.NEW_KEYWORD) {
createSpaceInCode(true);
}
else if (myRole2 == ChildRole.ARGUMENT_LIST) {
createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES);
}
// We don't want to insert space between brackets in case of expression like 'new int[] {1}', hence, we check that exactly
// one of the children is bracket.
else if (myRole1 == ChildRole.LBRACKET ^ myRole2 == ChildRole.RBRACKET) {
createSpaceInCode(mySettings.SPACE_WITHIN_BRACKETS);
}
}
@Override
public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) {
visitArrayInitializer();
}
@Override
public void visitClass(PsiClass aClass) {
if (myChild1.getElementType() == JavaDocElementType.DOC_COMMENT) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
return;
}
if (myRole2 == ChildRole.LBRACE) {
myResult = getSpaceBeforeClassLBrace(aClass);
}
else if (myRole1 == ChildRole.LBRACE || isEndOfLineCommentAfterLBrace(myChild1)) {
if (aClass.isEnum()) {
createParenthSpace(true, false);
}
else if (myRole2 == ChildRole.RBRACE && mySettings.KEEP_SIMPLE_CLASSES_IN_ONE_LINE) {
int spaces = mySettings.SPACE_WITHIN_BRACES ? 1 : 0;
myResult = Spacing.createSpacing(spaces, spaces, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
else if (aClass instanceof PsiAnonymousClass) {
if (myRole2 == ChildRole.CLASS_INITIALIZER && isTheOnlyClassMember(myChild2)) {
myResult = Spacing.createSpacing(0, 0, 0,
mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
else {
myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_ANONYMOUS_CLASS_HEADER + 1,
mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
else {
myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_CLASS_HEADER + 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
else if (myRole2 == ChildRole.RBRACE && aClass.isEnum()) {
createParenthSpace(true, false);
}
else if (aClass instanceof PsiAnonymousClass && ElementType.JAVA_PLAIN_COMMENT_BIT_SET.contains(myChild1.getElementType())) {
ASTNode prev = myChild1.getTreePrev();
if (prev.getElementType() == TokenType.WHITE_SPACE && !StringUtil.containsLineBreak(prev.getChars())) {
prev = prev.getTreePrev();
}
if (prev.getElementType() == JavaTokenType.LBRACE) {
myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_ANONYMOUS_CLASS_HEADER + 1,
mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
else {
processClassBody();
}
}
else if (aClass instanceof PsiAnonymousClass && myRole2 == ChildRole.ARGUMENT_LIST) {
createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES);
}
else {
processClassBody();
}
}
@NotNull
private Spacing getSpaceBeforeMethodLBrace(@NotNull PsiMethod method) {
final int space = mySettings.SPACE_BEFORE_METHOD_LBRACE ? 1 : 0;
final int methodBraceStyle = mySettings.METHOD_BRACE_STYLE;
if (methodBraceStyle == CommonCodeStyleSettings.END_OF_LINE) {
return createNonLFSpace(space, null, false);
}
else if (methodBraceStyle == CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED) {
TextRange headerRange = new TextRange(getMethodHeaderStartOffset(method), getMethodHeaderEndOffset(method));
return createNonLFSpace(space, headerRange, false);
}
else if (shouldHandleAsSimpleMethod(method)) {
TextRange rangeWithoutAnnotations = new TextRange(getMethodHeaderStartOffset(method), method.getTextRange().getEndOffset());
return createNonLFSpace(space, rangeWithoutAnnotations, false);
}
return Spacing.createSpacing(space, space, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
private static int getMethodHeaderEndOffset(@NotNull PsiMethod method) {
PsiElement headerEnd = method.getBody() != null ? method.getBody().getPrevSibling() : null;
if (headerEnd != null) {
return headerEnd.getTextRange().getEndOffset();
}
return method.getTextRange().getEndOffset();
}
@NotNull
private Spacing getSpaceBeforeClassLBrace(@NotNull PsiClass aClass) {
final int space = mySettings.SPACE_BEFORE_CLASS_LBRACE ? 1 : 0;
final int classBraceStyle = mySettings.CLASS_BRACE_STYLE;
if (classBraceStyle == CommonCodeStyleSettings.END_OF_LINE || shouldHandleAsSimpleClass(aClass)) {
return createNonLFSpace(space, null, false);
}
else if (classBraceStyle == CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED) {
final PsiIdentifier nameIdentifier = aClass.getNameIdentifier();
final int startOffset = nameIdentifier == null ? myParent.getTextRange().getStartOffset() : nameIdentifier.getTextRange().getStartOffset();
TextRange range = new TextRange(startOffset, myChild1.getTextRange().getEndOffset());
return createNonLFSpace(space, range, false);
}
return Spacing.createSpacing(space, space, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
private Spacing getSpaceBeforeLBrace(@NotNull ASTNode lBraceBlock, boolean spaceBeforeLbrace, @Nullable TextRange nextLineIfWrappedOptionRange) {
int space = spaceBeforeLbrace ? 1 : 0;
if (mySettings.BRACE_STYLE == CommonCodeStyleSettings.END_OF_LINE) {
return createNonLFSpace(space, null, false);
}
else if (mySettings.BRACE_STYLE == CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED) {
return createNonLFSpace(space, nextLineIfWrappedOptionRange, false);
}
else if (shouldHandleAsSimpleBlock(lBraceBlock)) {
return createNonLFSpace(space, lBraceBlock.getTextRange(), false);
}
return Spacing.createSpacing(space, space, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
private boolean shouldHandleAsSimpleClass(@NotNull PsiClass aClass) {
if (!mySettings.KEEP_SIMPLE_CLASSES_IN_ONE_LINE) return false;
final PsiElement lBrace = aClass.getLBrace();
final PsiElement rBrace = aClass.getRBrace();
if (lBrace != null && rBrace != null) {
PsiElement beforeLBrace = lBrace.getPrevSibling();
if (beforeLBrace instanceof PsiWhiteSpace && beforeLBrace.textContains('\n')) {
return false;
}
PsiElement betweenBraces = lBrace.getNextSibling();
if (betweenBraces == rBrace || isWhiteSpaceWithoutLinefeeds(betweenBraces) && betweenBraces.getNextSibling() == rBrace) {
return true;
}
}
return false;
}
private static boolean isWhiteSpaceWithoutLinefeeds(@Nullable PsiElement betweenBraces) {
return betweenBraces instanceof PsiWhiteSpace && !betweenBraces.textContains('\n');
}
private boolean shouldHandleAsSimpleBlock(@NotNull ASTNode node) {
if (!mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE) return false;
PsiElement prev = node.getPsi().getPrevSibling();
if (prev instanceof PsiWhiteSpace && prev.textContains('\n')) {
return false;
}
return !node.textContains('\n');
}
private boolean shouldHandleAsSimpleMethod(@NotNull PsiMethod method) {
if (!mySettings.KEEP_SIMPLE_METHODS_IN_ONE_LINE) return false;
boolean skipElement = true;
for (PsiElement element : method.getChildren()) {
if (element instanceof PsiTypeElement) skipElement = false;
if (skipElement) continue;
if (element.textContains('\n')) {
return false;
}
}
return true;
}
private static int getMethodHeaderStartOffset(@NotNull PsiMethod method) {
for (PsiElement element : method.getChildren()) {
if (element instanceof PsiTypeElement) {
return element.getTextRange().getStartOffset();
}
}
return method.getTextRange().getStartOffset();
}
private static boolean isEndOfLineCommentAfterLBrace(@NotNull ASTNode node) {
if (node.getPsi() instanceof PsiComment) {
PsiElement ws = node.getPsi().getPrevSibling();
if (isWhiteSpaceWithoutLinefeeds(ws)) {
PsiElement beforeWs = ws.getPrevSibling();
if (beforeWs instanceof PsiJavaToken && ((PsiJavaToken)beforeWs).getTokenType() == JavaTokenType.LBRACE) {
return true;
}
}
}
return false;
}
private static boolean isTheOnlyClassMember(final ASTNode node) {
ASTNode next = node.getTreeNext();
if (next == null || !(next.getElementType() == JavaTokenType.RBRACE)) return false;
ASTNode prev = node.getTreePrev();
if (prev == null || !(prev.getElementType() == JavaTokenType.LBRACE)) return false;
return true;
}
private void processClassBody() {
if (myChild1 instanceof JspJavaComment || myChild2 instanceof JspJavaComment) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, 0);
}
else if (processMethod()) {
}
else if (myRole2 == ChildRole.CLASS_INITIALIZER) {
if (myRole1 == ChildRole.LBRACE) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else if (myRole1 == ChildRole.FIELD) {
int lines = Math.max(getLinesAroundField(), getLinesAroundMethod()) + 1;
// IJ has been keeping initialization block which starts at the same line as a field for a while.
// However, it's not convenient for a situation when particular code is created via PSI - it's easier to not bothering
// with whitespace elements when inserting, say, new initialization blocks. That's why we don't enforce new line
// only during explicit reformatting ('Reformat' action).
//int minLineFeeds = FormatterUtil.isFormatterCalledExplicitly() ? 0 : 1;
myResult = Spacing.createSpacing(0, mySettings.SPACE_BEFORE_CLASS_LBRACE ? 1 : 0, 1, true, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE, lines);
}
else if (myRole1 == ChildRole.CLASS) {
setAroundClassSpacing();
}
else {
final int blankLines = getLinesAroundMethod() + 1;
myResult = Spacing.createSpacing(0, 0, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
else if (myRole1 == ChildRole.CLASS_INITIALIZER) {
if (myRole2 == ChildRole.RBRACE) {
int minLineFeeds = getMinLineFeedsBetweenRBraces(myChild1);
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, minLineFeeds, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
}
else if (myRole2 == ChildRole.CLASS) {
setAroundClassSpacing();
}
else {
final int blankLines = getLinesAroundMethod() + 1;
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
else if (myRole1 == ChildRole.CLASS) {
if (myRole2 == ChildRole.RBRACE) {
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
}
else {
final int blankLines = mySettings.BLANK_LINES_AROUND_CLASS + 1;
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
else if (myRole2 == ChildRole.CLASS) {
if (myRole1 == ChildRole.LBRACE) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, 0);
}
else {
final int blankLines = mySettings.BLANK_LINES_AROUND_CLASS + 1;
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
else if (myRole2 == ChildRole.FIELD) {
if (myRole1 == ChildRole.COMMA) {
createSpaceProperty(true, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else if (myRole1 == ChildRole.LBRACE) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, 0);
}
else {
final int blankLines = getLinesAroundField() + 1;
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
else if (myRole1 == ChildRole.FIELD) {
if (myRole2 == ChildRole.COMMA) {
ASTNode lastChildNode = myChild1.getLastChildNode();
if (lastChildNode != null && lastChildNode.getElementType() == JavaTokenType.SEMICOLON) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
else {
createSpaceProperty(false, false, 0);
}
}
else if (myRole2 == ChildRole.RBRACE) {
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
}
else {
final int blankLines = getLinesAroundField() + 1;
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
else if (myRole2 == ChildRole.COMMA || myChild2.getElementType() == JavaTokenType.SEMICOLON) {
createSpaceProperty(false, false, 0);
}
else if (myRole1 == ChildRole.COMMA) {
createSpaceProperty(mySettings.SPACE_AFTER_COMMA, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
else if (myRole1 == ChildRole.MODIFIER_LIST) {
processModifierList();
}
else if (myRole1 == ChildRole.LBRACE && myRole2 == ChildRole.RBRACE) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
}
else if (myRole2 == ChildRole.EXTENDS_LIST || myRole2 == ChildRole.IMPLEMENTS_LIST) {
createSpaceInCode(true);
}
else if (myRole2 == ChildRole.TYPE_PARAMETER_LIST) {
createSpaceInCode(myJavaSettings.SPACE_BEFORE_OPENING_ANGLE_BRACKET_IN_TYPE_PARAMETER);
}
else if (myRole2 == ChildRole.ARGUMENT_LIST) {
createSpaceInCode(false);
}
else if (myRole2 == ChildRole.RBRACE) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
}
}
/**
* Initializes {@link #myResult} property with {@link Spacing} which <code>'min line feeds'</code> property is defined
* from {@link CodeStyleSettings#BLANK_LINES_AROUND_CLASS} value.
*/
private void setAroundClassSpacing() {
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, mySettings.BLANK_LINES_AROUND_CLASS + 1,
mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
private boolean processMethod() {
if (myRole2 == ChildRole.METHOD || myChild2.getElementType() == JavaElementType.METHOD) {
if (myRole1 == ChildRole.LBRACE) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, 0);
}
else {
final int blankLines = getLinesAroundMethod() + 1;
myResult = Spacing.createSpacing(0, 0, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
else if (myRole1 == ChildRole.METHOD || myChild1.getElementType() == JavaElementType.METHOD) {
if (myRole1 == ChildRole.LBRACE) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, 0);
}
else {
final int blankLines = getLinesAroundMethod() + 1;
myResult = Spacing.createSpacing(0, 0, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
if (myRole2 == ChildRole.RBRACE) {
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
}
else {
final int blankLines = getLinesAroundMethod() + 1;
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
return myResult != null;
}
/**
* Allows to calculate <code>'min line feed'</code> setting of the {@link Spacing} to be used between two closing braces
* (assuming that left AST node that ends with closing brace is given to this method).
*
* @param leftNode left AST node that ends with closing brace
* @return <code>'min line feed'</code> setting of {@link Spacing} object to use for the given AST node and
* closing brace
*/
private static int getMinLineFeedsBetweenRBraces(ASTNode leftNode) {
// The general idea is to return zero in situation when opening curly braces goes one after other, e.g.
// new Expectations() {{
// foo();}}
// We don't want line feed between closing curly braces here.
if (leftNode == null || leftNode.getElementType() != JavaElementType.CLASS_INITIALIZER) {
return 1;
}
ASTNode lbraceCandidate = leftNode.getTreePrev();
return lbraceCandidate != null && lbraceCandidate.getElementType() == JavaTokenType.LBRACE ? 0 : 1;
}
private int getLinesAroundMethod() {
boolean useInterfaceMethodSpacing = !isClass(myParent) || isAbstractMethod(myChild1) && isAbstractMethod(myChild2);
return useInterfaceMethodSpacing ? mySettings.BLANK_LINES_AROUND_METHOD_IN_INTERFACE : mySettings.BLANK_LINES_AROUND_METHOD;
}
private int getLinesAroundField() {
if (isClass(myParent)) {
return mySettings.BLANK_LINES_AROUND_FIELD;
}
else {
return mySettings.BLANK_LINES_AROUND_FIELD_IN_INTERFACE;
}
}
private static boolean isClass(final PsiElement parent) {
if (parent instanceof PsiClass) {
return !((PsiClass)parent).isInterface();
}
return false;
}
private static boolean isAbstractMethod(ASTNode node) {
PsiElement element = node.getPsi();
if (element instanceof PsiMethod) {
PsiMethod method = (PsiMethod)element;
return method.getModifierList().hasModifierProperty(PsiModifier.ABSTRACT);
}
return false;
}
@Override
public void visitInstanceOfExpression(PsiInstanceOfExpression expression) {
createSpaceInCode(true);
}
@Override
public void visitEnumConstantInitializer(PsiEnumConstantInitializer enumConstantInitializer) {
if (myRole2 == ChildRole.EXTENDS_LIST || myRole2 == ChildRole.IMPLEMENTS_LIST) {
createSpaceInCode(true);
} else {
processMethod();
}
}
@Override
public void visitImportList(PsiImportList list) {
if (ElementType.IMPORT_STATEMENT_BASE_BIT_SET.contains(myChild1.getElementType()) &&
ElementType.IMPORT_STATEMENT_BASE_BIT_SET.contains(myChild2.getElementType())) {
if (myImportHelper == null) myImportHelper = new ImportHelper(mySettings.getRootSettings());
int emptyLines = myImportHelper.getEmptyLinesBetween(
SourceTreeToPsiMap.<PsiImportStatementBase>treeToPsiNotNull(myChild1),
SourceTreeToPsiMap.<PsiImportStatementBase>treeToPsiNotNull(myChild2)
) + 1;
myResult = Spacing.createSpacing(0, 0, emptyLines,
mySettings.KEEP_LINE_BREAKS,
mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
@Override
public void visitFile(PsiFile file) {
if (myType1 == JavaElementType.PACKAGE_STATEMENT) {
int lf = mySettings.BLANK_LINES_AFTER_PACKAGE + 1;
myResult = Spacing.createSpacing(0, 0, lf, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
else if (myType2 == JavaElementType.PACKAGE_STATEMENT) {
int lf = mySettings.BLANK_LINES_BEFORE_PACKAGE + 1;
myResult = Spacing.createSpacing(0, 0, lf, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
else if (myType1 == JavaElementType.IMPORT_LIST) {
int lf = mySettings.BLANK_LINES_AFTER_IMPORTS + 1;
myResult = Spacing.createSpacing(0, 0, lf, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
else if (myType2 == JavaElementType.IMPORT_LIST) {
int lf = mySettings.BLANK_LINES_BEFORE_IMPORTS + 1;
myResult = Spacing.createSpacing(0, 0, lf, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
else if (myType2 == JavaElementType.CLASS) {
int lf = mySettings.BLANK_LINES_AROUND_CLASS + 1;
myResult = Spacing.createSpacing(0, 0, lf, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
@Override
public void visitWhileStatement(PsiWhileStatement statement) {
if (myRole2 == ChildRole.LPARENTH) {
createSpaceInCode(mySettings.SPACE_BEFORE_WHILE_PARENTHESES);
}
else if (myRole1 == ChildRole.LPARENTH || myRole2 == ChildRole.RPARENTH) {
createSpaceInCode(mySettings.SPACE_WITHIN_WHILE_PARENTHESES);
}
else if (myRole2 == ChildRole.LOOP_BODY || myChild2.getElementType() == JavaElementType.CODE_BLOCK) {
if (myChild2.getElementType() == JavaElementType.BLOCK_STATEMENT) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_WHILE_LBRACE, null);
} else {
createSpacingBeforeElementInsideControlStatement();
}
}
}
@Override
public void visitDoWhileStatement(PsiDoWhileStatement statement) {
if (myRole1 == ChildRole.WHILE_KEYWORD && myRole2 == ChildRole.LPARENTH) {
createSpaceInCode(mySettings.SPACE_BEFORE_WHILE_PARENTHESES);
}
else if (myRole1 == ChildRole.LPARENTH || myRole2 == ChildRole.RPARENTH) {
createSpaceInCode(mySettings.SPACE_WITHIN_WHILE_PARENTHESES);
}
else if (myRole2 == ChildRole.LOOP_BODY) {
if (myChild2.getElementType() == JavaElementType.BLOCK_STATEMENT) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_DO_LBRACE, null);
} else {
createSpacingBeforeElementInsideControlStatement();
}
}
else if (myRole1 == ChildRole.LOOP_BODY || myChild2.getElementType() == JavaElementType.CODE_BLOCK) {
processOnNewLineCondition(mySettings.WHILE_ON_NEW_LINE, mySettings.SPACE_BEFORE_WHILE_KEYWORD);
}
}
private void processOnNewLineCondition(final boolean onNewLine) {
processOnNewLineCondition(onNewLine, true);
}
private void processOnNewLineCondition(final boolean onNewLine, final boolean createSpaceInline) {
if (onNewLine) {
if (!mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
myResult = Spacing.createDependentLFSpacing(0, 1, myParent.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
else {
createSpaceProperty(createSpaceInline, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
@Override
public void visitThrowStatement(PsiThrowStatement statement) {
if (myChild1.getElementType() == JavaTokenType.THROW_KEYWORD) {
createSpaceInCode(true);
}
}
@Override
public void visitTryStatement(PsiTryStatement statement) {
if (myRole2 == ChildRole.FINALLY_KEYWORD || myRole2 == ChildRole.CATCH_SECTION) {
boolean putRightChildOnNewLine = myRole2 == ChildRole.FINALLY_KEYWORD ? mySettings.FINALLY_ON_NEW_LINE : mySettings.CATCH_ON_NEW_LINE;
if (putRightChildOnNewLine) {
processOnNewLineCondition(true);
} else {
boolean useSpace = myRole2 == ChildRole.CATCH_SECTION && mySettings.SPACE_BEFORE_CATCH_KEYWORD
|| myRole2 == ChildRole.FINALLY_KEYWORD && mySettings.SPACE_BEFORE_FINALLY_KEYWORD;
createSpaceProperty(useSpace, false, 0);
}
return;
}
if (myRole2 == ChildRole.TRY_BLOCK) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_TRY_LBRACE, null);
}
else if (myRole2 == ChildRole.FINALLY_BLOCK) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_FINALLY_LBRACE, null);
}
else if (myType2 == JavaElementType.RESOURCE_LIST) {
createSpaceInCode(mySettings.SPACE_BEFORE_TRY_PARENTHESES);
}
}
@Override
public void visitForeachStatement(PsiForeachStatement statement) {
if (myRole1 == ChildRole.FOR_KEYWORD && myRole2 == ChildRole.LPARENTH) {
createSpaceInCode(mySettings.SPACE_BEFORE_FOR_PARENTHESES);
}
else if (myRole1 == ChildRole.LPARENTH || myRole2 == ChildRole.RPARENTH) {
createSpaceInCode(mySettings.SPACE_WITHIN_FOR_PARENTHESES);
}
else if (myRole1 == ChildRole.FOR_ITERATION_PARAMETER && myRole2 == ChildRole.COLON ||
myRole1 == ChildRole.COLON && myRole2 == ChildRole.FOR_ITERATED_VALUE)
{
createSpaceInCode(true);
}
else if (myRole2 == ChildRole.LOOP_BODY) {
if (myChild2.getElementType() == JavaElementType.BLOCK_STATEMENT) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_FOR_LBRACE, null);
}
else if (mySettings.KEEP_CONTROL_STATEMENT_IN_ONE_LINE) {
myResult = Spacing.createDependentLFSpacing(1, 1, myParent.getTextRange(), false, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
myResult = Spacing.createSpacing(0, 0, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
}
@Override
public void visitAssignmentExpression(PsiAssignmentExpression expression) {
if (myRole1 == ChildRole.OPERATION_SIGN || myRole2 == ChildRole.OPERATION_SIGN) {
createSpaceInCode(mySettings.SPACE_AROUND_ASSIGNMENT_OPERATORS);
}
}
@Override
public void visitParenthesizedExpression(PsiParenthesizedExpression expression) {
if (myRole1 == ChildRole.LPARENTH) {
createParenthSpace(mySettings.PARENTHESES_EXPRESSION_LPAREN_WRAP, mySettings.SPACE_WITHIN_PARENTHESES);
}
else if (myRole2 == ChildRole.RPARENTH) {
createParenthSpace(mySettings.PARENTHESES_EXPRESSION_RPAREN_WRAP, mySettings.SPACE_WITHIN_PARENTHESES);
}
}
@Override
public void visitCodeBlock(PsiCodeBlock block) {
processCodeBlock(keepInOneLine(block), block.getTextRange());
}
@Override
public void visitCodeFragment(JavaCodeFragment codeFragment) {
if (myChild1.getPsi() instanceof PsiStatement && myChild2.getPsi() instanceof PsiStatement) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
private void processCodeBlock(final boolean keepInOneLine, final TextRange textRange) {
final boolean lhsStatement = myChild1.getPsi() instanceof PsiStatement;
final boolean rhsStatement = myChild2.getPsi() instanceof PsiStatement;
if (myParent instanceof JspCodeBlock) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else if (myRole1 == ChildRoleBase.NONE && !lhsStatement || myRole2 == ChildRoleBase.NONE && !rhsStatement) {
final IElementType firstElementType = myChild1.getElementType();
if (
firstElementType == JavaTokenType.END_OF_LINE_COMMENT
||
firstElementType == JavaTokenType.C_STYLE_COMMENT) {
myResult = Spacing.createDependentLFSpacing(0, 1, myParent.getTextRange(),
mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
myResult = null;
}
}
else if (myRole1 == ChildRole.LBRACE) {
if (!keepInOneLine) {
int blankLines = 1;
if (myParent != null) {
ASTNode parentNode = myParent.getNode();
if (parentNode != null) {
ASTNode grandPa = parentNode.getTreeParent();
if (grandPa != null && grandPa.getElementType() == JavaElementType.METHOD) {
blankLines += mySettings.BLANK_LINES_BEFORE_METHOD_BODY;
}
}
}
myResult = Spacing.createSpacing(0, 0, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
myResult = Spacing.createDependentLFSpacing(0, 1, textRange, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
else if (myRole2 == ChildRole.RBRACE) {
if (!keepInOneLine) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
}
else {
myResult = Spacing.createDependentLFSpacing(0, 1, textRange, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
}
}
else if (myChild1.getElementType() == JavaElementType.SWITCH_LABEL_STATEMENT
&& myChild2.getElementType() == JavaElementType.BLOCK_STATEMENT)
{
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_SWITCH_LBRACE, null);
}
else if (lhsStatement && rhsStatement) {
int minSpaces = 0;
int minLineFeeds = 1;
PsiElement psi = myChild1.getPsi();
// We want to avoid situations like below:
// 1. Call 'introduce variable' refactoring for the code like 'System.out.println(1);';
// 2. When KEEP_MULTIPLE_EXPRESSIONS_IN_ONE_LINE is on, the output looks like 'int i = 1; System.out.println(i);';
// That's why we process the option only during the explicit reformat (directly invoked by an user).
if ((mySettings.KEEP_MULTIPLE_EXPRESSIONS_IN_ONE_LINE
&& (FormatterUtil.isFormatterCalledExplicitly() || ApplicationManager.getApplication().isUnitTestMode()))
|| psi != null && PsiTreeUtil.hasErrorElements(psi))
{
minSpaces = 1;
minLineFeeds = 0;
if (myChild1 != null) {
ASTNode lastElement = myChild1;
while (lastElement.getLastChildNode() != null) lastElement = lastElement.getLastChildNode();
//Not to place second statement on the same line with first one, if last ends with single line comment
if (lastElement instanceof PsiComment && lastElement.getElementType() == JavaTokenType.END_OF_LINE_COMMENT) minLineFeeds = 1;
}
}
myResult = Spacing.createSpacing(minSpaces, 0, minLineFeeds, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
private boolean keepInOneLine(final PsiCodeBlock block) {
if (block.getParent() instanceof PsiMethod) {
return shouldHandleAsSimpleMethod((PsiMethod)block.getParent());
}
else {
return shouldHandleAsSimpleBlock(block.getNode());
}
}
@Override
public void visitIfStatement(PsiIfStatement statement) {
if (myRole2 == ChildRole.ELSE_KEYWORD) {
if (myChild1.getElementType() != JavaElementType.BLOCK_STATEMENT) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
if (mySettings.ELSE_ON_NEW_LINE) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
createSpaceProperty(mySettings.SPACE_BEFORE_ELSE_KEYWORD, false, 0);
}
}
}
else if (myRole1 == ChildRole.ELSE_KEYWORD) {
if (myChild2.getElementType() == JavaElementType.IF_STATEMENT) {
if (mySettings.SPECIAL_ELSE_IF_TREATMENT) {
createSpaceProperty(false, false, 0);
}
else {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
else {
if (myChild2.getElementType() == JavaElementType.BLOCK_STATEMENT || myChild2.getElementType() == JavaElementType.CODE_BLOCK) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_ELSE_LBRACE, null);
}
else {
createSpacingBeforeElementInsideControlStatement();
}
}
}
else if (myChild2.getElementType() == JavaElementType.BLOCK_STATEMENT || myChild2.getElementType() == JavaElementType.CODE_BLOCK) {
boolean space = myRole2 == ChildRole.ELSE_BRANCH ? mySettings.SPACE_BEFORE_ELSE_LBRACE
: mySettings.SPACE_BEFORE_IF_LBRACE;
TextRange dependentRange = null;
if (myRole2 == ChildRole.THEN_BRANCH) {
PsiExpression condition = statement.getCondition();
if (condition != null) dependentRange = condition.getTextRange();
}
myResult = getSpaceBeforeLBrace(myChild2, space, dependentRange);
}
else if (myRole2 == ChildRole.LPARENTH) {
createSpaceInCode(mySettings.SPACE_BEFORE_IF_PARENTHESES);
}
else if (myRole1 == ChildRole.LPARENTH || myRole2 == ChildRole.RPARENTH) {
createSpaceInCode(mySettings.SPACE_WITHIN_IF_PARENTHESES);
}
else if (myRole2 == ChildRole.THEN_BRANCH) {
createSpacingBeforeElementInsideControlStatement();
}
}
private void createSpacingBeforeElementInsideControlStatement() {
if (mySettings.KEEP_CONTROL_STATEMENT_IN_ONE_LINE && myChild1.getElementType() != JavaTokenType.END_OF_LINE_COMMENT) {
//createNonLFSpace(1, null, mySettings.KEEP_LINE_BREAKS);
createSpaceProperty(true, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
//myResult = Spacing.createSpacing(1, 1, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
} else {
myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
private Spacing createNonLFSpace(int spaces, @Nullable final TextRange dependantRange, final boolean keepLineBreaks) {
final ASTNode prev = getPrevElementType(myChild2);
if (prev != null && prev.getElementType() == JavaTokenType.END_OF_LINE_COMMENT) {
return Spacing.createSpacing(0, Integer.MAX_VALUE, 1, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else if (dependantRange != null) {
return Spacing.createDependentLFSpacing(spaces, spaces, dependantRange, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
return Spacing.createSpacing(spaces, spaces, 0, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
@Nullable
private static ASTNode getPrevElementType(final ASTNode child) {
return FormatterUtil.getPreviousNonWhitespaceLeaf(child);
}
@Override
public void visitPolyadicExpression(PsiPolyadicExpression expression) {
if (myRole1 == ChildRole.OPERATION_SIGN || myRole2 == ChildRole.OPERATION_SIGN) {
IElementType i = expression.getOperationTokenType();
if (i == JavaTokenType.OROR || i == JavaTokenType.ANDAND) {
createSpaceInCode(mySettings.SPACE_AROUND_LOGICAL_OPERATORS);
}
else if (i == JavaTokenType.OR || i == JavaTokenType.AND || i == JavaTokenType.XOR) {
createSpaceInCode(mySettings.SPACE_AROUND_BITWISE_OPERATORS);
}
else if (i == JavaTokenType.EQEQ || i == JavaTokenType.NE) {
createSpaceInCode(mySettings.SPACE_AROUND_EQUALITY_OPERATORS);
}
else if (i == JavaTokenType.GT || i == JavaTokenType.LT || i == JavaTokenType.GE || i == JavaTokenType.LE) {
createSpaceInCode(mySettings.SPACE_AROUND_RELATIONAL_OPERATORS);
}
else if (i == JavaTokenType.PLUS || i == JavaTokenType.MINUS) {
createSpaceInCode(mySettings.SPACE_AROUND_ADDITIVE_OPERATORS);
}
else if (i == JavaTokenType.ASTERISK || i == JavaTokenType.DIV || i == JavaTokenType.PERC) {
createSpaceInCode(mySettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS);
}
else if (i == JavaTokenType.LTLT || i == JavaTokenType.GTGT || i == JavaTokenType.GTGTGT) {
createSpaceInCode(mySettings.SPACE_AROUND_SHIFT_OPERATORS);
}
else {
createSpaceInCode(false);
}
}
}
@Override
public void visitField(PsiField field) {
if (myChild1.getElementType() == JavaDocElementType.DOC_COMMENT) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
return;
}
if (myRole1 == ChildRole.INITIALIZER_EQ || myRole2 == ChildRole.INITIALIZER_EQ) {
createSpaceInCode(mySettings.SPACE_AROUND_ASSIGNMENT_OPERATORS);
}
else if (myRole1 == ChildRole.TYPE || myRole2 == ChildRole.TYPE) {
createSpaceInCode(true);
}
else if (myChild2.getElementType() == JavaTokenType.SEMICOLON) {
createSpaceProperty(false, false, 0);
}
else if (myRole1 == ChildRole.MODIFIER_LIST) {
createSpaceProperty(true, false, 0);
}
}
@Override
public void visitLocalVariable(PsiLocalVariable variable) {
if (myRole1 == ChildRole.INITIALIZER_EQ || myRole2 == ChildRole.INITIALIZER_EQ) {
createSpaceInCode(mySettings.SPACE_AROUND_ASSIGNMENT_OPERATORS);
}
else if (myRole1 == ChildRole.MODIFIER_LIST
|| myRole2 == ChildRole.TYPE_REFERENCE
|| myRole1 == ChildRole.TYPE_REFERENCE
|| myRole2 == ChildRole.TYPE
|| myRole1 == ChildRole.TYPE)
{
createSpaceInCode(true);
}
else if (myChild2.getElementType() == JavaTokenType.SEMICOLON) {
final PsiElement pp = myParent.getParent();
if (pp instanceof PsiDeclarationStatement) {
final PsiElement ppp = pp.getParent();
if (ppp instanceof PsiForStatement) {
createSpaceInCode(mySettings.SPACE_BEFORE_SEMICOLON);
return;
}
}
createSpaceProperty(false, false, 0);
}
}
@Override
public void visitMethod(PsiMethod method) {
if (myChild1.getElementType() == JavaDocElementType.DOC_COMMENT) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
return;
}
if (myRole2 == ChildRole.PARAMETER_LIST) {
createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_PARENTHESES);
}
else if (myRole1 == ChildRole.PARAMETER_LIST && myRole2 == ChildRole.THROWS_LIST || myRole1 == ChildRole.TYPE_PARAMETER_LIST) {
createSpaceInCode(true);
}
else if (myRole2 == ChildRole.METHOD_BODY) {
myResult = getSpaceBeforeMethodLBrace(method);
}
else if (myRole1 == ChildRole.MODIFIER_LIST) {
processModifierList();
}
else if (StdTokenSets.COMMENT_BIT_SET.contains(myChild1.getElementType())
&& (myRole2 == ChildRole.MODIFIER_LIST || myRole2 == ChildRole.TYPE_REFERENCE)) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, 0);
}
else if (myRole2 == ChildRole.DEFAULT_KEYWORD || myRole2 == ChildRole.ANNOTATION_DEFAULT_VALUE) {
createSpaceInCode(true);
}
else if (myChild2.getElementType() == JavaTokenType.SEMICOLON) {
createSpaceInCode(false);
}
else if (myRole1 == ChildRole.TYPE) {
createSpaceInCode(true);
}
}
private void processModifierList() {
if (mySettings.MODIFIER_LIST_WRAP) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
createSpaceProperty(true, false, 0);
}
}
@Override
public void visitModifierList(PsiModifierList list) {
myResult = Spacing.createSpacing(1, 1, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
@Override
public void visitParameterList(PsiParameterList list) {
if (myRole1 == ChildRole.LPARENTH && myRole2 == ChildRole.RPARENTH) {
createParenthSpace(mySettings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_EMPTY_METHOD_PARENTHESES);
}
else if (myRole2 == ChildRole.RPARENTH) {
createParenthSpace(mySettings.METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_METHOD_PARENTHESES);
}
else if (myRole2 == ChildRole.COMMA) {
createSpaceInCode(false);
}
else if (myRole1 == ChildRole.LPARENTH) {
createParenthSpace(mySettings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_METHOD_PARENTHESES);
}
else if (myRole1 == ChildRole.COMMA) {
createSpaceInCode(mySettings.SPACE_AFTER_COMMA);
}
}
private void createParenthSpace(final boolean onNewLine, final boolean space) {
createParenthSpace(onNewLine, space, myParent.getTextRange());
}
private void createParenthSpace(final boolean onNewLine, final boolean space, final TextRange dependence) {
if (onNewLine) {
final int spaces = space ? 1 : 0;
myResult = Spacing.createDependentLFSpacing(spaces, spaces, dependence, mySettings.KEEP_LINE_BREAKS,
mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
createSpaceInCode(space);
}
}
@Override
public void visitElement(PsiElement element) {
if (myRole1 == ChildRole.MODIFIER_LIST) {
processModifierList();
}
else if (myRole1 == ChildRole.OPERATION_SIGN) {
createSpaceInCode(mySettings.SPACE_AROUND_UNARY_OPERATOR);
}
else if ((myType1 == JavaDocTokenType.DOC_TAG_VALUE_TOKEN || myType1 == JavaDocElementType.DOC_TAG_VALUE_ELEMENT) &&
(myType2 == JavaDocTokenType.DOC_TAG_VALUE_TOKEN || myType2 == JavaDocElementType.DOC_TAG_VALUE_ELEMENT)) {
createSpaceInCode(true);
}
else if (myRole1 == ChildRole.COMMA) {
createSpaceInCode(mySettings.SPACE_AFTER_COMMA);
}
else if (myRole2 == ChildRole.COMMA) {
createSpaceInCode(mySettings.SPACE_BEFORE_COMMA);
}
}
@Override
public void visitExpressionList(PsiExpressionList list) {
if (myRole1 == ChildRole.LPARENTH && myRole2 == ChildRole.RPARENTH) {
createParenthSpace(mySettings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_EMPTY_METHOD_CALL_PARENTHESES);
}
else if (myRole2 == ChildRole.RPARENTH) {
createParenthSpace(mySettings.CALL_PARAMETERS_RPAREN_ON_NEXT_LINE,
myRole1 == ChildRole.COMMA || mySettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES);
}
else if (myRole1 == ChildRole.LPARENTH) {
createParenthSpace(mySettings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES);
}
else if (myRole1 == ChildRole.COMMA) {
createSpaceInCode(mySettings.SPACE_AFTER_COMMA);
}
else if (myRole2 == ChildRole.COMMA) {
createSpaceInCode(false);
}
}
@Override
public void visitSynchronizedStatement(PsiSynchronizedStatement statement) {
if (myRole1 == ChildRole.SYNCHRONIZED_KEYWORD || myRole2 == ChildRole.LPARENTH) {
createSpaceInCode(mySettings.SPACE_BEFORE_SYNCHRONIZED_PARENTHESES);
}
else if (myRole1 == ChildRole.LPARENTH || myRole2 == ChildRole.RPARENTH) {
createSpaceInCode(mySettings.SPACE_WITHIN_SYNCHRONIZED_PARENTHESES);
}
else if (myRole2 == ChildRole.BLOCK) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_SYNCHRONIZED_LBRACE, null);
}
}
@Override
public void visitSwitchLabelStatement(PsiSwitchLabelStatement statement) {
if (myRole1 == ChildRole.CASE_KEYWORD || myRole2 == ChildRole.CASE_EXPRESSION) {
createSpaceProperty(true, false, 0);
}
}
@Override
public void visitSwitchStatement(PsiSwitchStatement statement) {
if (myRole1 == ChildRole.SWITCH_KEYWORD && myRole2 == ChildRole.LPARENTH) {
createSpaceInCode(mySettings.SPACE_BEFORE_SWITCH_PARENTHESES);
}
else if (myRole1 == ChildRole.LPARENTH || myRole2 == ChildRole.RPARENTH) {
createSpaceInCode(mySettings.SPACE_WITHIN_SWITCH_PARENTHESES);
}
else if (myRole2 == ChildRole.SWITCH_BODY) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_SWITCH_LBRACE, null);
}
}
@Override
public void visitLambdaExpression(PsiLambdaExpression expression) {
if ((myRole1 == ChildRole.ARROW && (myRole2 == ChildRole.LBRACE || myRole2 == ChildRole.EXPRESSION)) ||
(myRole1 == ChildRole.PARAMETER_LIST && myRole2 == ChildRole.ARROW)) {
createSpaceInCode(mySettings.SPACE_AROUND_LAMBDA_ARROW);
}
}
@Override
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
if ((myRole1 == ChildRole.DOUBLE_COLON && myRole2 == ChildRole.REFERENCE_NAME) ||
(myRole1 == ChildRole.EXPRESSION && myRole2 == ChildRole.DOUBLE_COLON)) {
createSpaceInCode(mySettings.SPACE_AROUND_METHOD_REF_DBL_COLON);
}
}
@Override
public void visitForStatement(PsiForStatement statement) {
if (myRole2 == ChildRole.LPARENTH) {
createSpaceInCode(mySettings.SPACE_BEFORE_FOR_PARENTHESES);
}
else if (myRole1 == ChildRole.LPARENTH) {
ASTNode rparenth = findFrom(myChild2, JavaTokenType.RPARENTH, true);
if (rparenth == null) {
createSpaceInCode(mySettings.SPACE_WITHIN_FOR_PARENTHESES);
}
else {
createParenthSpace(mySettings.FOR_STATEMENT_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_FOR_PARENTHESES,
new TextRange(myChild1.getTextRange().getStartOffset(), rparenth.getTextRange().getEndOffset()));
if (myChild2.getElementType() == JavaElementType.EMPTY_STATEMENT) {
createSpaceInCode(mySettings.SPACE_BEFORE_SEMICOLON);
}
}
}
else if (myRole2 == ChildRole.RPARENTH) {
ASTNode lparenth = findFrom(myChild2, JavaTokenType.LPARENTH, false);
if (lparenth == null) {
createSpaceInCode(mySettings.SPACE_WITHIN_FOR_PARENTHESES);
}
else {
ASTNode prev = FormatterUtil.getPreviousLeaf(myChild2, TokenType.WHITE_SPACE, TokenType.ERROR_ELEMENT);
if (prev != null && prev.getElementType() == JavaTokenType.SEMICOLON) {
// Handle empty 'initialization' or 'condition' section.
createSpaceInCode(mySettings.SPACE_AFTER_SEMICOLON);
}
else {
createParenthSpace(mySettings.FOR_STATEMENT_RPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_FOR_PARENTHESES,
new TextRange(lparenth.getTextRange().getStartOffset(), myChild2.getTextRange().getEndOffset()));
}
}
}
else if (myRole1 == ChildRole.FOR_INITIALIZATION) {
createSpaceInCode(mySettings.SPACE_AFTER_SEMICOLON);
}
else if (myRole1 == ChildRole.CONDITION) {
createSpaceInCode(mySettings.SPACE_BEFORE_SEMICOLON);
}
else if (myRole1 == ChildRole.FOR_SEMICOLON) {
createSpaceInCode(mySettings.SPACE_AFTER_SEMICOLON);
}
else if (myRole2 == ChildRole.LOOP_BODY || myChild2.getElementType() == JavaElementType.CODE_BLOCK) {
if (myChild2.getElementType() == JavaElementType.BLOCK_STATEMENT) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_FOR_LBRACE, null);
}
else if (mySettings.KEEP_CONTROL_STATEMENT_IN_ONE_LINE) {
myResult = Spacing.createDependentLFSpacing(1, 1, myParent.getTextRange(), false, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
myResult = Spacing.createSpacing(0, 0, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
}
@Nullable
private static ASTNode findFrom(ASTNode current, final IElementType expected, boolean forward) {
while (current != null) {
if (current.getElementType() == expected) return current;
current = forward ? current.getTreeNext() : current.getTreePrev();
}
return null;
}
@Override
public void visitCatchSection(PsiCatchSection section) {
if (myRole2 == ChildRole.CATCH_BLOCK) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_CATCH_LBRACE, null);
}
else if (myRole2 == ChildRole.CATCH_BLOCK_PARAMETER_LPARENTH) {
createSpaceInCode(mySettings.SPACE_BEFORE_CATCH_PARENTHESES);
}
else if (myRole1 == ChildRole.CATCH_BLOCK_PARAMETER_LPARENTH || myRole2 == ChildRole.CATCH_BLOCK_PARAMETER_RPARENTH) {
createSpaceInCode(mySettings.SPACE_WITHIN_CATCH_PARENTHESES);
}
}
@Override
public void visitResourceList(final PsiResourceList resourceList) {
if (myType1 == JavaTokenType.LPARENTH && myType2 == JavaTokenType.RPARENTH) {
createParenthSpace(mySettings.RESOURCE_LIST_RPAREN_ON_NEXT_LINE, false);
}
else if (myType1 == JavaTokenType.LPARENTH) {
createParenthSpace(mySettings.RESOURCE_LIST_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_TRY_PARENTHESES);
}
else if (myType2 == JavaTokenType.RPARENTH) {
createParenthSpace(mySettings.RESOURCE_LIST_RPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_TRY_PARENTHESES);
}
else if (myType1 == JavaTokenType.SEMICOLON) {
createSpaceInCode(mySettings.SPACE_AFTER_SEMICOLON);
}
else if (myType2 == JavaTokenType.SEMICOLON) {
createSpaceInCode(mySettings.SPACE_BEFORE_SEMICOLON);
}
}
@Override
public void visitReferenceParameterList(PsiReferenceParameterList list) {
if (myRole1 == ChildRole.LT_IN_TYPE_LIST && myRole2 == ChildRole.GT_IN_TYPE_LIST
|| myRole1 == ChildRole.TYPE_IN_REFERENCE_PARAMETER_LIST && myRole2 == ChildRole.COMMA) {
createSpaceInCode(false);
}
else if (myRole1 == ChildRole.LT_IN_TYPE_LIST && myRole2 == ChildRole.TYPE_IN_REFERENCE_PARAMETER_LIST) {
createSpaceInCode(myJavaSettings.SPACES_WITHIN_ANGLE_BRACKETS);
}
else if (myRole1 == ChildRole.COMMA && myRole2 == ChildRole.TYPE_IN_REFERENCE_PARAMETER_LIST) {
createSpaceInCode(mySettings.SPACE_AFTER_COMMA_IN_TYPE_ARGUMENTS);
}
else if (myRole2 == ChildRole.GT_IN_TYPE_LIST) {
createSpaceInCode(myJavaSettings.SPACES_WITHIN_ANGLE_BRACKETS);
}
}
@Override
public void visitTypeCastExpression(PsiTypeCastExpression expression) {
if (myRole1 == ChildRole.LPARENTH || myRole2 == ChildRole.RPARENTH) {
createSpaceInCode(mySettings.SPACE_WITHIN_CAST_PARENTHESES);
}
else if (myRole1 == ChildRole.RPARENTH) {
createSpaceInCode(mySettings.SPACE_AFTER_TYPE_CAST);
}
}
private void createSpaceProperty(boolean space, int keepBlankLines) {
createSpaceProperty(space, mySettings.KEEP_LINE_BREAKS, keepBlankLines);
}
private void createSpaceProperty(boolean space, boolean keepLineBreaks, final int keepBlankLines) {
final ASTNode prev = getPrevElementType(myChild2);
if (prev != null && prev.getElementType() == JavaTokenType.END_OF_LINE_COMMENT) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
if (!space && !canStickChildrenTogether(myChild1, myChild2)) {
space = true;
}
if (!keepLineBreaks && myRole2 == ChildRoleBase.NONE) {
keepLineBreaks = true;
}
myResult = Spacing.createSpacing(space ? 1 : 0, space ? 1 : 0, 0, keepLineBreaks, keepBlankLines);
}
}
@Override
public void visitReferenceList(PsiReferenceList list) {
if (myRole1 == ChildRole.COMMA) {
createSpaceInCode(true);
}
else if (myRole2 == ChildRole.COMMA) {
createSpaceInCode(false);
}
else if (myRole1 == ChildRole.AMPERSAND_IN_BOUNDS_LIST || myRole2 == ChildRole.AMPERSAND_IN_BOUNDS_LIST) {
createSpaceInCode(myJavaSettings.SPACE_AROUND_TYPE_BOUNDS_IN_TYPE_PARAMETERS);
}
else if (myRole1 == ChildRole.EXTENDS_KEYWORD
|| myRole2 == ChildRole.EXTENDS_KEYWORD
|| myRole1 == ChildRole.IMPLEMENTS_KEYWORD
|| myRole2 == ChildRole.IMPLEMENTS_KEYWORD
|| myRole1 == ChildRole.THROWS_KEYWORD)
{
createSpaceInCode(true);
}
}
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
visitReferenceElement(expression);
}
@Override
public void visitConditionalExpression(PsiConditionalExpression expression) {
if (myRole2 == ChildRole.QUEST) {
createSpaceInCode(mySettings.SPACE_BEFORE_QUEST);
}
else if (myRole1 == ChildRole.QUEST) {
createSpaceInCode(mySettings.SPACE_AFTER_QUEST);
}
else if (myRole2 == ChildRole.COLON) {
createSpaceInCode(mySettings.SPACE_BEFORE_COLON);
}
else if (myRole1 == ChildRole.COLON) {
createSpaceInCode(mySettings.SPACE_AFTER_COLON);
}
}
@Override
public void visitStatement(PsiStatement statement) {
if (myRole2 == ChildRole.CLOSING_SEMICOLON) {
createSpaceInCode(false);
}
if (statement instanceof JspClassLevelDeclarationStatement) {
processClassBody();
}
}
@Override
public void visitReturnStatement(PsiReturnStatement statement) {
if (myChild2.getElementType() == JavaTokenType.SEMICOLON) {
createSpaceInCode(false);
}
else if (myRole1 == ChildRole.RETURN_KEYWORD) {
createSpaceInCode(true);
}
else {
super.visitReturnStatement(statement);
}
}
@Override
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
if (myRole2 == ChildRole.ARGUMENT_LIST) {
createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES);
}
}
@Override
public void visitTypeParameter(PsiTypeParameter classParameter) {
createSpaceInCode(true);
}
@Override
public void visitTypeElement(PsiTypeElement type) {
if (myType1 == JavaElementType.ANNOTATION || myType2 == JavaElementType.ANNOTATION) {
createSpaceInCode(true);
}
else if (myType2 == JavaTokenType.ELLIPSIS || myType2 == JavaTokenType.LBRACKET || myType2 == JavaTokenType.RBRACKET) {
createSpaceInCode(false);
}
else if (type.getType() instanceof PsiDisjunctionType) {
createSpaceInCode(mySettings.SPACE_AROUND_BITWISE_OPERATORS);
}
else {
createSpaceInCode(true);
}
}
@Override
public void visitDeclarationStatement(PsiDeclarationStatement declarationStatement) {
if (myRole2 == ChildRole.COMMA) {
createSpaceProperty(false, false, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else if (myRole1 == ChildRole.COMMA) {
createSpaceInCode(true);
}
}
@Override
public void visitTypeParameterList(PsiTypeParameterList list) {
if (myRole1 == ChildRole.LT_IN_TYPE_LIST || myRole2 == ChildRole.GT_IN_TYPE_LIST) {
createSpaceInCode(myJavaSettings.SPACES_WITHIN_ANGLE_BRACKETS);
}
else if (myRole1 == ChildRole.COMMA) {
createSpaceInCode(mySettings.SPACE_AFTER_COMMA);
}
}
@Override
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
if (myRole1 == ChildRole.REFERENCE_PARAMETER_LIST && myRole2 == ChildRole.REFERENCE_NAME) {
createSpaceInCode(myJavaSettings.SPACE_AFTER_CLOSING_ANGLE_BRACKET_IN_TYPE_ARGUMENT);
}
else if (myRole2 == ChildRole.REFERENCE_PARAMETER_LIST) {
createSpaceInCode(mySettings.SPACE_BEFORE_TYPE_PARAMETER_LIST);
}
else if (myRole2 == ChildRole.DOT) {
createSpaceInCode(false);
}
else if (myType1 == JavaElementType.ANNOTATION) {
createSpaceInCode(true);
}
}
@Override
public void visitAnnotation(PsiAnnotation annotation) {
if (myRole2 == ChildRole.PARAMETER_LIST) {
createSpaceInCode(mySettings.SPACE_BEFORE_ANOTATION_PARAMETER_LIST);
}
else if (myChild1.getElementType() == JavaTokenType.AT && myChild2.getElementType() == JavaElementType.JAVA_CODE_REFERENCE) {
createSpaceInCode(false);
}
}
@Override
public void visitClassInitializer(PsiClassInitializer initializer) {
if (myChild2.getElementType() == JavaElementType.CODE_BLOCK) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_METHOD_LBRACE, null);
}
}
@Override
public void visitAnnotationParameterList(PsiAnnotationParameterList list) {
if (myRole1 == ChildRole.LPARENTH && myRole2 == ChildRole.RPARENTH) {
createSpaceInCode(false);
}
// There is a possible case that annotation key-value pair is used in 'shorten' form (with implicit name 'values'). It's also
// possible that target value is surrounded by curly braces. We want to define child role accordingly then.
else if (myRole1 == ChildRole.LPARENTH && mySettings.SPACE_BEFORE_ANNOTATION_ARRAY_INITIALIZER_LBRACE && myRole2 == ChildRole.ANNOTATION_VALUE) {
createSpaceInCode(true);
}
else if (myRole1 == ChildRole.LPARENTH || myRole2 == ChildRole.RPARENTH) {
createSpaceInCode(mySettings.SPACE_WITHIN_ANNOTATION_PARENTHESES);
}
else if (myRole2 == ChildRole.COMMA) {
createSpaceInCode(false);
}
else if (myRole1 == ChildRole.COMMA) {
createSpaceInCode(true);
}
}
@Override
public void visitNameValuePair(PsiNameValuePair pair) {
if (myRole1 == ChildRole.OPERATION_SIGN || myRole2 == ChildRole.OPERATION_SIGN) {
createSpaceInCode(mySettings.SPACE_AROUND_ASSIGNMENT_OPERATORS);
}
}
@Override
public void visitAnnotationArrayInitializer(PsiArrayInitializerMemberValue initializer) {
visitArrayInitializer();
}
private void visitArrayInitializer() {
if (myRole1 == ChildRole.LBRACE) {
if (mySettings.ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE) {
int spaces = mySettings.SPACE_WITHIN_ARRAY_INITIALIZER_BRACES ? 1 : 0;
myResult = Spacing.createDependentLFSpacing(spaces, spaces, myParent.getTextRange(), mySettings.KEEP_LINE_BREAKS,
mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else {
createSpaceProperty(mySettings.SPACE_WITHIN_ARRAY_INITIALIZER_BRACES, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
}
else if (myRole2 == ChildRole.LBRACE) {
createSpaceInCode(mySettings.SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE);
}
else if (myRole2 == ChildRole.RBRACE) {
if (mySettings.ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE) {
int spaces = mySettings.SPACE_WITHIN_ARRAY_INITIALIZER_BRACES ? 1 : 0;
myResult = Spacing.createDependentLFSpacing(spaces, spaces, myParent.getTextRange(), mySettings.KEEP_LINE_BREAKS,
mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
}
else {
createSpaceProperty(mySettings.SPACE_WITHIN_ARRAY_INITIALIZER_BRACES, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
}
}
else if (myRole1 == ChildRole.COMMA) {
createSpaceInCode(mySettings.SPACE_AFTER_COMMA);
}
else if (myRole2 == ChildRole.COMMA) {
createSpaceInCode(mySettings.SPACE_BEFORE_COMMA);
}
}
@Override
public void visitEnumConstant(PsiEnumConstant enumConstant) {
if (myRole2 == ChildRole.ARGUMENT_LIST) {
createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES);
}
else if (myRole2 == ChildRole.ANONYMOUS_CLASS) {
myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_CLASS_LBRACE, null);
}
}
@Override
public void visitDocTag(PsiDocTag tag) {
if (myType1 == JavaDocTokenType.DOC_TAG_NAME && myType2 == JavaDocElementType.DOC_TAG_VALUE_ELEMENT) {
myResult = Spacing.createSpacing(1, 1, 0, false, 0);
}
}
@Override
public void visitAssertStatement(PsiAssertStatement statement) {
if (myChild1.getElementType() == JavaTokenType.ASSERT_KEYWORD) {
createSpaceInCode(true);
}
else if (myChild1.getElementType() == JavaTokenType.COLON){
createSpaceInCode(mySettings.SPACE_AFTER_COLON);
}
else if (myChild2.getElementType() == JavaTokenType.COLON) {
createSpaceInCode(mySettings.SPACE_BEFORE_COLON);
}
}
@Override
public void visitParameter(PsiParameter parameter) {
if (myRole1 == ChildRole.TYPE || myRole1 == ChildRole.MODIFIER_LIST) {
createSpaceInCode(true);
}
}
@SuppressWarnings({"ConstantConditions"})
public static Spacing getSpacing(ASTNode node, CommonCodeStyleSettings settings, JavaCodeStyleSettings javaSettings) {
JavaSpacePropertyProcessor spacePropertyProcessor = mySharedProcessorAllocator.get();
try {
if (spacePropertyProcessor == null) {
spacePropertyProcessor = new JavaSpacePropertyProcessor();
mySharedProcessorAllocator.set(spacePropertyProcessor);
}
spacePropertyProcessor.doInit(node, settings, javaSettings);
return spacePropertyProcessor.getResult();
}
finally {
spacePropertyProcessor.clear();
}
}
private static boolean isWS(final ASTNode lastChild) {
return lastChild != null && lastChild.getElementType() == TokenType.WHITE_SPACE;
}
private static final Map<Pair<IElementType, IElementType>, Boolean> myCanStickJavaTokensMatrix =
new ConcurrentHashMap<Pair<IElementType, IElementType>, Boolean>();
public static boolean canStickChildrenTogether(final ASTNode child1, final ASTNode child2) {
if (child1 == null || child2 == null) return true;
if (isWS(child1) || isWS(child2)) return true;
ASTNode token1 = TreeUtil.findLastLeaf(child1);
ASTNode token2 = TreeUtil.findFirstLeaf(child2);
LOG.assertTrue(token1 != null);
LOG.assertTrue(token2 != null);
return !(token1.getElementType() instanceof IJavaElementType && token2.getElementType()instanceof IJavaElementType) ||
canStickJavaTokens(token1,token2);
}
private static boolean canStickJavaTokens(ASTNode token1, ASTNode token2) {
IElementType type1 = token1.getElementType();
IElementType type2 = token2.getElementType();
Pair<IElementType, IElementType> pair = Pair.create(type1, type2);
Boolean res = myCanStickJavaTokensMatrix.get(pair);
if (res == null) {
if (!checkToken(token1) || !checkToken(token2)) return true;
String text = token1.getText() + token2.getText();
Lexer lexer = JavaParserDefinition.createLexer(LanguageLevel.HIGHEST);
lexer.start(text);
boolean canMerge = lexer.getTokenType() == type1;
lexer.advance();
canMerge &= lexer.getTokenType() == type2;
res = canMerge;
myCanStickJavaTokensMatrix.put(pair, res);
}
return res.booleanValue();
}
private static boolean checkToken(final ASTNode token1) {
Lexer lexer = JavaParserDefinition.createLexer(LanguageLevel.HIGHEST);
final String text = token1.getText();
lexer.start(text);
if (lexer.getTokenType() != token1.getElementType()) return false;
lexer.advance();
return lexer.getTokenType() == null;
}
}