From 6434c2ab967ff352983d1ec87ce7b844b7288384 Mon Sep 17 00:00:00 2001 From: Denis Kumar Date: Tue, 6 Oct 2020 16:02:05 +0300 Subject: [PATCH] Rule 5.2.2 parameters size (#359) * Rule 5.2.2 parameters size ### What's done: Implemented rule Added tests and info into documentations --- diktat-analysis.yml | 7 ++- .../src/main/kotlin/generated/WarningNames.kt | 2 + .../cqfn/diktat/ruleset/constants/Warnings.kt | 3 +- .../ruleset/rules/DiktatRuleSetProvider.kt | 1 + .../ruleset/rules/FunctionArgumentsSize.kt | 49 ++++++++++++++++++ .../main/resources/diktat-analysis-huawei.yml | 7 ++- .../src/main/resources/diktat-analysis.yml | 5 ++ .../chapter5/FunctionArgumentsSizeWarnTest.kt | 51 +++++++++++++++++++ info/available-rules.md | 1 + 9 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/FunctionArgumentsSize.kt create mode 100644 diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/FunctionArgumentsSizeWarnTest.kt diff --git a/diktat-analysis.yml b/diktat-analysis.yml index 7fefa45b51..30a90735da 100644 --- a/diktat-analysis.yml +++ b/diktat-analysis.yml @@ -290,4 +290,9 @@ enabled: true configuration: maxFunctionLength: '30' # max length of function - isIncludeHeader: 'false' # count function's header \ No newline at end of file + isIncludeHeader: 'false' # count function's header +# Checks that function doesn't contains too many parameters +- name: TOO_MANY_PARAMETERS + enabled: true + configuration: + maxParameterListSize: '5' # max parameters size \ No newline at end of file diff --git a/diktat-rules/src/main/kotlin/generated/WarningNames.kt b/diktat-rules/src/main/kotlin/generated/WarningNames.kt index bc245c3845..917d2b32a6 100644 --- a/diktat-rules/src/main/kotlin/generated/WarningNames.kt +++ b/diktat-rules/src/main/kotlin/generated/WarningNames.kt @@ -171,4 +171,6 @@ object WarningNames { const val FLOAT_IN_ACCURATE_CALCULATIONS: String = "FLOAT_IN_ACCURATE_CALCULATIONS" const val TOO_LONG_FUNCTION: String = "TOO_LONG_FUNCTION" + + const val TOO_MANY_PARAMETERS: String = "TOO_MANY_PARAMETERS" } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt index a105b3b009..83f534dc1c 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode * This class represent individual inspections of diktat code style. * A [Warnings] entry contains rule name, warning message and is used in code check. */ -@Suppress("ForbiddenComment", "MagicNumber") +@Suppress("ForbiddenComment", "MagicNumber", "TOO_MANY_PARAMETERS") enum class Warnings(private val canBeAutoCorrected: Boolean, private val warn: String) : Rule { // ======== chapter 1 ======== PACKAGE_NAME_MISSING(true, "no package name declared in a file"), @@ -109,6 +109,7 @@ enum class Warnings(private val canBeAutoCorrected: Boolean, private val warn: S // ======== chapter 5 ======== TOO_LONG_FUNCTION(false, "function is too long: split it or make more primitive"), + TOO_MANY_PARAMETERS(false, "function has too many parameters"), ; /** diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt index f1ba4ca42e..3b7fb8c3a2 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt @@ -57,6 +57,7 @@ class DiktatRuleSetProvider(private val diktatConfigFile: String = "diktat-analy ::LineLength, ::TypeAliasRule, ::FunctionLength, + ::FunctionArgumentsSize, ::BlankLinesRule, ::NullableTypeRule, ::WhiteSpaceRule, diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/FunctionArgumentsSize.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/FunctionArgumentsSize.kt new file mode 100644 index 0000000000..8011e67091 --- /dev/null +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/FunctionArgumentsSize.kt @@ -0,0 +1,49 @@ +package org.cqfn.diktat.ruleset.rules + +import com.pinterest.ktlint.core.Rule +import com.pinterest.ktlint.core.ast.ElementType +import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER +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.TOO_MANY_PARAMETERS +import org.jetbrains.kotlin.com.intellij.lang.ASTNode +import org.jetbrains.kotlin.psi.KtFunction + +class FunctionArgumentsSize(private val configRules: List) : Rule("argument-size") { + + companion object { + const val maxDefaultParameterSize = 5L + } + + private val configuration: FunctionArgumentsSizeConfiguration by lazy { + FunctionArgumentsSizeConfiguration(configRules.getRuleConfig(TOO_MANY_PARAMETERS)?.configuration ?: mapOf()) + } + + private lateinit var emitWarn: ((offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) + private var isFixMode: Boolean = false + + override fun visit(node: ASTNode, + autoCorrect: Boolean, + emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) { + emitWarn = emit + isFixMode = autoCorrect + + if (node.elementType == ElementType.FUN) { + checkFun(node, configuration.maxParameterSize) + } + } + + @Suppress("UnsafeCallOnNullableType") + private fun checkFun(node: ASTNode, maxParameterSize: Long) { + val parameterListSize = (node.psi as KtFunction).valueParameters.size + if (parameterListSize > maxParameterSize){ + TOO_MANY_PARAMETERS.warn(configRules, emitWarn, isFixMode, + "${node.findChildByType(IDENTIFIER)!!.text} has $parameterListSize, but allowed $maxParameterSize", node.startOffset, node) + } + } + + class FunctionArgumentsSizeConfiguration(config: Map) : RuleConfiguration(config) { + val maxParameterSize = config["maxParameterListSize"]?.toLongOrNull()?: maxDefaultParameterSize + } +} diff --git a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml index c880bf2df8..9781739ba9 100644 --- a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml +++ b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml @@ -289,4 +289,9 @@ enabled: true configuration: maxFunctionLength: '30' # max length of function - isIncludeHeader: 'false' # count function's header \ No newline at end of file + isIncludeHeader: 'false' # count function's header +# Checks that function doesn't contains too many parameters +- name: TOO_MANY_PARAMETERS + enabled: true + configuration: + maxParameterListSize: '5' # max parameters size \ No newline at end of file diff --git a/diktat-rules/src/main/resources/diktat-analysis.yml b/diktat-rules/src/main/resources/diktat-analysis.yml index 886599dcd6..691de2706a 100644 --- a/diktat-rules/src/main/resources/diktat-analysis.yml +++ b/diktat-rules/src/main/resources/diktat-analysis.yml @@ -293,3 +293,8 @@ configuration: maxFunctionLength: '30' # max length of function isIncludeHeader: 'false' # count function's header +# Checks that function doesn't contains too many parameters +- name: TOO_MANY_PARAMETERS + enabled: true + configuration: + maxParameterListSize: '5' # max parameters size diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/FunctionArgumentsSizeWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/FunctionArgumentsSizeWarnTest.kt new file mode 100644 index 0000000000..a89f7fae90 --- /dev/null +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/FunctionArgumentsSizeWarnTest.kt @@ -0,0 +1,51 @@ +package org.cqfn.diktat.ruleset.chapter5 + +import com.pinterest.ktlint.core.LintError +import generated.WarningNames +import org.cqfn.diktat.common.config.rules.RulesConfig +import org.cqfn.diktat.ruleset.constants.Warnings.TOO_MANY_PARAMETERS +import org.cqfn.diktat.ruleset.rules.DIKTAT_RULE_SET_ID +import org.cqfn.diktat.ruleset.rules.FunctionArgumentsSize +import org.cqfn.diktat.util.LintTestBase +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test + +class FunctionArgumentsSizeWarnTest: LintTestBase(::FunctionArgumentsSize) { + + private val ruleId = "$DIKTAT_RULE_SET_ID:argument-size" + + private val rulesConfigList: List = listOf( + RulesConfig(TOO_MANY_PARAMETERS.name, true, + mapOf("maxParameterListSize" to "1")) + ) + + @Test + @Tag(WarningNames.TOO_MANY_PARAMETERS) + fun `check simple function`() { + lintMethod( + """ + |fun foo(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) {} + |fun foo(a: Int, b: Int, c: Int, d: Int, e: Int, myLambda: () -> Unit) {} + |fun foo(a: Int, b: Int, c: Int, d: Int, myLambda: () -> Unit) {} + |fun foo(a: Int, b: Int, c: Int, d: Int, e: Int, myLambda: () -> Unit) = 10 + |abstract fun foo(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) + """.trimMargin(), + LintError(1, 1, ruleId, "${TOO_MANY_PARAMETERS.warnText()} foo has 6, but allowed 5", false), + LintError(2, 1, ruleId, "${TOO_MANY_PARAMETERS.warnText()} foo has 6, but allowed 5", false), + LintError(4, 1, ruleId, "${TOO_MANY_PARAMETERS.warnText()} foo has 6, but allowed 5", false), + LintError(5, 1, ruleId, "${TOO_MANY_PARAMETERS.warnText()} foo has 6, but allowed 5", false) + ) + } + + @Test + @Tag(WarningNames.TOO_MANY_PARAMETERS) + fun `check function with config`() { + lintMethod( + """ + |fun foo(a: Int, b: Int) {} + """.trimMargin(), + LintError(1, 1, ruleId, "${TOO_MANY_PARAMETERS.warnText()} foo has 2, but allowed 1", false), + rulesConfigList = rulesConfigList + ) + } +} diff --git a/info/available-rules.md b/info/available-rules.md index f9fa1e1ce7..3e8b8dad28 100644 --- a/info/available-rules.md +++ b/info/available-rules.md @@ -84,3 +84,4 @@ | 4 | 4.2.2 | TYPE_ALIAS | Check: if type reference of property is longer than expected | yes | typeReferenceLength | -| | 4 | 4.3.2 | GENERIC_VARIABLE_WRONG_DECLARATION | Check: warns if variables of generic types don't have explicit type declaration
Fix: fixes only variables that have generic declaration on both sides | yes | - | + | | 5 | 5.1.1 | TOO_LONG_FUNCTION | Check: if length of function is too long | no | maxFunctionLength isIncludeHeader| +| 5 | 5.2.2 | TOO_MANY_PARAMETERS | Check: if function contains more parameters than allowed | no | maxParameterListSize |