Skip to content

Commit

Permalink
Prevent incorrect reporting of violations in case a nullable function…
Browse files Browse the repository at this point in the history
… type reference exceeds the maximum line length `parameter-list-wrapping`

Closes #1324
  • Loading branch information
paul-dingemans committed May 27, 2023
1 parent bd0005a commit 1cb8e6e
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 82 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
* Do not flag a (potential) mutable extension property in case the getter is annotated or prefixed with a modifier `property-naming` ([#2024](https://github.com/pinterest/ktlint/issues/2024))
* Do not merge an annotated expression body with the function signature even if it fits on a single line ([#2043](https://github.com/pinterest/ktlint/issues/2043))
* Ignore property with name `serialVersionUID` in `property-naming` ([#2045](https://github.com/pinterest/ktlint/issues/2045))
* Prevent incorrect reporting of violations in case a nullable function type reference exceeds the maximum line length `parameter-list-wrapping` ([#1324](https://github.com/pinterest/ktlint/issues/1324))

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import com.pinterest.ktlint.rule.engine.core.api.editorconfig.MAX_LINE_LENGTH_PR
import com.pinterest.ktlint.rule.engine.core.api.firstChildLeafOrSelf
import com.pinterest.ktlint.rule.engine.core.api.indent
import com.pinterest.ktlint.rule.engine.core.api.isWhiteSpaceWithNewline
import com.pinterest.ktlint.rule.engine.core.api.parent
import com.pinterest.ktlint.rule.engine.core.api.leavesIncludingSelf
import com.pinterest.ktlint.rule.engine.core.api.nextLeaf
import com.pinterest.ktlint.rule.engine.core.api.prevCodeLeaf
import com.pinterest.ktlint.rule.engine.core.api.prevLeaf
import com.pinterest.ktlint.rule.engine.core.api.prevSibling
Expand Down Expand Up @@ -89,48 +90,55 @@ public class ParameterListWrappingRule :
require(node.elementType == NULLABLE_TYPE)
node
.takeUnless {
// skip when max line length is not exceedd
// skip when max line length is not exceeded
(node.column - 1 + node.textLength) <= maxLineLength
}?.findChildByType(FUNCTION_TYPE)
?.findChildByType(VALUE_PARAMETER_LIST)
?.takeIf { it.findChildByType(VALUE_PARAMETER) != null }
?.takeUnless { it.textContains('\n') }
?.let {
node
.children()
.forEach {
when (it.elementType) {
LPAR -> {
emit(
it.startOffset,
"Parameter of nullable type should be on a separate line (unless the type fits on a single line)",
true,
)
if (autoCorrect) {
it.upsertWhitespaceAfterMe("\n${indentConfig.indent}")
}
}
RPAR -> {
emit(it.startOffset, errorMessage(it), true)
if (autoCorrect) {
it.upsertWhitespaceBeforeMe("\n")
}
}
}?.takeUnless { it.textContains('\n') }
?.takeIf { it.isFunctionTypeWithNonEmptyValueParameterList() }
?.let { nullableType ->
nullableType
.findChildByType(LPAR)
?.takeUnless { it.nextLeaf()?.isWhiteSpaceWithNewline() == true }
?.let { lpar ->
emit(
lpar.startOffset + 1,
"Expected new line before function type as it does not fit on a single line",
true,
)
if (autoCorrect) {
lpar.upsertWhitespaceAfterMe("\n${indentConfig.indent}")
}
}
nullableType
.findChildByType(RPAR)
?.takeUnless { it.prevLeaf()?.isWhiteSpaceWithNewline() == true }
?.let { rpar ->
emit(
rpar.startOffset,
"Expected new line after function type as it does not fit on a single line",
true
)
if (autoCorrect) {
rpar.upsertWhitespaceBeforeMe("\n")
}
}
}
}

private fun ASTNode.isFunctionTypeWithNonEmptyValueParameterList() =
null !=
findChildByType(FUNCTION_TYPE)
?.findChildByType(VALUE_PARAMETER_LIST)
?.findChildByType(VALUE_PARAMETER)

private fun ASTNode.needToWrapParameterList() =
when {
hasNoParameters() -> false
codeStyle != ktlint_official && isPartOfFunctionLiteralInNonKtlintOfficialCodeStyle() -> false
codeStyle == ktlint_official && isPartOfFunctionLiteralStartingOnSameLineAsClosingParenthesisOfPrecedingReferenceExpression() ->
false
isFunctionTypeWrappedInNullableType() -> false
textContains('\n') -> true
codeStyle == ktlint_official && containsAnnotatedParameter() -> true
exceedsMaxLineLength() -> true
isOnLineExceedingMaxLineLength() -> true
else -> false
}

Expand Down Expand Up @@ -160,11 +168,6 @@ public class ParameterListWrappingRule :
}
}

private fun ASTNode.isFunctionTypeWrappedInNullableType(): Boolean {
require(elementType == VALUE_PARAMETER_LIST)
return treeParent.elementType == FUNCTION_TYPE && treeParent?.treeParent?.elementType == NULLABLE_TYPE
}

private fun ASTNode.containsAnnotatedParameter(): Boolean {
require(elementType == VALUE_PARAMETER_LIST)
return this.children()
Expand Down Expand Up @@ -222,10 +225,12 @@ public class ParameterListWrappingRule :
when (child.elementType) {
LPAR -> {
val prevLeaf = child.prevLeaf()
if (prevLeaf is PsiWhiteSpace && prevLeaf.textContains('\n')) {
if (!child.treeParent.isValueParameterListInFunctionType() &&
prevLeaf.isWhiteSpaceWithNewline()
) {
emit(child.startOffset, errorMessage(child), true)
if (autoCorrect) {
prevLeaf.delete()
(prevLeaf as PsiWhiteSpace).delete()
}
}
}
Expand Down Expand Up @@ -271,7 +276,24 @@ public class ParameterListWrappingRule :
}
}

private fun ASTNode.exceedsMaxLineLength() = (column - 1 + textLength) > maxLineLength && !textContains('\n')
private fun ASTNode.isValueParameterListInFunctionType() =
FUNCTION_TYPE ==
takeIf { it.elementType == VALUE_PARAMETER_LIST }
?.treeParent
?.elementType

private fun ASTNode.isOnLineExceedingMaxLineLength(): Boolean {
val stopLeaf = nextLeaf { it.textContains('\n') }?.nextLeaf()
val lineContent =
prevLeaf { it.textContains('\n') }
?.leavesIncludingSelf()
?.takeWhile { it.prevLeaf() != stopLeaf }
?.joinToString(separator = "") { it.text }
?.substringAfter('\n')
?.substringBefore('\n')
.orEmpty()
return lineContent.length > maxLineLength
}

private fun errorMessage(node: ASTNode) =
when (node.elementType) {
Expand Down
Loading

0 comments on commit 1cb8e6e

Please sign in to comment.