diff --git a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt index dd1da6f962f..f134116c2b9 100644 --- a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt +++ b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt @@ -20,6 +20,8 @@ import com.intellij.formatting.* 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.impl.source.tree.TreeUtil import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.TokenSet import org.jetbrains.kotlin.KtNodeTypes @@ -506,11 +508,23 @@ private val INDENT_RULES = arrayOf( .within(KtNodeTypes.PARENTHESIZED) .set(Indent.getContinuationWithoutFirstIndent(false)), - strategy("Round Brackets around conditions") - .forType(LPAR, RPAR) + strategy("Opening parenthesis for conditions") + .forType(LPAR) .within(KtNodeTypes.IF, KtNodeTypes.WHEN_ENTRY, KtNodeTypes.WHILE, KtNodeTypes.DO_WHILE) .set(Indent.getContinuationWithoutFirstIndent(true)), + strategy("Closing parenthesis for conditions") + .forType(RPAR) + .forElement { node -> !hasErrorElementBefore(node) } + .within(KtNodeTypes.IF, KtNodeTypes.WHEN_ENTRY, KtNodeTypes.WHILE, KtNodeTypes.DO_WHILE) + .set(Indent.getNoneIndent()), + + strategy("Closing parenthesis for incomplete conditions") + .forType(RPAR) + .forElement { node -> hasErrorElementBefore(node) } + .within(KtNodeTypes.IF, KtNodeTypes.WHEN_ENTRY, KtNodeTypes.WHILE, KtNodeTypes.DO_WHILE) + .set(Indent.getContinuationWithoutFirstIndent()), + strategy("KDoc comment indent") .within(KDOC_CONTENT) .forType(KDocTokens.LEADING_ASTERISK, KDocTokens.END) @@ -550,6 +564,13 @@ private val INDENT_RULES = arrayOf( private fun getOperationType(node: ASTNode): IElementType? = node.findChildByType(KtNodeTypes.OPERATION_REFERENCE)?.firstChildNode?.elementType +private fun hasErrorElementBefore(node: ASTNode): Boolean { + val prevSibling = getPrevWithoutWhitespace(node) ?: return false + if (prevSibling.elementType == TokenType.ERROR_ELEMENT) return true + val lastChild = TreeUtil.getLastChild(prevSibling) + return lastChild?.elementType == TokenType.ERROR_ELEMENT +} + private fun getAlignmentForChildInParenthesis( shouldAlignChild: Boolean, parameter: IElementType, delimiter: IElementType, shouldAlignParenthesis: Boolean, openBracket: IElementType, closeBracket: IElementType): CommonAlignmentStrategy { diff --git a/idea/testData/formatter/IfClosingParen.after.kt b/idea/testData/formatter/IfClosingParen.after.kt new file mode 100644 index 00000000000..4afa1ea3be3 --- /dev/null +++ b/idea/testData/formatter/IfClosingParen.after.kt @@ -0,0 +1,6 @@ +fun foo() { + if (longCond1 && + longCond2 + ) { + } +} diff --git a/idea/testData/formatter/IfClosingParen.kt b/idea/testData/formatter/IfClosingParen.kt new file mode 100644 index 00000000000..21720528484 --- /dev/null +++ b/idea/testData/formatter/IfClosingParen.kt @@ -0,0 +1,6 @@ +fun foo() { + if (longCond1 && + longCond2 + ) { + } +} diff --git a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java index bfaf9cf41f7..23e62d8fad5 100644 --- a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java @@ -428,6 +428,12 @@ public class FormatterTestGenerated extends AbstractFormatterTest { doTest(fileName); } + @TestMetadata("IfClosingParen.after.kt") + public void testIfClosingParen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/IfClosingParen.after.kt"); + doTest(fileName); + } + @TestMetadata("IfElseRemoveLineBreak.after.kt") public void testIfElseRemoveLineBreak() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/IfElseRemoveLineBreak.after.kt");