diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/WhiteSpaceRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/WhiteSpaceRule.kt index 3c9d2416a8..7c34b51ff5 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/WhiteSpaceRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/WhiteSpaceRule.kt @@ -171,7 +171,8 @@ class WhiteSpaceRule(private val configRules: List) : Rule("horizon */ @Suppress("UnsafeCallOnNullableType") private fun handleLbrace(node: ASTNode) { - val whitespaceOrPrevNode = node.parent({ it.treePrev != null }, strict = false)!!.treePrev + // `{` can't be the very first symbol in the file, so `!!` should be safe + val whitespaceOrPrevNode = node.selfOrParentsTreePrev()!! val isFromLambdaAsArgument = node .parents() .take(numParentsForLambda) @@ -181,12 +182,15 @@ class WhiteSpaceRule(private val configRules: List) : Rule("horizon it[0].elementType == FUNCTION_LITERAL && it[1].elementType == LAMBDA_EXPRESSION && it[2].elementType == VALUE_ARGUMENT && + // lambda is not passed as a named argument !it[2].hasChildOfType(EQ) && + // lambda is the first argument in the list it[2].prevSibling { prevNode -> prevNode.elementType == COMMA } == null } ?: false val prevNode = whitespaceOrPrevNode.let { if (it.elementType == WHITE_SPACE) it.treePrev else it } val numWhiteSpace = whitespaceOrPrevNode.numWhiteSpaces() + // note: the conditions in the following `if`s cannot be collapsed into simple conjunctions if (isFromLambdaAsArgument) { if (numWhiteSpace != 0) { WRONG_WHITESPACE.warnAndFix(configRules, emitWarn, isFixMode, "there should be no whitespace before '{' of lambda" + @@ -239,8 +243,11 @@ class WhiteSpaceRule(private val configRules: List) : Rule("horizon @Suppress("UnsafeCallOnNullableType") private fun handleToken(node: ASTNode, requiredSpacesBefore: Int?, requiredSpacesAfter: Int?) { - require(requiredSpacesBefore != null || requiredSpacesAfter != null) - val spacesBefore = node.parent({ it.treePrev != null }, strict = false)!!.treePrev.numWhiteSpaces() + require(requiredSpacesBefore != null || requiredSpacesAfter != null) { + "requiredSpacesBefore=$requiredSpacesBefore and requiredSpacesAfter=$requiredSpacesAfter, but at least one should not be null" + } + val spacesBefore = node.selfOrParentsTreePrev()!!.numWhiteSpaces() + // calculate actual spaces after but only if requiredSpacesAfter is not null, otherwise we won't check it val spacesAfter = requiredSpacesAfter?.let { _ -> // for `!!` and possibly other postfix expressions treeNext and treeParent.treeNext can be null // upper levels are already outside of the expression this token belongs to, so we won't check them @@ -309,23 +316,25 @@ class WhiteSpaceRule(private val configRules: List) : Rule("horizon } private fun ASTNode.fixSpaceAround(requiredSpacesBefore: Int?, requiredSpacesAfter: Int?) { - if (requiredSpacesBefore != null) { - if (requiredSpacesBefore == 1) { - (if (treePrev.elementType == WHITE_SPACE) treePrev.treePrev else treePrev).leaveSingleWhiteSpace() - } else if (requiredSpacesBefore == 0) { - treePrev.removeIfWhiteSpace() - } + if (requiredSpacesBefore == 1) { + selfOrParentsTreePrev()?.let { if (it.elementType == WHITE_SPACE) it.treePrev else it }?.leaveSingleWhiteSpace() + } else if (requiredSpacesBefore == 0) { + selfOrParentsTreePrev()?.removeIfWhiteSpace() } - if (requiredSpacesAfter != null) { - if (requiredSpacesAfter == 1) { - leaveSingleWhiteSpace() - } else if (requiredSpacesAfter == 0) { - // for `!!` and possibly other postfix expressions treeNext can be null - (treeNext ?: treeParent.treeNext).removeIfWhiteSpace() - } + + if (requiredSpacesAfter == 1) { + leaveSingleWhiteSpace() + } else if (requiredSpacesAfter == 0) { + // for `!!` and possibly other postfix expressions treeNext can be null + (treeNext ?: treeParent.treeNext).removeIfWhiteSpace() } } + /** + * Function that returns `treePrev` of this node, or if this.treePrev is null, `treePrev` of first parent node that has it + */ + private fun ASTNode.selfOrParentsTreePrev() = parent({ it.treePrev != null }, strict = false)?.treePrev + /** * This method counts spaces in this node. Null is returned in following cases: * * if it is WHITE_SPACE with a newline diff --git a/diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLParExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLParExpected.kt index 8038a3e329..36e0011387 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLParExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLParExpected.kt @@ -15,3 +15,8 @@ class Example : SuperExample { when (expression) { } } } + +data class Example( + val foo: Foo, + val bar: Bar +) diff --git a/diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLParTest.kt b/diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLParTest.kt index e23b99176a..26ca963b94 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLParTest.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLParTest.kt @@ -9,9 +9,14 @@ class Example : SuperExample { when(expression) { } } - fun bar() { + fun bar () { if (condition) { } for (i in 1..100) { } when (expression) { } } } + +data class Example ( + val foo: Foo, + val bar: Bar +)