Skip to content

Commit

Permalink
bugfix/empty-lambdas(#796)
Browse files Browse the repository at this point in the history
### What's done:
  * Fixed bug
  • Loading branch information
aktsay6 committed Mar 19, 2021
1 parent d9b6b6e commit 727aff3
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ 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.DOT_QUALIFIED_EXPRESSION
import com.pinterest.ktlint.core.ast.ElementType.FILE
import com.pinterest.ktlint.core.ast.ElementType.FUNCTION_LITERAL
import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER
import com.pinterest.ktlint.core.ast.ElementType.LAMBDA_EXPRESSION
import com.pinterest.ktlint.core.ast.ElementType.LPAR
import com.pinterest.ktlint.core.ast.ElementType.RBRACE
import com.pinterest.ktlint.core.ast.ElementType.VALUE_PARAMETER
import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl
import org.jetbrains.kotlin.psi.psiUtil.parents

/**
* Rule that checks if empty code blocks (`{ }`) are used and checks their formatting.
Expand All @@ -28,6 +34,9 @@ class EmptyBlock(configRules: List<RulesConfig>) : DiktatRule(
val configuration = EmptyBlockStyleConfiguration(
configRules.getRuleConfig(EMPTY_BLOCK_STRUCTURE_ERROR)?.configuration ?: emptyMap()
)
if (node.elementType == FILE) {
println(node.prettyPrint())
}
searchNode(node, configuration)
}

Expand All @@ -41,7 +50,7 @@ class EmptyBlock(configRules: List<RulesConfig>) : DiktatRule(

@Suppress("UnsafeCallOnNullableType", "TOO_LONG_FUNCTION")
private fun checkEmptyBlock(node: ASTNode, configuration: EmptyBlockStyleConfiguration) {
if (node.treeParent.isOverridden() || isAnonymousSamClass(node)) {
if (node.treeParent.isOverridden() || isAnonymousSamClass(node) || isLambdaUsedAsFunction(node)) {
return
}
if (node.isBlockEmpty()) {
Expand Down Expand Up @@ -82,18 +91,32 @@ class EmptyBlock(configRules: List<RulesConfig>) : DiktatRule(
}
}

@Suppress("UnsafeCallOnNullableType", "WRONG_WHITESPACE")
private fun isAnonymousSamClass(node: ASTNode) : Boolean =
@Suppress("UnsafeCallOnNullableType")
private fun isAnonymousSamClass(node: ASTNode): Boolean =
if (node.elementType == FUNCTION_LITERAL && node.hasParent(CALL_EXPRESSION)) {
// We are checking identifier because it is not class in AST
// , SAM conversions are indistinguishable from lambdas.
// We are checking identifier because it is not class in AST,
// SAM conversions are indistinguishable from lambdas.
// So we just verify that identifier is in PascalCase
val valueArgument = node.findParentNodeWithSpecificType(CALL_EXPRESSION)!!
valueArgument.findLeafWithSpecificType(IDENTIFIER)?.text?.isPascalCase() ?: false
} else {
false
}

private fun isLambdaUsedAsFunction(node: ASTNode): Boolean {
val parents = node.parents()
if (parents.any { it.elementType == CALL_EXPRESSION }) {
val callExpression = parents.find { it.elementType == CALL_EXPRESSION }!!
// excepting cases like list.map { }
return callExpression.treeParent.elementType != DOT_QUALIFIED_EXPRESSION
} else if (parents.any { it.elementType == LAMBDA_EXPRESSION }) {
val lambdaExpression = parents.find { it.elementType == LAMBDA_EXPRESSION }!!
// cases like A({}). Here Lambda expression is used as a value parameter.
return lambdaExpression.treeParent.elementType == VALUE_PARAMETER
}
return false
}

/**
* [RuleConfiguration] for empty blocks formatting
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,21 @@ class EmptyBlockWarnTest : LintTestBase(::EmptyBlock) {
rulesConfigList = rulesConfigListEmptyBlockExist
)
}

@Test
@Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)
fun `should not trigger on empty lambdas as a functions`() {
lintMethod(
"""
|fun foo(bar: () -> Unit = {})
|
|class Some {
| fun bar() {
| A({})
| }
|}
""".trimMargin(),
rulesConfigList = rulesConfigListEmptyBlockExist
)
}
}

0 comments on commit 727aff3

Please sign in to comment.