Skip to content

Commit

Permalink
Release testing bugs 1.2.0 (#2570)
Browse files Browse the repository at this point in the history
* A when-condition preceded by a comment should be treated as a multiline condition and as of that lead to adding blank lines between the when-conditions

* Rename BackingPropertyRuleTest to BackingPropertyNamingRuleTest

* Prevent conflict between `string-template-indent` and `multiline-expression` when function body expression is a multiline string template
  • Loading branch information
paul-dingemans committed Feb 28, 2024
1 parent befa71d commit 623431b
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 7 deletions.
24 changes: 22 additions & 2 deletions documentation/snapshot/docs/rules/experimental.md
Expand Up @@ -104,8 +104,19 @@ Consistently add or remove blank lines between when-conditions in a when-stateme
else -> null
}

// ij_kotlin_line_break_after_multiline_when_entry = true
val foo3 =
when (bar) {
BAR1 -> "bar1"

// BAR2 comment
BAR2 -> "bar2"

else -> null
}

// ij_kotlin_line_break_after_multiline_when_entry = false
val foo2 =
val foo4 =
when (bar) {
BAR1 -> "bar1"
BAR2 -> {
Expand Down Expand Up @@ -138,8 +149,17 @@ Consistently add or remove blank lines between when-conditions in a when-stateme
else -> null
}

// ij_kotlin_line_break_after_multiline_when_entry = true (missing newline after BAR1, and BAR2)
val foo3 =
when (bar) {
BAR1 -> "bar1"
// BAR2 comment
BAR2 -> "bar2"
else -> null
}

// ij_kotlin_line_break_after_multiline_when_entry = false (unexpected newline after BAR2)
val foo2 =
val foo4 =
when (bar) {
BAR1 -> "bar1"
BAR2 -> {
Expand Down
Expand Up @@ -148,6 +148,7 @@ public class ArgumentListWrappingRule :
// 2
// )
child.treeParent.hasTypeArgumentListInFront() -> -1

// IDEA quirk:
// foo
// .bar = Baz(
Expand All @@ -161,6 +162,7 @@ public class ArgumentListWrappingRule :
// 2
// )
child.treeParent.isPartOfDotQualifiedAssignmentExpression() -> -1

else -> 0
}.let {
if (child.treeParent.isOnSameLineAsControlFlowKeyword()) {
Expand Down
Expand Up @@ -10,10 +10,12 @@ import com.pinterest.ktlint.rule.engine.core.api.children
import com.pinterest.ktlint.rule.engine.core.api.editorconfig.EditorConfig
import com.pinterest.ktlint.rule.engine.core.api.editorconfig.EditorConfigProperty
import com.pinterest.ktlint.rule.engine.core.api.indent
import com.pinterest.ktlint.rule.engine.core.api.isPartOfComment
import com.pinterest.ktlint.rule.engine.core.api.isWhiteSpace
import com.pinterest.ktlint.rule.engine.core.api.lastChildLeafOrSelf
import com.pinterest.ktlint.rule.engine.core.api.nextLeaf
import com.pinterest.ktlint.rule.engine.core.api.prevCodeSibling
import com.pinterest.ktlint.rule.engine.core.api.prevSibling
import com.pinterest.ktlint.rule.engine.core.api.upsertWhitespaceBeforeMe
import com.pinterest.ktlint.ruleset.standard.StandardRule
import org.ec4j.core.model.PropertyType
Expand Down Expand Up @@ -92,7 +94,11 @@ public class BlankLineBetweenWhenConditions :

private fun ASTNode.containsBlankLine(): Boolean = elementType == WHITE_SPACE && text.count { it == '\n' } > 1

private fun ASTNode.hasAnyMultilineWhenCondition() = children().any { it.elementType == WHEN_ENTRY && it.textContains('\n') }
private fun ASTNode.hasAnyMultilineWhenCondition() =
children()
.any { it.elementType == WHEN_ENTRY && (it.textContains('\n') || it.isPrecededByComment()) }

private fun ASTNode.isPrecededByComment() = prevSibling { !it.isWhiteSpace() }?.isPartOfComment() ?: false

private fun ASTNode.findWhitespaceAfterPreviousCodeSibling() =
prevCodeSibling()
Expand Down
Expand Up @@ -224,6 +224,7 @@ public class ParameterListWrappingRule :
// param2: R
// )
child.treeParent.isFunWithTypeParameterListInFront() -> -1

else -> 0
}.let {
if (child.elementType == VALUE_PARAMETER) {
Expand Down
@@ -1,5 +1,6 @@
package com.pinterest.ktlint.ruleset.standard.rules

import com.pinterest.ktlint.rule.engine.core.api.ElementType
import com.pinterest.ktlint.rule.engine.core.api.ElementType.CALL_EXPRESSION
import com.pinterest.ktlint.rule.engine.core.api.ElementType.CLOSING_QUOTE
import com.pinterest.ktlint.rule.engine.core.api.ElementType.COMMA
Expand Down Expand Up @@ -43,8 +44,6 @@ public class StringTemplateIndentRule :
id = "string-template-indent",
visitorModifiers =
setOf(
// Wrap all multiline string templates to a separate line
// VisitorModifier.RunAfterRule(MULTILINE_EXPRESSION_WRAPPING_RULE_ID, ONLY_WHEN_RUN_AFTER_RULE_IS_LOADED_AND_ENABLED),
// The IndentationRule first needs to fix the indentation of the opening quotes of the string template. The indentation inside
// the string template is relative to the opening quotes. Running this rule before the IndentationRule results in a wrong
// indentation whenever the indent level of the root of the string template is changed.
Expand Down Expand Up @@ -99,6 +98,7 @@ public class StringTemplateIndentRule :
stringTemplate
.takeUnless { it.isPrecededByWhitespaceWithNewline() }
?.takeUnless { it.isPrecededByReturnKeyword() }
?.takeUnless { it.isFunctionBodyExpressionOnSameLine() }
?.let { whiteSpace ->
emit(stringTemplate.startOffset, "Expected newline before multiline string template", true)
if (autoCorrect) {
Expand Down Expand Up @@ -151,6 +151,19 @@ public class StringTemplateIndentRule :
// """
prevCodeLeaf()?.elementType == RETURN_KEYWORD

private fun ASTNode.isFunctionBodyExpressionOnSameLine() =
prevCodeLeaf()
?.takeIf { it.elementType == ElementType.EQ }
?.closingParenthesisOfFunctionOrNull()
?.prevLeaf()
?.let { it.isWhiteSpaceWithNewline() }
?: false

private fun ASTNode.closingParenthesisOfFunctionOrNull() =
takeIf { treeParent.elementType == ElementType.FUN }
?.prevCodeLeaf()
?.takeIf { it.elementType == ElementType.RPAR }

private fun ASTNode.getIndent(): String {
// When executing this rule, the indentation rule may not have run yet. The functionality to determine the correct indentation level
// is out of scope of this rule as it is owned by the indentation rule. Therefore, the indentation of the line at which the
Expand Down
Expand Up @@ -13,7 +13,7 @@ import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.CsvSource
import org.junit.jupiter.params.provider.ValueSource

class BackingPropertyRuleTest {
class BackingPropertyNamingRuleTest {
private val backingPropertyNamingRuleAssertThat = assertThatRule { BackingPropertyNamingRule() }

@Nested
Expand Down
Expand Up @@ -122,7 +122,7 @@ class BlankLineBetweenWhenConditionsTest {
}

@Test
fun `Given xx a when-condition preceded by a comment and the when-condition needs to be preceded by blank line then add this line before the comment`() {
fun `Given a when-condition with a single line body on the next line then add blank lines`() {
val code =
"""
val foo =
Expand Down Expand Up @@ -185,6 +185,33 @@ class BlankLineBetweenWhenConditionsTest {
.hasLintViolation(4, 1, "Add a blank line between all when-condition in case at least one multiline when-condition is found in the statement")
.isFormattedAs(formattedCode)
}

@Test
fun `Given a simple when-statement in which a when condition is preceded by a comment then add blank lines between the when-conditions`() {
val code =
"""
val foo =
when (bar) {
BAR -> "bar"
// Some comment
else -> null
}
""".trimIndent()
val formattedCode =
"""
val foo =
when (bar) {
BAR -> "bar"
// Some comment
else -> null
}
""".trimIndent()
@Suppress("ktlint:standard:argument-list-wrapping", "ktlint:standard:max-line-length")
blankLineAfterWhenConditionRuleAssertThat(code)
.hasLintViolation(4, 1, "Add a blank line between all when-condition in case at least one multiline when-condition is found in the statement")
.isFormattedAs(formattedCode)
}
}

@Nested
Expand Down
Expand Up @@ -470,4 +470,22 @@ class StringTemplateIndentRuleTest {
""".trimIndent().replaceStringTemplatePlaceholder()
stringTemplateIndentRuleAssertThat(code).hasNoLintViolations()
}

@Test
fun `Given a string template on same line as closing parenthesis of multiline function signature`() {
// Interpret "$." in code sample below as "$". It is used whenever the code which has to be inspected should
// actually contain a string template. Using "$" instead of "$." would result in a String in which the string
// templates would have been evaluated before the code would actually be processed by the rule.
val code =
"""
fun foo(
bar: String
) = $MULTILINE_STRING_QUOTE
Bar: $.bar
$MULTILINE_STRING_QUOTE.trimIndent()
""".trimIndent()
stringTemplateIndentRuleAssertThat(code)
.addAdditionalRuleProvider { MultilineExpressionWrappingRule() }
.hasNoLintViolations()
}
}

0 comments on commit 623431b

Please sign in to comment.