Repository: cqfn/diKTat (kotlin)

Issue:
Boolean conditions: strange logging
Diktat version:     implementation("org.cqfn.diktat:diktat-gradle-plugin:1.0.0-rc.1")
Running via gradle script.

```
 if (doubleQuoteIsClosed && singleQuoteIsClosed) {
                // FixMe: isLetterOrDigit is not supported in Kotlin 1.4, but 1.5 is not compiling right now
                if (!setOf('_', '-', '.', '"', '\'').contains(ch) && !ch.isLetterOrDigit())
                    throw TomlParsingException(
                        "Not able to parse the key: [$rawContent] as it contains invalid symbols." +
                                " In case you would like to use special symbols - use quotes.",
                        lineNo
                    )
            }
```
```
line 2:0 no viable alternative at character '/'
line 2:1 no viable alternative at character '/'
line 2:8 no viable alternative at character ':'
line 2:10 mismatched input 'isLetterOrDigit' expecting RPAREN
line 2:54 no viable alternative at character '.'
line 2:56 no viable alternative at character ','
line 2:63 no viable alternative at character '.'
```

Pull request description:
### What's done:
* Changed logic
* Added tests

This pull request closes #959

Patch:
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/BooleanExpressionsRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/BooleanExpressionsRule.kt
index 8a80d65c79..6fb7b78e40 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/BooleanExpressionsRule.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/BooleanExpressionsRule.kt
@@ -19,6 +19,8 @@ import com.pinterest.ktlint.core.ast.ElementType.CONDITION
 import com.pinterest.ktlint.core.ast.ElementType.OPERATION_REFERENCE
 import com.pinterest.ktlint.core.ast.ElementType.PARENTHESIZED
 import com.pinterest.ktlint.core.ast.ElementType.PREFIX_EXPRESSION
+import com.pinterest.ktlint.core.ast.isLeaf
+import com.pinterest.ktlint.core.ast.isPartOfComment
 import org.jetbrains.kotlin.com.intellij.lang.ASTNode
 import org.jetbrains.kotlin.psi.KtBinaryExpression
 import org.jetbrains.kotlin.psi.KtParenthesizedExpression
@@ -110,13 +112,13 @@ class BooleanExpressionsRule(configRules: List<RulesConfig>) : DiktatRule(
             }
         var characterAsciiCode = 'A'.code  // `A` character in ASCII
         (logicalExpressions + elementaryBooleanExpressions).forEach { expression ->
-            mapOfExpressionToChar.computeIfAbsent(expression.text) {
+            mapOfExpressionToChar.computeIfAbsent(expression.textWithoutComments()) {
                 // Every elementary expression is assigned a single-letter variable.
                 characterAsciiCode++.toChar()
             }
         }
         // Prepare final formatted string
-        var correctedExpression = node.text
+        var correctedExpression = node.textWithoutComments()
         // At first, substitute all elementary expressions with variables
         mapOfExpressionToChar.forEach { (refExpr, char) ->
             correctedExpression = correctedExpression.replace(refExpr, char.toString())
@@ -131,17 +133,24 @@ class BooleanExpressionsRule(configRules: List<RulesConfig>) : DiktatRule(
      * Split the complex expression into elementary parts
      */
     private fun ASTNode.collectElementaryExpressions() = this
-        .findAllNodesWithCondition({ astNode ->
+        .findAllNodesWithCondition { astNode ->
             astNode.elementType == BINARY_EXPRESSION &&
                     // filter out boolean conditions in nested lambdas, e.g. `if (foo.filter { a && b })`
                     (astNode == this || astNode.parents().takeWhile { it != this }
                         .all { it.elementType in setOf(BINARY_EXPRESSION, PARENTHESIZED, PREFIX_EXPRESSION) })
-        })
+        }
         .partition {
             val operationReferenceText = (it.psi as KtBinaryExpression).operationReference.text
             operationReferenceText == "&&" || operationReferenceText == "||"
         }
 
+    private fun ASTNode.textWithoutComments() = findAllNodesWithCondition(withSelf = false) {
+        it.isLeaf()
+    }
+        .filterNot { it.isPartOfComment() }
+        .joinToString(separator = "") { it.text }
+        .replace("\n", " ")
+
     private fun fixBooleanExpression(
         node: ASTNode,
         simplifiedExpr: Expression<String>,
@@ -217,7 +226,7 @@ class BooleanExpressionsRule(configRules: List<RulesConfig>) : DiktatRule(
             getCommonOperand(expression, '|', '&')
         } else {
             // this is done for excluding A || B && A || C without parenthesis.
-            val parenthesizedExpressions = node.findAllNodesWithCondition({ it.elementType == PARENTHESIZED })
+            val parenthesizedExpressions = node.findAllNodesWithCondition { it.elementType == PARENTHESIZED }
             parenthesizedExpressions.forEach {
                 it.findLeafWithSpecificType(OPERATION_REFERENCE) ?: run {
                     return null
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/NullChecksRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/NullChecksRule.kt
index f52999d07e..8885de7311 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/NullChecksRule.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/NullChecksRule.kt
@@ -205,7 +205,7 @@ class NullChecksRule(configRules: List<RulesConfig>) : DiktatRule(
         .treeParent
         .findChildByType(type)
         ?.let { it.findChildByType(BLOCK) ?: it }
-        ?.findAllNodesWithCondition({ it.elementType == BREAK })?.isNotEmpty()
+        ?.findAllNodesWithCondition { it.elementType == BREAK }?.isNotEmpty()
         ?: false
 
     private fun ASTNode.extractLinesFromBlock(type: IElementType): List<String>? =
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/LambdaLengthRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/LambdaLengthRule.kt
index 533266c3c7..06b9d02aac 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/LambdaLengthRule.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/LambdaLengthRule.kt
@@ -33,7 +33,7 @@ class LambdaLengthRule(configRules: List<RulesConfig>) : DiktatRule(
         val copyNode = node.clone() as ASTNode
         val sizeLambda = countCodeLines(copyNode)
         if (sizeLambda > configuration.maxLambdaLength) {
-            copyNode.findAllNodesWithCondition({ it.elementType == ElementType.LAMBDA_EXPRESSION }).forEachIndexed { index, astNode ->
+            copyNode.findAllNodesWithCondition { it.elementType == ElementType.LAMBDA_EXPRESSION }.forEachIndexed { index, astNode ->
                 if (index > 0) {
                     astNode.treeParent.removeChild(astNode)
                 }
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/UselessSupertype.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/UselessSupertype.kt
index 9e041c9309..994f58f11e 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/UselessSupertype.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/UselessSupertype.kt
@@ -44,7 +44,7 @@ class UselessSupertype(configRules: List<RulesConfig>) : DiktatRule(
     private fun checkClass(node: ASTNode) {
         val superNodes = node
             .findChildByType(SUPER_TYPE_LIST)
-            ?.findAllNodesWithCondition({ it.elementType in superType })
+            ?.findAllNodesWithCondition { it.elementType in superType }
             ?.takeIf { it.isNotEmpty() } ?: return
         val qualifiedSuperCalls = node
             .findAllDescendantsWithSpecificType(DOT_QUALIFIED_EXPRESSION)
@@ -118,10 +118,10 @@ class UselessSupertype(configRules: List<RulesConfig>) : DiktatRule(
                 .first()
                 .text
         }
-        val superNodes = fileNode.findAllNodesWithCondition({ superClass ->
+        val superNodes = fileNode.findAllNodesWithCondition { superClass ->
             superClass.elementType == CLASS &&
                     superClass.getIdentifierName()!!.text in superNodesIdentifier
-        }).mapNotNull { it.findChildByType(CLASS_BODY) }
+        }.mapNotNull { it.findChildByType(CLASS_BODY) }
         if (superNodes.size != superTypeList.size) {
             return null
         }
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt
index 4e4fc80ad5..8fb437f207 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt
@@ -422,17 +422,16 @@ fun ASTNode.numNewLines() = text.count { it == '\n' }
  * This method performs tree traversal and returns all nodes with specific element type
  */
 fun ASTNode.findAllDescendantsWithSpecificType(elementType: IElementType, withSelf: Boolean = true) =
-        findAllNodesWithCondition({ it.elementType == elementType }, withSelf)
+        findAllNodesWithCondition(withSelf) { it.elementType == elementType }
 
 /**
  * This method performs tree traversal and returns all nodes which satisfy the condition
  */
-@Suppress("LAMBDA_IS_NOT_LAST_PARAMETER")
-fun ASTNode.findAllNodesWithCondition(condition: (ASTNode) -> Boolean,
-                                      withSelf: Boolean = true): List<ASTNode> {
+fun ASTNode.findAllNodesWithCondition(withSelf: Boolean = true,
+                                      condition: (ASTNode) -> Boolean): List<ASTNode> {
     val result = if (condition(this) && withSelf) mutableListOf(this) else mutableListOf()
     return result + this.getChildren(null).flatMap {
-        it.findAllNodesWithCondition(condition)
+        it.findAllNodesWithCondition(withSelf = true, condition)
     }
 }
 
@@ -808,7 +807,7 @@ fun isLocatedInTest(filePathParts: List<String>, testAnchors: List<String>) = fi
  * @return the number of lines in a block of code.
  */
 fun countCodeLines(copyNode: ASTNode): Int {
-    copyNode.findAllNodesWithCondition({ it.isPartOfComment() }).forEach { it.treeParent.removeChild(it) }
+    copyNode.findAllNodesWithCondition { it.isPartOfComment() }.forEach { it.treeParent.removeChild(it) }
     val text = copyNode.text.lines().filter { it.isNotBlank() }
     return text.size
 }


Test patch:
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/BooleanExpressionsRuleWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/BooleanExpressionsRuleWarnTest.kt
index 43de384360..afb8fb408e 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/BooleanExpressionsRuleWarnTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/BooleanExpressionsRuleWarnTest.kt
@@ -210,6 +210,19 @@ class BooleanExpressionsRuleWarnTest : LintTestBase(::BooleanExpressionsRule) {
         )
     }
 
+    @Test
+    fun `test makeCorrectExpressionString method - comment should be removed`() {
+        checkExpressionFormatter(
+            """
+                foo && bar &&
+                // FixMe: isLetterOrDigit is not supported in Kotlin 1.4, but 1.5 is not compiling right now
+                setOf('_', '-', '.', '"', '\'').baz() && ch.isLetterOrDigit()
+            """.trimIndent(),
+            "(C & D &  B & A)",
+            4
+        )
+    }
+
     @Test
     @Suppress("TOO_LONG_FUNCTION", "LongMethod")
     fun `regression - should not log ANTLR errors when parsing is not required`() {