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

org.cqfn.diktat.ruleset.rules.chapter4.ImmutableValNoVarRule.kt Maven / Gradle / Ivy

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

import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.Warnings.SAY_NO_TO_VAR
import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.search.findAllVariablesWithAssignments
import org.cqfn.diktat.ruleset.utils.search.findAllVariablesWithUsages

import com.pinterest.ktlint.core.ast.ElementType
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtLoopExpression
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType

/**
 * Variables with `val` modifier - are immutable (read-only).
 * Usage of such variables instead of `var` variables increases robustness and readability of code,
 * because `var` variables can be reassigned several times in the business logic. Of course, in some scenarios with loops or accumulators only `var`s can be used and are allowed.
 * FixMe: here we should also raise warnings for a reassignment of a var (if var has no assignments except in declaration - it can be final)
 */
class ImmutableValNoVarRule(configRules: List) : DiktatRule(
    NAME_ID,
    configRules,
    listOf(SAY_NO_TO_VAR)
) {
    override fun logic(node: ASTNode) {
        if (node.elementType == ElementType.FILE) {
            // we will raise warning for cases when var property has no assignments
            val varNoAssignments = node
                .findAllVariablesWithAssignments { it.name != null && it.isVar }
                .filter { it.value.isEmpty() }

            varNoAssignments.forEach { (_, _) ->
                // FixMe: raise another warning and fix the code (change to val) for variables without assignment
            }

            // we can force to be immutable only variables that are from local context (not from class and not from file-level)
            val usages = node
                .findAllVariablesWithUsages { it.isLocal && it.name != null && it.parent is KtBlockExpression && it.isVar }
                .filter { !varNoAssignments.containsKey(it.key) }

            usages.forEach { (property, usages) ->
                val usedInAccumulators = usages.any {
                    it.getParentOfType(true) != null ||
                            it.getParentOfType(true) != null
                }

                if (!usedInAccumulators) {
                    SAY_NO_TO_VAR.warn(configRules, emitWarn, isFixMode, property.text, property.node.startOffset, property.node)
                }
            }

            return
        }
    }
    companion object {
        const val NAME_ID = "no-var-rule"
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy