LongMethod: disregard params in method definition (#2806)

* failing tests for #2804 LongMethod with params

* fix test

* skipTrees for KtParameterList for linesOfCode

* use test snippets that compile

* [ci ckip] use fun body for LongMethod
- revert changes in LinesOfCode.kt
- still need to update nested methods

* remove unused import

* add functionToBodyLinesCache to track fun body length

* remove spaces from test asserts
This commit is contained in:
Niraj Palecha
2020-06-22 21:07:32 +05:30
committed by GitHub
parent 049e6415d4
commit e0407049e1
2 changed files with 118 additions and 4 deletions

View File

@@ -37,15 +37,23 @@ class LongMethod(
Debt.TWENTY_MINS)
private val functionToLinesCache = HashMap<KtNamedFunction, Int>()
private val functionToBodyLinesCache = HashMap<KtNamedFunction, Int>()
private val nestedFunctionTracking = IdentityHashMap<KtNamedFunction, HashSet<KtNamedFunction>>()
override fun preVisit(root: KtFile) {
functionToLinesCache.clear()
functionToBodyLinesCache.clear()
nestedFunctionTracking.clear()
}
override fun postVisit(root: KtFile) {
for ((function, lines) in functionToLinesCache) {
val functionToLines = HashMap<KtNamedFunction, Int>()
functionToLinesCache.map { (function, lines) ->
val isNested = function.getStrictParentOfType<KtNamedFunction>() != null
if (isNested) functionToLines[function] = functionToBodyLinesCache[function] ?: 0
else functionToLines[function] = lines
}
for ((function, lines) in functionToLines) {
if (lines >= threshold) {
report(
ThresholdedCodeSmell(
@@ -61,10 +69,12 @@ class LongMethod(
}
override fun visitNamedFunction(function: KtNamedFunction) {
val lines = function.linesOfCode()
val parentMethods = function.getStrictParentOfType<KtNamedFunction>()
val bodyEntity = function.bodyBlockExpression ?: function.bodyExpression
val lines = (if (parentMethods != null) function else bodyEntity)?.linesOfCode() ?: 0
functionToLinesCache[function] = lines
function.getStrictParentOfType<KtNamedFunction>()
?.let { nestedFunctionTracking.getOrPut(it) { HashSet() }.add(function) }
functionToBodyLinesCache[function] = bodyEntity?.linesOfCode() ?: 0
parentMethods?.let { nestedFunctionTracking.getOrPut(it) { HashSet() }.add(function) }
super.visitNamedFunction(function)
findAllNestedFunctions(function)
.fold(0) { acc, next -> acc + (functionToLinesCache[next] ?: 0) }

View File

@@ -1,5 +1,6 @@
package io.gitlab.arturbosch.detekt.rules.complexity
import io.gitlab.arturbosch.detekt.api.ThresholdedCodeSmell
import io.gitlab.arturbosch.detekt.test.assertThat
import io.gitlab.arturbosch.detekt.test.compileAndLint
import org.spekframework.spek2.Spek
@@ -44,5 +45,108 @@ class LongMethodSpec : Spek({
assertThat(subject.compileAndLint(code)).isEmpty()
}
it("should not find too long method with params on newlines") {
val code = """
fun methodWithParams(
param1: String
) { // 4 lines
println()
println()
}
"""
assertThat(subject.compileAndLint(code)).isEmpty()
}
it("should find too long method with params on newlines") {
val code = """
fun longMethodWithParams(
param1: String
) { // 5 lines
println()
println()
println()
}
"""
val findings = subject.compileAndLint(code)
assertThat(findings).hasSize(1)
assertThat(findings[0] as ThresholdedCodeSmell).hasValue(5)
}
it("should find long method with method call with params on separate lines") {
val code = """
fun longMethod(
x1: Int,
x2: Int,
y1: Int,
y2: Int
) { // 8 lines
listOf(
x1,
y1,
x2,
y2
)
}
"""
val findings = subject.compileAndLint(code)
assertThat(findings).hasSize(1)
assertThat(findings[0] as ThresholdedCodeSmell).hasValue(8)
}
it("should find two long methods with params on separate lines") {
val code = """
fun longMethod(
param1: String
) { // 5 lines
println()
println()
println()
fun nestedLongMethod(
param1: String
) { // 5 lines
println()
println()
println()
}
}
"""
val findings = subject.compileAndLint(code)
assertThat(findings).hasSize(2)
assertThat(findings).hasTextLocations("longMethod", "nestedLongMethod")
}
it("should find nested long methods with params on separate lines") {
val code = """
fun longMethod(
param1: String
) { // 4 lines
println()
println()
fun nestedLongMethod(
param1: String
) { // 5 lines
println()
println()
println()
}
}
"""
val findings = subject.compileAndLint(code)
assertThat(findings).hasSize(1)
assertThat(findings).hasTextLocations("nestedLongMethod")
assertThat(findings[0] as ThresholdedCodeSmell).hasValue(5)
}
}
})