All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cqfn.diktat.ruleset.rules.chapter5.NestedFunctionBlock.kt Maven / Gradle / Ivy

There is a newer version: 1.2.5
Show newest version
package org.cqfn.diktat.ruleset.rules.chapter5

import org.cqfn.diktat.common.config.rules.RuleConfiguration
import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.common.config.rules.getRuleConfig
import org.cqfn.diktat.ruleset.constants.Warnings.NESTED_BLOCK
import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.findAllDescendantsWithSpecificType
import org.cqfn.diktat.ruleset.utils.hasChildOfType

import com.pinterest.ktlint.core.ast.ElementType.CLASS
import com.pinterest.ktlint.core.ast.ElementType.FUN
import com.pinterest.ktlint.core.ast.ElementType.FUNCTION_LITERAL
import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER
import com.pinterest.ktlint.core.ast.ElementType.LBRACE
import com.pinterest.ktlint.core.ast.ElementType.OBJECT_DECLARATION
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.psi.psiUtil.parents

/**
 * Rule 5.1.2 Nested blokcs
 */
class NestedFunctionBlock(configRules: List) : DiktatRule(
    NAME_ID,
    configRules,
    listOf(NESTED_BLOCK)
) {
    private val configuration: NestedBlockConfiguration by lazy {
        NestedBlockConfiguration(configRules.getRuleConfig(NESTED_BLOCK)?.configuration ?: emptyMap())
    }

    override fun logic(node: ASTNode) {
        if (node.elementType in nullificationType) {
            countNestedBlocks(node, configuration.maxNestedBlockQuantity)
        }
    }

    private fun countNestedBlocks(node: ASTNode, maxNestedBlockCount: Long) {
        node.findAllDescendantsWithSpecificType(LBRACE)
            .reversed()
            .forEach { lbraceNode ->
                val blockParent = lbraceNode
                    .parents()
                    .takeWhile { it != node }
                    .takeIf { parentList -> parentList.map { it.elementType }.none { it in nullificationType } }
                    ?.count { it.hasChildOfType(LBRACE) }
                    ?: return
                if (blockParent > maxNestedBlockCount) {
                    NESTED_BLOCK.warn(configRules, emitWarn, isFixMode, node.findChildByType(IDENTIFIER)?.text ?: node.text,
                        node.startOffset, node)
                    return
                }
            }
    }

    /**
     * [RuleConfiguration] for analyzing nested code blocks
     */
    class NestedBlockConfiguration(config: Map) : RuleConfiguration(config) {
        /**
         * Maximum number of allowed levels of nested blocks
         */
        val maxNestedBlockQuantity = config["maxNestedBlockQuantity"]?.toLong() ?: MAX_NESTED_BLOCK_COUNT
    }

    companion object {
        private const val MAX_NESTED_BLOCK_COUNT = 4L
        const val NAME_ID = "nested-block"

        /**
         * Nodes of these types reset counter of nested blocks
         */
        private val nullificationType = listOf(CLASS, FUN, OBJECT_DECLARATION, FUNCTION_LITERAL)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy