Skip to content

Commit

Permalink
New rule 5.2.4 for lambda length
Browse files Browse the repository at this point in the history
### What's done:
* Added rule logic
* Added new warning
* Added new test
  • Loading branch information
Cheshiriks committed Jan 18, 2021
1 parent d19fcd3 commit 4eacdd3
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -221,14 +221,14 @@ class BlockStructureBraces(private val configRules: List<RulesConfig>) : Rule("b
allMiddleSpace: List<ASTNode>,
node: ASTNode,
keyword: IElementType) {
allMiddleSpace.forEach { allMidSpace ->
if (checkBraceNode(allMidSpace, true)) {
allMiddleSpace.forEach { space ->
if (checkBraceNode(space, true)) {
BRACES_BLOCK_STRUCTURE_ERROR.warnAndFix(configRules, emitWarn, isFixMode, "incorrect new line after closing brace",
allMidSpace.startOffset, allMidSpace) {
if (allMidSpace.elementType != WHITE_SPACE) {
space.startOffset, space) {
if (space.elementType != WHITE_SPACE) {
node.addChild(PsiWhiteSpaceImpl(" "), node.findChildByType(keyword))
} else {
(allMidSpace as LeafPsiElement).replaceWithText(" ")
(space as LeafPsiElement).replaceWithText(" ")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ import org.cqfn.diktat.ruleset.utils.*

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType
import com.pinterest.ktlint.core.ast.isPartOfComment
import org.jetbrains.kotlin.com.intellij.lang.ASTNode

/**
* Rule 5.2.4 check lambda length without parameters
*/
class LambdaLengthRule(private val configRules: List<RulesConfig>) : Rule("lambda-length") {
private val configuration by lazy {
LambdaLengthConfiguration(
this.configRules.getRuleConfig(Warnings.TOO_MANY_LINES_IN_LAMBDA)?.configuration ?: emptyMap()
)
}
private var isFixMode: Boolean = false
private lateinit var emitWarn: EmitType

Expand All @@ -27,12 +31,6 @@ class LambdaLengthRule(private val configRules: List<RulesConfig>) : Rule("lambd
emitWarn = emit
isFixMode = autoCorrect

val configuration by lazy {
LambdaLengthConfiguration(
configRules.getRuleConfig(Warnings.TOO_MANY_LINES_IN_LAMBDA)?.configuration ?: emptyMap()
)
}

if (node.elementType == ElementType.LAMBDA_EXPRESSION) {
checkLambda(node, configuration)
}
Expand All @@ -42,15 +40,12 @@ class LambdaLengthRule(private val configRules: List<RulesConfig>) : Rule("lambd
val copyNode = node.clone() as ASTNode
val sizeLambda = countCodeLines(copyNode)
if (sizeLambda > configuration.maxLambdaLength) {
val lambdaNodeList = copyNode.findAllNodesWithCondition({it.elementType == ElementType.LAMBDA_EXPRESSION})
if (lambdaNodeList.size > 1) {
lambdaNodeList.forEach {
if (lambdaNodeList.indexOf(it) > 0) {
it.treeParent.removeChild(it)
}
copyNode.findAllNodesWithCondition({it.elementType == ElementType.LAMBDA_EXPRESSION}).forEachIndexed {index, node ->
if (index > 0) {
node.treeParent.removeChild(node)
}
}
val isIt: Boolean = copyNode.findAllNodesWithSpecificType(ElementType.REFERENCE_EXPRESSION).map {re -> re.text}.indexOf("it") != -1
val isIt: Boolean = copyNode.findAllNodesWithSpecificType(ElementType.REFERENCE_EXPRESSION).map {re -> re.text}.contains("it")
val parameters = node.findChildByType(ElementType.FUNCTION_LITERAL)?.findChildByType(ElementType.VALUE_PARAMETER_LIST)
if (parameters == null && isIt) {
Warnings.TOO_MANY_LINES_IN_LAMBDA.warn(configRules, emitWarn, isFixMode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,16 @@ class SmartCastRule(private val configRules: List<RulesConfig>) : Rule("smart-ca
*/
@Suppress("NestedBlockDepth", "TYPE_ALIAS")
private fun handleGroups(groups: Map<KtNameReferenceExpression, List<KtNameReferenceExpression>>) {
groups.keys.forEach {
val parentText = it.node.treeParent.text
groups.keys.forEach { key ->
val parentText = key.node.treeParent.text
if (parentText.contains(" is ")) {
groups.getValue(it).forEach { asCall ->
groups.getValue(key).forEach { asCall ->
if (asCall.node.hasParent(THEN)) {
raiseWarning(asCall.node)
}
}
} else if (parentText.contains(" !is ")) {
groups.getValue(it).forEach { asCall ->
groups.getValue(key).forEach { asCall ->
if (asCall.node.hasParent(ELSE)) {
raiseWarning(asCall.node)
}
Expand Down Expand Up @@ -234,12 +234,12 @@ class SmartCastRule(private val configRules: List<RulesConfig>) : Rule("smart-ca

val identifier = node.getFirstChildWithType(REFERENCE_EXPRESSION)?.text

node.getAllChildrenWithType(WHEN_ENTRY).forEach {
if (it.hasChildOfType(WHEN_CONDITION_IS_PATTERN) && identifier != null) {
val type = it.getFirstChildWithType(WHEN_CONDITION_IS_PATTERN)!!
node.getAllChildrenWithType(WHEN_ENTRY).forEach { node ->
if (node.hasChildOfType(WHEN_CONDITION_IS_PATTERN) && identifier != null) {
val type = node.getFirstChildWithType(WHEN_CONDITION_IS_PATTERN)!!
.getFirstChildWithType(TYPE_REFERENCE)?.text

val callExpr = it.findAllNodesWithSpecificType(BINARY_WITH_TYPE).firstOrNull()
val callExpr = node.findAllNodesWithSpecificType(BINARY_WITH_TYPE).firstOrNull()
val blocks = listOf(IsExpressions(identifier, type ?: ""))

callExpr?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,8 @@ private fun ASTNode.calculateLineNumber() = getRootNode()
}

/**
* Count number of lines in code block. Note: only *copy* of a node should be passed to this method, because the method changes the node.
*
* @return the number of lines in a block of code.
*/
fun countCodeLines(copyNode: ASTNode): Int {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,32 @@ class LambdaLengthWarnTest : LintTestBase(::LambdaLengthRule) {

@Test
@Tag(WarningNames.TOO_MANY_LINES_IN_LAMBDA)
fun `without "it"`() {
fun `nested lambda with implicit parameter`() {
lintMethod(
"""
|fun foo() {
| private val allTestsFromResources: List<String> by lazy {
| val fileUrl: URL? = javaClass.getResource("123")
| val resource = fileUrl
| ?.let { File(it.file) }
| }
| }
|}
""".trimMargin(),
rulesConfigList = rulesConfigList
)
}

@Test
@Tag(WarningNames.TOO_MANY_LINES_IN_LAMBDA)
fun `lambda doesn't expect parameters`() {
lintMethod(
"""
|fun foo() {
| private val allTestsFromResources: List<String> by lazy {
| val fileUrl: URL? = javaClass.getResource("123")
| list = listOf(1, 2, 3, 4, 5)
| .removeAt(1)
| }
|}
""".trimMargin(),
rulesConfigList = rulesConfigList
Expand Down

0 comments on commit 4eacdd3

Please sign in to comment.