Can't filter the functions based on annotation #6903
-
Hi, I am trying to filter out functions based on a Composable annotation. I'm using a LongMethod rule as a base, but instead the custom rule, just like LongMethod, picks up all the functions, not just the Composable ones. Any help? Here's the rule code: import io.github.detekt.metrics.linesOfCode
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 org.jetbrains.kotlin.com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import java.util.IdentityHashMap
class ComposableTooLong(config: Config) : Rule(config) {
companion object {
const val ISSUE_DESCRIPTION = "This rule reports the Composable function that is too long"
}
private val maxFunctionLength: Int by config(defaultValue = 10)
override val issue = Issue(javaClass.simpleName, Severity.Minor, ISSUE_DESCRIPTION, 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) {
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 > maxFunctionLength && isComposable(function)) {
report(
ThresholdedCodeSmell(
issue = issue,
entity = Entity.atName(function),
metric = Metric(
type = lines.toString(),
value = maxFunctionLength,
threshold = maxFunctionLength
),
message = "The function ${function.nameAsSafeName} is too long ($lines). " +
"The maximum length is $maxFunctionLength."
)
)
}
}
}
private fun isComposable(function: KtNamedFunction): Boolean {
function.annotationEntries.forEach {
if (it.text == "@Composable") {
return true
}
}
return false
}
override fun visitNamedFunction(function: KtNamedFunction) {
if (isComposable(function)) {
val parentMethods = function.getStrictParentOfType<KtNamedFunction>()
val bodyEntity = function.bodyBlockExpression ?: function.bodyExpression
val lines = (if (parentMethods != null) function else bodyEntity)?.linesOfCode() ?: 0
functionToLinesCache[function] = lines
functionToBodyLinesCache[function] = bodyEntity?.linesOfCode() ?: 0
parentMethods?.let { nestedFunctionTracking.getOrPut(it) { HashSet() }.add(function) }
super.visitNamedFunction(function)
PsiTreeUtil.findChildrenOfType(function, KtNamedFunction::class.java)
.fold(0) { acc, next -> acc + (functionToLinesCache[next] ?: 0) }
.takeIf { it > 0 }
?.let { functionToLinesCache[function] = lines - it }
} else {
return
}
}
} Edited by @BraisGabin: fix code format |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 4 replies
-
Something similar is made by: https://github.com/detekt/detekt/blob/86f4de2773c4a1e6664b8afb5544f2f1a3003495/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/suppressors/AnnotationSuppressor.kt But nearly all the magic is done here: https://github.com/detekt/detekt/blob/e93a9a052a0013739b816bc79f856a576e8bbcc9/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/AnnotationExcluder.kt Probably that should help you :) |
Beta Was this translation helpful? Give feedback.
Something similar is made by: https://github.com/detekt/detekt/blob/86f4de2773c4a1e6664b8afb5544f2f1a3003495/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/suppressors/AnnotationSuppressor.kt
But nearly all the magic is done here: https://github.com/detekt/detekt/blob/e93a9a052a0013739b816bc79f856a576e8bbcc9/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/AnnotationExcluder.kt
Probably that should help you :)