Fix formatting for multiline binary expressions

#KT-4797 Fixed
This commit is contained in:
Nikolay Krasko
2014-04-20 01:27:11 +04:00
parent 055859888e
commit 45013ce8af
31 changed files with 354 additions and 29 deletions
@@ -22,7 +22,6 @@ import com.intellij.lang.ASTNode;
import com.intellij.psi.TokenType;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.formatter.common.AbstractBlock;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
@@ -111,19 +110,13 @@ public class JetBlock extends AbstractBlock {
if (child.getElementType() == OPERATION_REFERENCE) {
ASTNode operationNode = child.getFirstChildNode();
if (operationNode != null) {
return new JetBlock(operationNode, alignmentStrategy, Indent.getNoneIndent(), null, mySettings, mySpacingBuilder);
return new JetBlock(operationNode, alignmentStrategy, createChildIndent(child), null, mySettings, mySpacingBuilder);
}
}
return new JetBlock(child, alignmentStrategy, createChildIndent(child), null, mySettings, mySpacingBuilder);
}
private static Indent indentIfNotBrace(@NotNull ASTNode child) {
return child.getElementType() == RBRACE || child.getElementType() == LBRACE
? Indent.getNoneIndent()
: Indent.getNormalIndent();
}
private static ASTNode getPrevWithoutWhitespace(ASTNode node) {
node = node.getTreePrev();
while (node != null && node.getElementType() == TokenType.WHITE_SPACE) {
@@ -171,6 +164,10 @@ public class JetBlock extends AbstractBlock {
return new ChildAttributes(Indent.getSpaceIndent(KDOC_COMMENT_INDENT), null);
}
if (type == PARENTHESIZED) {
return super.getChildAttributes(newChildIndex);
}
if (isIncomplete()) {
return super.getChildAttributes(newChildIndex);
}
@@ -184,28 +181,52 @@ public class JetBlock extends AbstractBlock {
}
private NodeAlignmentStrategy getChildrenAlignmentStrategy() {
CommonCodeStyleSettings jetCommonSettings = mySettings.getCommonSettings(JetLanguage.INSTANCE);
final CommonCodeStyleSettings jetCommonSettings = mySettings.getCommonSettings(JetLanguage.INSTANCE);
JetCodeStyleSettings jetSettings = mySettings.getCustomSettings(JetCodeStyleSettings.class);
// Prepare default null strategy
NodeAlignmentStrategy strategy = myAlignmentStrategy;
// Redefine list of strategies for some special elements
IElementType parentType = myNode.getElementType();
if (parentType == VALUE_PARAMETER_LIST) {
strategy = getAlignmentForChildInParenthesis(
return getAlignmentForChildInParenthesis(
jetCommonSettings.ALIGN_MULTILINE_PARAMETERS, VALUE_PARAMETER, COMMA,
jetCommonSettings.ALIGN_MULTILINE_METHOD_BRACKETS, LPAR, RPAR);
}
else if (parentType == VALUE_ARGUMENT_LIST) {
strategy = getAlignmentForChildInParenthesis(
return getAlignmentForChildInParenthesis(
jetCommonSettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS, VALUE_ARGUMENT, COMMA,
jetCommonSettings.ALIGN_MULTILINE_METHOD_BRACKETS, LPAR, RPAR);
}
else if (parentType == WHEN) {
strategy = getAlignmentForCaseBranch(jetSettings.ALIGN_IN_COLUMNS_CASE_BRANCH);
return getAlignmentForCaseBranch(jetSettings.ALIGN_IN_COLUMNS_CASE_BRANCH);
}
return strategy;
else if (parentType == BINARY_EXPRESSION) {
return NodeAlignmentStrategy.fromTypes(AlignmentStrategy.wrap(
createAlignment(jetCommonSettings.ALIGN_MULTILINE_BINARY_OPERATION, getAlignment())));
}
else if (parentType == PARENTHESIZED) {
return new NodeAlignmentStrategy() {
Alignment bracketsAlignment = jetCommonSettings.ALIGN_MULTILINE_BINARY_OPERATION ? Alignment.createAlignment() : null;
@Nullable
@Override
public Alignment getAlignment(@NotNull ASTNode childNode) {
IElementType childNodeType = childNode.getElementType();
ASTNode prev = getPrevWithoutWhitespace(childNode);
if ((prev != null && prev.getElementType() == TokenType.ERROR_ELEMENT) || childNodeType == TokenType.ERROR_ELEMENT) {
return bracketsAlignment;
}
if (childNodeType == LPAR || childNodeType == RPAR) {
return bracketsAlignment;
}
return null;
}
};
}
return myAlignmentStrategy;
}
private static NodeAlignmentStrategy getAlignmentForChildInParenthesis(
@@ -288,6 +309,14 @@ public class JetBlock extends AbstractBlock {
.in(DOT_QUALIFIED_EXPRESSION, SAFE_ACCESS_EXPRESSION)
.set(Indent.getContinuationWithoutFirstIndent(true)),
ASTIndentStrategy.forNode("Binary expressions")
.in(BINARY_EXPRESSION)
.set(Indent.getContinuationWithoutFirstIndent(false)),
ASTIndentStrategy.forNode("Parenthesized expression")
.in(PARENTHESIZED)
.set(Indent.getContinuationWithoutFirstIndent(false)),
ASTIndentStrategy.forNode("KDoc comment indent")
.in(DOC_COMMENT)
.forType(KDocTokens.LEADING_ASTERISK, KDocTokens.END)
@@ -338,4 +367,17 @@ public class JetBlock extends AbstractBlock {
return Indent.getNoneIndent();
}
@Nullable
private static Alignment createAlignment(boolean alignOption, @Nullable Alignment defaultAlignment) {
return alignOption ? createAlignmentOrDefault(null, defaultAlignment) : defaultAlignment;
}
@Nullable
private static Alignment createAlignmentOrDefault(@Nullable Alignment base, @Nullable Alignment defaultAlignment) {
if (defaultAlignment == null) {
return base == null ? Alignment.createAlignment() : Alignment.createChildAlignment(base);
}
return defaultAlignment;
}
}
@@ -155,6 +155,7 @@ public class JetLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSetti
"ALIGN_MULTILINE_PARAMETERS",
"ALIGN_MULTILINE_PARAMETERS_IN_CALLS",
"ALIGN_MULTILINE_METHOD_BRACKETS",
"ALIGN_MULTILINE_BINARY_OPERATION",
"ELSE_ON_NEW_LINE",
"WHILE_ON_NEW_LINE",
"CATCH_ON_NEW_LINE",
@@ -2,7 +2,7 @@
fun foo() {
fun bar1() {}
val x = 1 +
<caret>2 +
3
<caret>2 +
3
fun bar2() {}
}
@@ -1,8 +1,8 @@
// MOVE: up
fun foo() {
val x = 1 +
<caret>2 +
3
<caret>2 +
3
fun bar1() {}
fun bar2() {}
}
@@ -3,6 +3,6 @@ fun foo() {
fun bar1() {}
fun bar2() {}
val x = 1 +
<caret>2 +
3
<caret>2 +
3
}
@@ -2,7 +2,7 @@
fun foo() {
fun bar1() {}
val x = 1 +
(2 +
<caret>3)
(2 +
<caret>3)
fun bar2() {}
}
@@ -1,8 +1,8 @@
// MOVE: up
fun foo() {
val x = 1 +
(2 +
<caret>3)
(2 +
<caret>3)
fun bar1() {}
fun bar2() {}
}
@@ -3,6 +3,6 @@ fun foo() {
fun bar1() {}
fun bar2() {}
val x = 1 +
(2 +
<caret>3)
(2 +
<caret>3)
}
@@ -0,0 +1,15 @@
fun test() {
val somelong = 1 + 2 +
3 - 4 -
5 * 6 *
7 / 8 /
9 % 10 %
11
val withBrackets = 3 +
4 - (5 +
4 * 5)
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
// Strage behaviour for disabled alignment is same to Java
@@ -0,0 +1,15 @@
fun test() {
val somelong = 1 + 2 +
3 - 4 -
5 * 6 *
7 / 8 /
9 % 10 %
11
val withBrackets = 3 +
4 - (5 +
4 * 5)
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
// Strage behaviour for disabled alignment is same to Java
@@ -0,0 +1,15 @@
fun test() {
val somelong = 1 + 2 +
3 - 4 -
5 * 6 *
7 / 8 /
9 % 10 %
11
val withBrackets = 3 +
4 - (5 +
4 * 5)
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
// Strage behaviour for disabled alignment is same to Java
@@ -0,0 +1,32 @@
fun test() {
if (true
|| false
|| true) {
}
if (true || false
|| true) {
}
if (true
|| false
|| true) {
}
if (true ||
false ||
true) {
}
true
|| true
false
&& false
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,32 @@
fun test() {
if (true
|| false
|| true) {
}
if (true || false
|| true) {
}
if (true
|| false
|| true) {
}
if (true ||
false ||
true) {
}
true
|| true
false
&& false
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,32 @@
fun test() {
if (true
|| false
|| true) {
}
if (true || false
|| true) {
}
if (true
|| false
|| true) {
}
if (true ||
false ||
true) {
}
true
|| true
false
&& false
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,6 @@
fun some() {
val test = 3 +
<caret>4
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,6 @@
fun some() {
val test = 3 +
<caret>4
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,5 @@
fun some() {
val test = 3 + <caret>4
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,6 @@
fun some() {
val test = 3 +
<caret>
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,6 @@
fun some() {
val test = 3 +
<caret>
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,5 @@
fun some() {
val test = 3 + <caret>
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,4 @@
val somelong = 3 + 4 - (3 +
<caret>)
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,4 @@
val somelong = 3 + 4 - (3 +
<caret>)
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,3 @@
val somelong = 3 + 4 - (3 + <caret>)
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,5 @@
val somelong = 3 + 4 - (
<caret>
)
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,5 @@
val somelong = 3 + 4 - (
<caret>
)
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,3 @@
val somelong = 3 + 4 - (<caret>)
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,4 @@
val somelong = 3 + (3 *
<caret>3)
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,4 @@
val somelong = 3 + (3 *
<caret>3)
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -0,0 +1,3 @@
val somelong = 3 + (3 * <caret>3)
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
@@ -36,7 +36,19 @@ public class JetFormatterTestGenerated extends AbstractJetFormatterTest {
@InnerTestClasses({Formatter.ModifierList.class})
public static class Formatter extends AbstractJetFormatterTest {
public void testAllFilesPresentInFormatter() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/formatter"), Pattern.compile("^([^\\.]+)\\.after\\.kt.*$"), true);
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage",
new File("idea/testData/formatter"), Pattern.compile("^([^\\.]+)\\.after\\.kt.*$"),
true);
}
@TestMetadata("BinaryExpressions.after.kt")
public void testBinaryExpressions() throws Exception {
doTest("idea/testData/formatter/BinaryExpressions.after.kt");
}
@TestMetadata("BinaryExpressionsBoolean.after.kt")
public void testBinaryExpressionsBoolean() throws Exception {
doTest("idea/testData/formatter/BinaryExpressionsBoolean.after.kt");
}
@TestMetadata("BlockFor.after.kt")
@@ -407,6 +419,16 @@ public class JetFormatterTestGenerated extends AbstractJetFormatterTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/formatter"), Pattern.compile("^([^\\.]+)\\.after\\.inv\\.kt.*$"), true);
}
@TestMetadata("BinaryExpressions.after.inv.kt")
public void testBinaryExpressions() throws Exception {
doTestInverted("idea/testData/formatter/BinaryExpressions.after.inv.kt");
}
@TestMetadata("BinaryExpressionsBoolean.after.inv.kt")
public void testBinaryExpressionsBoolean() throws Exception {
doTestInverted("idea/testData/formatter/BinaryExpressionsBoolean.after.inv.kt");
}
@TestMetadata("CatchFinallyOnNewLine.after.inv.kt")
public void testCatchFinallyOnNewLine() throws Exception {
doTestInverted("idea/testData/formatter/CatchFinallyOnNewLine.after.inv.kt");
@@ -106,6 +106,31 @@ public class JetTypingIndentationTestBaseGenerated extends AbstractJetTypingInde
doNewlineTest("idea/testData/indentationOnNewline/If.after.kt");
}
@TestMetadata("InBinaryExpressionInMiddle.after.kt")
public void testInBinaryExpressionInMiddle() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InBinaryExpressionInMiddle.after.kt");
}
@TestMetadata("InBinaryExpressionUnfinished.after.kt")
public void testInBinaryExpressionUnfinished() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InBinaryExpressionUnfinished.after.kt");
}
@TestMetadata("InBinaryExpressionsBeforeCloseParenthesis.after.kt")
public void testInBinaryExpressionsBeforeCloseParenthesis() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InBinaryExpressionsBeforeCloseParenthesis.after.kt");
}
@TestMetadata("InExpressionsParentheses.after.kt")
public void testInExpressionsParentheses() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InExpressionsParentheses.after.kt");
}
@TestMetadata("InExpressionsParenthesesBeforeOperand.after.kt")
public void testInExpressionsParenthesesBeforeOperand() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InExpressionsParenthesesBeforeOperand.after.kt");
}
@TestMetadata("NotFirstParameter.after.kt")
public void testNotFirstParameter() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/NotFirstParameter.after.kt");
@@ -171,6 +196,31 @@ public class JetTypingIndentationTestBaseGenerated extends AbstractJetTypingInde
Pattern.compile("^([^\\.]+)\\.after\\.inv\\.kt.*$"), true);
}
@TestMetadata("InBinaryExpressionInMiddle.after.inv.kt")
public void testInBinaryExpressionInMiddle() throws Exception {
doNewlineTestWithInvert("idea/testData/indentationOnNewline/InBinaryExpressionInMiddle.after.inv.kt");
}
@TestMetadata("InBinaryExpressionUnfinished.after.inv.kt")
public void testInBinaryExpressionUnfinished() throws Exception {
doNewlineTestWithInvert("idea/testData/indentationOnNewline/InBinaryExpressionUnfinished.after.inv.kt");
}
@TestMetadata("InBinaryExpressionsBeforeCloseParenthesis.after.inv.kt")
public void testInBinaryExpressionsBeforeCloseParenthesis() throws Exception {
doNewlineTestWithInvert("idea/testData/indentationOnNewline/InBinaryExpressionsBeforeCloseParenthesis.after.inv.kt");
}
@TestMetadata("InExpressionsParentheses.after.inv.kt")
public void testInExpressionsParentheses() throws Exception {
doNewlineTestWithInvert("idea/testData/indentationOnNewline/InExpressionsParentheses.after.inv.kt");
}
@TestMetadata("InExpressionsParenthesesBeforeOperand.after.inv.kt")
public void testInExpressionsParenthesesBeforeOperand() throws Exception {
doNewlineTestWithInvert("idea/testData/indentationOnNewline/InExpressionsParenthesesBeforeOperand.after.inv.kt");
}
@TestMetadata("SettingAlignMultilineParametersInCalls.after.inv.kt")
public void testSettingAlignMultilineParametersInCalls() throws Exception {
doNewlineTestWithInvert("idea/testData/indentationOnNewline/SettingAlignMultilineParametersInCalls.after.inv.kt");