Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Separating ComplexMethod rule into CyclomaticComplexMethod and Cognit…
…iveComplexMethod (#5442) * feature: add rule CognitiveComplexMethod * test: add test for CognitiveComplexMethod rule * move: ComplexMethod -> CyclomaticComplexMethod * fix: remove referencing ComplexMethod * fix: detekt correct * fix: set alias * config: deactivate default cognitive complex method rule * test: add positive and negative test cases * Update detekt-rules-complexity/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/complexity/CyclomaticComplexMethod.kt Co-authored-by: Brais Gabín <braisgabin@gmail.com> * fix: remove conflicting activeByDefault and sync Co-authored-by: Brais Gabín <braisgabin@gmail.com>
- Loading branch information
1 parent
7697efd
commit 7b632b2
Showing
9 changed files
with
135 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
...ty/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/complexity/CognitiveComplexMethod.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package io.gitlab.arturbosch.detekt.rules.complexity | ||
|
||
import io.github.detekt.metrics.CognitiveComplexity | ||
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.Metric | ||
import io.gitlab.arturbosch.detekt.api.Rule | ||
import io.gitlab.arturbosch.detekt.api.Severity | ||
import io.gitlab.arturbosch.detekt.api.ThresholdedCodeSmell | ||
import io.gitlab.arturbosch.detekt.api.config | ||
import io.gitlab.arturbosch.detekt.api.internal.Configuration | ||
import org.jetbrains.kotlin.psi.KtNamedFunction | ||
|
||
/** | ||
* Complex methods are hard to understand and read. It might not be obvious what side-effects a complex method has. | ||
* Prefer splitting up complex methods into smaller methods that are in turn easier to understand. | ||
* Smaller methods can also be named much clearer which leads to improved readability of the code. | ||
* | ||
* This rule measures and restricts the complexity of the method through the [Cognitive Complexity metric of Sonasource](https://www.sonarsource.com/docs/CognitiveComplexity.pdf). | ||
* Which improves McCabe's Cyclomatic Complexity ({@link CyclomaticComplexMethod}) considering the programmer's mental model. | ||
* | ||
* Similar to cyclomatic complexity, it is a mathematical model that increases +1 complexity for flow control statements, | ||
* but increases additional complexity when the statements are deeply nested. | ||
* | ||
* The statements that increase the complexity or the nesting level are as follows. | ||
* - __Complexity Increments__ - `if`, `when`, `for`, `while`, `do while`, `catch`, `labeled break`, `labeled continue`, `labeled return`, `recursion call`, `&&`, `||` | ||
* - __Nesting Level Increments__ - `if`, `when`, `for`, `while`, `do while`, `catch`, `nested function` | ||
* - __Additional Complexity Increments by Nesting Level__ - `if`, `when`, `for`, `while`, `do while`, `catch` | ||
*/ | ||
class CognitiveComplexMethod(config: Config = Config.empty) : Rule(config) { | ||
|
||
override val issue = Issue( | ||
"CognitiveComplexMethod", | ||
Severity.Maintainability, | ||
"Prefer splitting up complex methods into smaller, easier to understand methods.", | ||
Debt.TWENTY_MINS | ||
) | ||
|
||
@Configuration("Cognitive Complexity number for a method.") | ||
private val threshold: Int by config(defaultValue = 15) | ||
|
||
override fun visitNamedFunction(function: KtNamedFunction) { | ||
val complexity = CognitiveComplexity.calculate(function) | ||
|
||
if (complexity >= threshold) { | ||
report( | ||
ThresholdedCodeSmell( | ||
issue, | ||
Entity.atName(function), | ||
Metric("CC", complexity, threshold), | ||
"The function ${function.nameAsSafeName} appears to be too complex " + | ||
"based on Cognitive Complexity (complexity: $complexity). " + | ||
"Defined complexity threshold for methods is set to '$threshold'" | ||
) | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
...rc/test/kotlin/io/gitlab/arturbosch/detekt/rules/complexity/CognitiveComplexMethodSpec.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package io.gitlab.arturbosch.detekt.rules.complexity | ||
|
||
import io.gitlab.arturbosch.detekt.api.SourceLocation | ||
import io.gitlab.arturbosch.detekt.test.TestConfig | ||
import io.gitlab.arturbosch.detekt.test.assertThat | ||
import io.gitlab.arturbosch.detekt.test.compileAndLint | ||
import io.gitlab.arturbosch.detekt.test.isThresholded | ||
import org.junit.jupiter.api.Test | ||
|
||
class CognitiveComplexMethodSpec { | ||
|
||
private val testConfig = TestConfig("threshold" to "1") | ||
|
||
@Test | ||
fun `should report complex function`() { | ||
val code = """ | ||
fun sumOfPrimes(max: Int): Int { // total cognitive complexity is 7 | ||
var total = 0 | ||
next@ for (i in 1..max) { // +1 | ||
for (j in 2 until i) { // +1 +1 | ||
if (i % j == 0) { // +1 +2 | ||
continue@next // +1 | ||
} | ||
} | ||
println(i) | ||
total++ | ||
} | ||
return total | ||
} | ||
""".trimIndent() | ||
val findings = CognitiveComplexMethod(testConfig).compileAndLint(code) | ||
assertThat(findings).hasSize(1) | ||
assertThat(findings).hasStartSourceLocations(SourceLocation(1, 5)) | ||
assertThat(findings.first()).isThresholded().withValue(7) | ||
} | ||
|
||
@Test | ||
fun `should not report simple function`() { | ||
val code = """ | ||
fun add(a: Int, b: Int): Int { // total cognitive complexity is 0 | ||
return a + b | ||
} | ||
""".trimIndent() | ||
val findings = CognitiveComplexMethod(testConfig).compileAndLint(code) | ||
assertThat(findings).isEmpty() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters