Skip to content

Commit

Permalink
Ignore lambdas that dont return Unit in ContentSlotReused
Browse files Browse the repository at this point in the history
  • Loading branch information
mrmans0n committed Nov 19, 2024
1 parent fd1618d commit 5808d61
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ fun KtCallableDeclaration.contentSlots(
treatAsComposableLambdaTypes: Set<String>,
): Sequence<KtParameter> = valueParameters.asSequence()
.filter { parameter ->
parameter.typeReference?.isComposableLambda(treatAsLambdaTypes, treatAsComposableLambdaTypes) == true
parameter.typeReference?.isComposableUiEmitterLambda(treatAsLambdaTypes, treatAsComposableLambdaTypes) == true
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,37 @@ fun KtTypeReference.isComposableLambda(
else -> false
}

fun KtTypeReference.isComposableUiEmitterLambda(
treatAsLambdaTypes: Set<String> = emptySet(),
treatAsComposableLambdaTypes: Set<String> = emptySet(),
): Boolean = when (val element = typeElement) {
null -> false
is KtFunctionType -> isComposable && element.returnsUnit
is KtNullableType -> (isComposable && element.isLambda(treatAsLambdaTypes)) ||
// Only possibility for this to not have a @Composable annotation is for it to be a KtUserType
(element.innerType as? KtUserType)?.referencedName in treatAsComposableLambdaTypes

is KtUserType -> (isComposable && element.referencedName in treatAsLambdaTypes) ||
element.referencedName in treatAsComposableLambdaTypes

else -> false
}

val KtTypeElement.returnsUnit: Boolean
get() = when (this) {
is KtFunctionType -> returnTypeReference?.text == "Unit"
is KtNullableType -> innerType?.returnsUnit == true
else -> false
}

val KtTypeReference.returnsUnit: Boolean
get() = when (val element = typeElement) {
null -> false
is KtFunctionType -> element.returnsUnit
is KtNullableType -> element.innerType?.returnsUnit == true
else -> false
}

fun KtFile.lambdaTypes(config: ComposeKtConfig): Set<String> = buildSet {
// Add the provided types
addAll(config.getSet("treatAsLambda", emptySet()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,24 @@ class ContentSlotReusedCheckTest {
val errors = rule.lint(code)
assertThat(errors).isEmpty()
}

@Test
fun `passes when content does not return Unit`() {
@Language("kotlin")
val code =
"""
@Composable
fun A(text: String, content: @Composable () -> String) {
if (x) content() else content()
}
@Composable
fun B(text: String, content: @Composable (() -> String)?) {
if (x) content() else content()
}
""".trimIndent()

val errors = rule.lint(code)
assertThat(errors).isEmpty()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,23 @@ class ContentSlotReusedCheckTest {
.withEditorConfigOverride(treatAsComposableLambda to "Potato", treatAsLambda to "Plum")
.hasNoLintViolations()
}

@Test
fun `passes when content does not return Unit`() {
@Language("kotlin")
val code =
"""
@Composable
fun A(text: String, content: @Composable () -> String) {
if (x) content() else content()
}
@Composable
fun B(text: String, content: @Composable (() -> String)?) {
if (x) content() else content()
}
""".trimIndent()

ruleAssertThat(code).hasNoLintViolations()
}
}

0 comments on commit 5808d61

Please sign in to comment.