diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/BlockStructureBraces.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/BlockStructureBraces.kt index 3cd13a9842..a2b5b43144 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/BlockStructureBraces.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/BlockStructureBraces.kt @@ -7,6 +7,7 @@ import org.cqfn.diktat.ruleset.constants.Warnings.BRACES_BLOCK_STRUCTURE_ERROR import org.cqfn.diktat.ruleset.rules.DiktatRule import org.cqfn.diktat.ruleset.utils.* +import com.pinterest.ktlint.core.ast.ElementType import com.pinterest.ktlint.core.ast.ElementType.BLOCK import com.pinterest.ktlint.core.ast.ElementType.BODY import com.pinterest.ktlint.core.ast.ElementType.CATCH @@ -233,6 +234,11 @@ class BlockStructureBraces(configRules: List) : DiktatRule( return } val space = node.findChildByType(RBRACE)!!.treePrev + node.findParentNodeWithSpecificType(ElementType.LAMBDA_ARGUMENT)?.let { + if (space.text.isEmpty()) { + return + } + } if (checkBraceNode(space)) { BRACES_BLOCK_STRUCTURE_ERROR.warnAndFix(configRules, emitWarn, isFixMode, "no newline before closing brace", (space.treeNext ?: node.findChildByType(RBRACE))!!.startOffset, node) { diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/EmptyBlock.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/EmptyBlock.kt index 1034ed1063..f0405440c5 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/EmptyBlock.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/EmptyBlock.kt @@ -5,14 +5,9 @@ import org.cqfn.diktat.common.config.rules.RulesConfig import org.cqfn.diktat.common.config.rules.getRuleConfig import org.cqfn.diktat.ruleset.constants.Warnings.EMPTY_BLOCK_STRUCTURE_ERROR import org.cqfn.diktat.ruleset.rules.DiktatRule -import org.cqfn.diktat.ruleset.utils.findLBrace -import org.cqfn.diktat.ruleset.utils.findLeafWithSpecificType -import org.cqfn.diktat.ruleset.utils.findParentNodeWithSpecificType -import org.cqfn.diktat.ruleset.utils.hasParent -import org.cqfn.diktat.ruleset.utils.isBlockEmpty -import org.cqfn.diktat.ruleset.utils.isOverridden -import org.cqfn.diktat.ruleset.utils.isPascalCase +import org.cqfn.diktat.ruleset.utils.* +import com.pinterest.ktlint.core.ast.ElementType import com.pinterest.ktlint.core.ast.ElementType.CALL_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.FUNCTION_LITERAL import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER @@ -41,7 +36,10 @@ class EmptyBlock(configRules: List) : DiktatRule( checkEmptyBlock(newNode, configuration) } - @Suppress("UnsafeCallOnNullableType") + private fun isNewLine(node: ASTNode) = + node.findChildByType(WHITE_SPACE)?.text?.contains("\n") ?: false + + @Suppress("UnsafeCallOnNullableType", "TOO_LONG_FUNCTION") private fun checkEmptyBlock(node: ASTNode, configuration: EmptyBlockStyleConfiguration) { if (node.treeParent.isOverridden() || isAnonymousSamClass(node)) { return @@ -51,6 +49,19 @@ class EmptyBlock(configRules: List) : DiktatRule( EMPTY_BLOCK_STRUCTURE_ERROR.warn(configRules, emitWarn, isFixMode, "empty blocks are forbidden unless it is function with override keyword", node.startOffset, node) } else { + node.findParentNodeWithSpecificType(ElementType.LAMBDA_ARGUMENT)?.let { + // Lambda body is always has a BLOCK -> run { } - (LBRACE, WHITE_SPACE, BLOCK "", RBRACE) + if (isNewLine(node)) { + val freeText = "do not put newlines in empty lambda" + EMPTY_BLOCK_STRUCTURE_ERROR.warnAndFix(configRules, emitWarn, isFixMode, freeText, node.startOffset, node) { + val whiteSpaceNode = node.findChildByType(WHITE_SPACE) + whiteSpaceNode?.let { + node.replaceChild(whiteSpaceNode, PsiWhiteSpaceImpl(" ")) + } + } + } + return + } val space = node.findChildByType(RBRACE)!!.treePrev if (configuration.emptyBlockNewline && !space.text.contains("\n")) { EMPTY_BLOCK_STRUCTURE_ERROR.warnAndFix(configRules, emitWarn, isFixMode, "different style for empty block", diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/BlankLinesRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/BlankLinesRule.kt index d055ffbf7f..d638f25096 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/BlankLinesRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/BlankLinesRule.kt @@ -3,6 +3,7 @@ package org.cqfn.diktat.ruleset.rules.chapter3.files import org.cqfn.diktat.common.config.rules.RulesConfig import org.cqfn.diktat.ruleset.constants.Warnings.TOO_MANY_BLANK_LINES import org.cqfn.diktat.ruleset.rules.DiktatRule +import org.cqfn.diktat.ruleset.utils.findParentNodeWithSpecificType import org.cqfn.diktat.ruleset.utils.getFirstChildWithType import org.cqfn.diktat.ruleset.utils.leaveExactlyNumNewLines import org.cqfn.diktat.ruleset.utils.leaveOnlyOneNewLine @@ -12,6 +13,7 @@ import com.pinterest.ktlint.core.ast.ElementType.BLOCK import com.pinterest.ktlint.core.ast.ElementType.CLASS_BODY import com.pinterest.ktlint.core.ast.ElementType.FILE import com.pinterest.ktlint.core.ast.ElementType.FUNCTION_LITERAL +import com.pinterest.ktlint.core.ast.ElementType.LAMBDA_ARGUMENT import com.pinterest.ktlint.core.ast.ElementType.LBRACE import com.pinterest.ktlint.core.ast.ElementType.RBRACE import com.pinterest.ktlint.core.ast.ElementType.SCRIPT @@ -44,6 +46,13 @@ class BlankLinesRule(configRules: List) : DiktatRule( it.elementType == BLOCK && it.treeParent?.elementType != SCRIPT || it.elementType == CLASS_BODY || it.elementType == FUNCTION_LITERAL }) { + node.findParentNodeWithSpecificType(LAMBDA_ARGUMENT)?.let { + // Lambda body is always has a BLOCK -> run { } - (LBRACE, WHITE_SPACE, BLOCK "", RBRACE) + if (node.treeNext.text.isEmpty()) { + return + } + } + if ((node.treeNext.elementType == RBRACE) xor (node.treePrev.elementType == LBRACE)) { // if both are present, this is not beginning or end // if both are null, then this block is empty and is handled in another rule diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/BlockStructureBracesWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/BlockStructureBracesWarnTest.kt index 6fbcb92a84..b34828e1d4 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/BlockStructureBracesWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/BlockStructureBracesWarnTest.kt @@ -85,6 +85,20 @@ class BlockStructureBracesWarnTest : LintTestBase(::BlockStructureBraces) { ) } + @Test + @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR) + fun `check lambda with empty block`() { + lintMethod( + """ + |fun foo() { + | run { + | + | } + |} + """.trimMargin() + ) + } + @Test @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR) fun `check empty block in else expression`() { diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/EmptyBlockWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/EmptyBlockWarnTest.kt index 656ac7af05..66e82eb25e 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/EmptyBlockWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/EmptyBlockWarnTest.kt @@ -96,39 +96,39 @@ class EmptyBlockWarnTest : LintTestBase(::EmptyBlock) { } @Test - fun `check if-else expression without block`() { + fun `empty lambda`() { lintMethod( """ |fun foo() { - | if (node.treeParent != null) return else println(true) + | run { } |} - """.trimMargin() + """.trimMargin(), + rulesConfigList = rulesConfigListEmptyBlockExist ) } @Test - fun `check for expresion and while without block`() { + fun `check if-else expression without block`() { lintMethod( """ |fun foo() { - | for(x in 0..10) println(x) - | val x = 10 - | while (x > 0) - | --x + | if (node.treeParent != null) return else println(true) |} """.trimMargin() ) } @Test - fun `check empty lambda`() { + fun `check for expresion and while without block`() { lintMethod( """ |fun foo() { - | val y = listOf().map {} + | for(x in 0..10) println(x) + | val x = 10 + | while (x > 0) + | --x |} - """.trimMargin(), - LintError(2, 30, ruleId, "${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} empty blocks are forbidden unless it is function with override keyword", false) + """.trimMargin() ) } @@ -138,14 +138,28 @@ class EmptyBlockWarnTest : LintTestBase(::EmptyBlock) { lintMethod( """ |fun foo() { - | val y = listOf().map {} + | val y = listOf().map { + | + | } |} """.trimMargin(), - LintError(2, 30, ruleId, "${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} different style for empty block", true), + LintError(2, 30, ruleId, "${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} do not put newlines in empty lambda", true), rulesConfigList = rulesConfigListEmptyBlockExist ) } + @Test + fun `check empty lambda`() { + lintMethod( + """ + |fun foo() { + | val y = listOf().map { } + |} + """.trimMargin(), + LintError(2, 30, ruleId, "${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} empty blocks are forbidden unless it is function with override keyword", false) + ) + } + @Test fun `should not trigger on anonymous SAM classes #1`() { lintMethod( diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/BlankLinesWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/BlankLinesWarnTest.kt index 02a2b2947b..ff4ddae24e 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/BlankLinesWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/BlankLinesWarnTest.kt @@ -30,6 +30,20 @@ class BlankLinesWarnTest : LintTestBase(::BlankLinesRule) { ) } + @Test + @Tag(WarningNames.TOO_MANY_BLANK_LINES) + fun `check lambda with empty block`() { + lintMethod( + """ + |fun foo() { + | run { + | + | } + |} + """.trimMargin() + ) + } + @Test @Tag(WarningNames.TOO_MANY_BLANK_LINES) fun `should prohibit usage of two or more consecutive blank lines`() { diff --git a/diktat-rules/src/test/resources/test/paragraph3/empty_block/EmptyBlockExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/empty_block/EmptyBlockExpected.kt index a47f33cf2b..debdaa86fe 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/empty_block/EmptyBlockExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/empty_block/EmptyBlockExpected.kt @@ -10,8 +10,7 @@ fun foo () { fun goo () { var x = 10 if (x == 10) return else println(10) - val y = listOf().map { -} + val y = listOf().map { } for(x in 0..10) println(x) while (x > 0) --x diff --git a/diktat-rules/src/test/resources/test/paragraph3/empty_block/EmptyBlockTest.kt b/diktat-rules/src/test/resources/test/paragraph3/empty_block/EmptyBlockTest.kt index 7316e61550..fb5faa35ff 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/empty_block/EmptyBlockTest.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/empty_block/EmptyBlockTest.kt @@ -9,7 +9,9 @@ fun foo () { fun goo () { var x = 10 if (x == 10) return else println(10) - val y = listOf().map {} + val y = listOf().map { + + } for(x in 0..10) println(x) while (x > 0) --x