in rules/common/src/main/kotlin/com/twitter/compose/rules/ComposeModifierReused.kt [23:68]
override fun visitComposable(function: KtFunction, autoCorrect: Boolean, emitter: Emitter) {
if (!function.emitsContent) return
val composableBlockExpression = function.bodyBlockExpression ?: return
val modifier = function.modifierParameter ?: return
val initialName = modifier.name ?: return
// Try to get all possible names by iterating on possible name reassignments until it's stable
val modifierNames = composableBlockExpression.obtainAllModifierNames(initialName)
// Find all composable-looking CALL_EXPRESSIONs that are using any of these modifier names
composableBlockExpression.findChildrenByClass<KtCallExpression>()
.filter { it.calleeExpression?.text?.first()?.isUpperCase() == true }
.filter { it.isUsingModifiers(modifierNames) }
.map { callExpression ->
// To get an accurate count (and respecting if/when/whatever different branches)
// we'll need to traverse upwards to [function] from each one of these usages
// to see the real amount of usages.
buildSet<KtCallExpression> {
var current: PsiElement = callExpression
while (current != composableBlockExpression) {
// If the current element is a CALL_EXPRESSION and using modifiers, log it
if (current is KtCallExpression && current.isUsingModifiers(modifierNames)) {
add(current)
}
// If any of the siblings also use any of these, we also log them.
// This is for the special case where only sibling composables reuse modifiers
addAll(
current.siblings()
.filterIsInstance<KtCallExpression>()
.filter { it.isUsingModifiers(modifierNames) },
)
current = current.parent
}
}
}
// Any set with more than 1 item is interesting to us: means there is a rule violation
.filter { it.size > 1 }
// At this point we have all the grouping of violations, so we just need to extract all individual
// items from them as we are no longer interested in the groupings, but their individual elements
.flatten()
// We don't want to double report
.distinct()
.forEach { callExpression ->
emitter.report(callExpression, ModifierShouldBeUsedOnceOnly, false)
}
}