mirror of
https://github.com/jlengrand/detekt.git
synced 2026-03-10 08:11:23 +00:00
Introduce NamedArguments rule (#3167)
* Introduce NamedArguments rule when function is invoked with more than default number of non-named parameters * Change the documentation to make the intent of default threshold clear * Add compliant and non-compliant code documentation. Add tests for constructor
This commit is contained in:
committed by
GitHub
parent
7364edc494
commit
b6d298a6ad
@@ -28,6 +28,7 @@ class ComplexityProvider : DefaultRuleSetProvider {
|
||||
ComplexCondition(config),
|
||||
LabeledExpression(config),
|
||||
ReplaceSafeCallChainWithRun(config),
|
||||
NamedArguments(config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package io.gitlab.arturbosch.detekt.rules.complexity
|
||||
|
||||
import io.gitlab.arturbosch.detekt.api.CodeSmell
|
||||
import io.gitlab.arturbosch.detekt.api.Config
|
||||
import io.gitlab.arturbosch.detekt.api.Debt
|
||||
import io.gitlab.arturbosch.detekt.api.Entity
|
||||
import io.gitlab.arturbosch.detekt.api.Issue
|
||||
import io.gitlab.arturbosch.detekt.api.Severity
|
||||
import io.gitlab.arturbosch.detekt.api.ThresholdRule
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
|
||||
/**
|
||||
* Reports function invocations which have more parameters than a certain threshold and are all not named.
|
||||
*
|
||||
* <noncompliant>
|
||||
* fun sum(a: Int, b: Int, c: Int, d: Int) {
|
||||
* }
|
||||
* sum(1, 2, 3, 4)
|
||||
* </noncompliant>
|
||||
*
|
||||
* <compliant>
|
||||
* fun sum(a: Int, b: Int, c: Int, d: Int) {
|
||||
* }
|
||||
* sum(a = 1, b = 2, c = 3, d = 4)
|
||||
* </compliant>
|
||||
*
|
||||
* @configuration threshold - number of parameters that triggers this inspection (default: `3`)
|
||||
*/
|
||||
class NamedArguments(
|
||||
config: Config = Config.empty,
|
||||
threshold: Int = DEFAULT_FUNCTION_THRESHOLD
|
||||
) : ThresholdRule(config, threshold) {
|
||||
|
||||
override val issue = Issue(
|
||||
"NamedArguments", Severity.Maintainability,
|
||||
"Function invocation with more than $threshold parameters must all be named",
|
||||
Debt.FIVE_MINS
|
||||
)
|
||||
|
||||
override fun visitCallExpression(expression: KtCallExpression) {
|
||||
val valueArguments = expression.valueArguments
|
||||
if (valueArguments.size > threshold && valueArguments.any { !it.isNamed() }) {
|
||||
report(CodeSmell(issue, Entity.from(expression), issue.description))
|
||||
} else {
|
||||
super.visitCallExpression(expression)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_FUNCTION_THRESHOLD = 3
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package io.gitlab.arturbosch.detekt.rules.complexity
|
||||
|
||||
import io.gitlab.arturbosch.detekt.test.compileAndLint
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.spekframework.spek2.Spek
|
||||
import org.spekframework.spek2.style.specification.describe
|
||||
|
||||
class NamedArgumentsSpec : Spek({
|
||||
|
||||
val defaultThreshold = 2
|
||||
val namedArguments by memoized { NamedArguments(threshold = defaultThreshold) }
|
||||
|
||||
describe("NameArguments rule") {
|
||||
|
||||
val errorMessage = "Function invocation with more than $defaultThreshold parameters must all be named"
|
||||
it("invocation with more than 2 parameters should throw error") {
|
||||
val code = """
|
||||
fun sum(a: Int, b:Int, c:Int) {
|
||||
println(a + b + c)
|
||||
}
|
||||
fun call() {
|
||||
sum(1, 2, 3)
|
||||
}
|
||||
"""
|
||||
val findings = namedArguments.compileAndLint(code)
|
||||
assertThat(findings).hasSize(1)
|
||||
assertThat(findings.first().message).isEqualTo(errorMessage)
|
||||
}
|
||||
|
||||
it("Function invocation with more than 2 parameters should not throw error if named") {
|
||||
val code = """
|
||||
fun sum(a: Int, b:Int, c:Int) {
|
||||
println(a + b + c)
|
||||
}
|
||||
fun call() {
|
||||
sum(a = 1, b = 2, c = 3)
|
||||
}
|
||||
"""
|
||||
val findings = namedArguments.compileAndLint(code)
|
||||
assertThat(findings).hasSize(0)
|
||||
}
|
||||
|
||||
it("invocation with more than 2 parameters should throw error if even one is not named") {
|
||||
val code = """
|
||||
fun sum(a: Int, b:Int, c:Int) {
|
||||
println(a + b + c)
|
||||
}
|
||||
fun call() {
|
||||
sum(1, b = 2, c = 3)
|
||||
}
|
||||
"""
|
||||
val findings = namedArguments.compileAndLint(code)
|
||||
assertThat(findings).hasSize(1)
|
||||
assertThat(findings.first().message).isEqualTo(errorMessage)
|
||||
}
|
||||
|
||||
it("invocation with less than 3 parameters should not throw error") {
|
||||
val code = """
|
||||
fun sum(a: Int, b:Int) {
|
||||
println(a + b)
|
||||
}
|
||||
fun call() {
|
||||
sum(1, 2)
|
||||
}
|
||||
"""
|
||||
val findings = namedArguments.compileAndLint(code)
|
||||
assertThat(findings).hasSize(0)
|
||||
}
|
||||
|
||||
it("invocation with less than 3 named parameters should not throw error") {
|
||||
val code = """
|
||||
fun sum(a: Int, b:Int) {
|
||||
println(a + b)
|
||||
}
|
||||
fun call() {
|
||||
sum(a = 1, b = 2)
|
||||
}
|
||||
"""
|
||||
val findings = namedArguments.compileAndLint(code)
|
||||
assertThat(findings).hasSize(0)
|
||||
}
|
||||
|
||||
it("constructor invocation with more than 3 non-named parameters should throw error") {
|
||||
val code = """
|
||||
class C(val a: Int, val b:Int, val c:Int)
|
||||
|
||||
val obj = C(1, 2, 3)
|
||||
"""
|
||||
val findings = namedArguments.compileAndLint(code)
|
||||
assertThat(findings).hasSize(1)
|
||||
assertThat(findings.first().message).isEqualTo(errorMessage)
|
||||
}
|
||||
|
||||
it("constructor invocation with more than 3 named parameters should not throw error") {
|
||||
val code = """
|
||||
class C(val a: Int, val b:Int, val c:Int)
|
||||
|
||||
val obj = C(a = 1, b = 2, c= 3)
|
||||
"""
|
||||
val findings = namedArguments.compileAndLint(code)
|
||||
assertThat(findings).hasSize(0)
|
||||
}
|
||||
|
||||
it("constructor invocation with less than 3 non-named parameters should not throw error") {
|
||||
val code = """
|
||||
class C(val a: Int, val b:Int)
|
||||
|
||||
val obj = C(1, 2)
|
||||
"""
|
||||
val findings = namedArguments.compileAndLint(code)
|
||||
assertThat(findings).hasSize(0)
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user