Skip to content

Commit

Permalink
Ignore nested reference expressions in chain-method-continuation (#…
Browse files Browse the repository at this point in the history
…2606)

Closes #2602
  • Loading branch information
paul-dingemans committed Mar 17, 2024
1 parent feb3226 commit 2b396bd
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public class ChainMethodContinuationRule :
chainedExpression
.chainOperators
.filterNot { it.isJavaClassReferenceExpression() }
.filterNot { it.isSimpleReferenceExpression() }
.filterNot { it.isReferenceExpression() }
.forEach { chainOperator ->
when {
chainOperator.shouldBeOnSameLineAsClosingElementOfPreviousExpressionInMethodChain() -> {
Expand All @@ -161,10 +161,14 @@ public class ChainMethodContinuationRule :
nextCodeSibling()?.elementType == REFERENCE_EXPRESSION &&
nextCodeSibling()?.firstChildLeafOrSelf()?.text == "java"

private fun ASTNode.isSimpleReferenceExpression() =
treeParent.elementType == DOT_QUALIFIED_EXPRESSION &&
prevCodeSibling()?.elementType == REFERENCE_EXPRESSION &&
nextCodeSibling()?.elementType == REFERENCE_EXPRESSION
private fun ASTNode.isReferenceExpression(): Boolean = treeParent.isNestedReferenceExpression()

private fun ASTNode.isNestedReferenceExpression(): Boolean =
elementType == DOT_QUALIFIED_EXPRESSION &&
children().first().let { it.elementType == REFERENCE_EXPRESSION || it.hasRightHandSideReferenceExpression() } &&
hasRightHandSideReferenceExpression()

private fun ASTNode.hasRightHandSideReferenceExpression() = children().last().elementType == REFERENCE_EXPRESSION

private fun ChainedExpression.wrapBeforeChainOperator() =
when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -532,16 +532,13 @@ class ChainMethodContinuationRuleTest {
"""
// $MAX_LINE_LENGTH_MARKER $EOL_CHAR
val foo1 = Foo::class.java.canonicalName
val foo2 = Foo::class.java
.canonicalName
val foo2 = Foo::class.java.canonicalName
.uppercase()
""".trimIndent()
chainMethodContinuationRuleAssertThat(code)
.setMaxLineLength()
.hasLintViolations(
LintViolation(3, 27, "Expected newline before '.'"),
LintViolation(3, 41, "Expected newline before '.'"),
).isFormattedAs(formattedCode)
.hasLintViolation(3, 41, "Expected newline before '.'")
.isFormattedAs(formattedCode)
}

@Nested
Expand Down Expand Up @@ -1038,4 +1035,86 @@ class ChainMethodContinuationRuleTest {
LintViolation(2, 54, "Expected newline before '.'"),
).isFormattedAs(formattedCode)
}

@Test
fun `Issue 2602 - Given a chained method starting with some nested reference expressions then do not wrap the reference expressions`() {
val code =
"""
// $MAX_LINE_LENGTH_MARKER $EOL_CHAR
fun buildBar1(): Foo.Bar = Foo.Bar.builder().build()
fun buildBar2(): Foo.Bar = Foo.bar.Bar.builder().build()
fun buildBar3(): Foo.Bar = Foo.bar.bar.Bar.builder().build()
""".trimIndent()
val formattedCode =
"""
// $MAX_LINE_LENGTH_MARKER $EOL_CHAR
fun buildBar1(): Foo.Bar = Foo.Bar
.builder()
.build()
fun buildBar2(): Foo.Bar = Foo.bar.Bar
.builder()
.build()
fun buildBar3(): Foo.Bar = Foo.bar.bar.Bar
.builder()
.build()
""".trimIndent()
chainMethodContinuationRuleAssertThat(code)
.setMaxLineLength()
.addAdditionalRuleProvider { MaxLineLengthRule() }
.hasLintViolations(
LintViolation(2, 35, "Expected newline before '.'"),
LintViolation(2, 45, "Expected newline before '.'"),
LintViolation(3, 39, "Expected newline before '.'"),
LintViolation(3, 49, "Expected newline before '.'"),
LintViolation(4, 43, "Expected newline before '.'"),
LintViolation(4, 53, "Expected newline before '.'"),
).isFormattedAs(formattedCode)
}

@Test
fun `Given a chained method having some nested reference expressions after chained method call then do not wrap the reference expressions`() {
val code =
"""
// $MAX_LINE_LENGTH_MARKER $EOL_CHAR
fun buildBar1(): Foo.Bar = Foo.baz().Bar.builder().build()
fun buildBar2(): Foo.Bar = Foo.baz().bar.Bar.builder().build()
fun buildBar3(): Foo.Bar = Foo.baz().bar.bar.Bar.builder().build()
""".trimIndent()
val formattedCode =
"""
// $MAX_LINE_LENGTH_MARKER $EOL_CHAR
fun buildBar1(): Foo.Bar = Foo
.baz()
.Bar
.builder()
.build()
fun buildBar2(): Foo.Bar = Foo
.baz()
.bar.Bar
.builder()
.build()
fun buildBar3(): Foo.Bar = Foo
.baz()
.bar.bar.Bar
.builder()
.build()
""".trimIndent()
chainMethodContinuationRuleAssertThat(code)
.setMaxLineLength()
.addAdditionalRuleProvider { MaxLineLengthRule() }
.hasLintViolations(
LintViolation(2, 31, "Expected newline before '.'"),
LintViolation(2, 37, "Expected newline before '.'"),
LintViolation(2, 41, "Expected newline before '.'"),
LintViolation(2, 51, "Expected newline before '.'"),
LintViolation(3, 31, "Expected newline before '.'"),
LintViolation(3, 37, "Expected newline before '.'"),
LintViolation(3, 45, "Expected newline before '.'"),
LintViolation(3, 55, "Expected newline before '.'"),
LintViolation(4, 31, "Expected newline before '.'"),
LintViolation(4, 37, "Expected newline before '.'"),
LintViolation(4, 49, "Expected newline before '.'"),
LintViolation(4, 59, "Expected newline before '.'"),
).isFormattedAs(formattedCode)
}
}

0 comments on commit 2b396bd

Please sign in to comment.