We are making custom lint for the purpose of applying them to the Android project.
The problematic part is the lint that requires the use of NamedArgument in the Composable function.
@Composable
fun MyComposable(
a: String,
b: Int,
onClick: () -> Unit = {},
) {}
@Composable
fun success1() {
MyComposable(
a = "success",
b = 1,
) {
}
}
I was thinking about how to determine if MyComposable is @Composable when calling MyComposable in the success1 function in the following cases:
class NamedArgumentDetector : Detector(), SourceCodeScanner {
override fun getApplicableUastTypes() = listOf(
UExpression::class.java,
)
override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
override fun visitExpression(node: UExpression) {
if (node !is KotlinUFunctionCallExpression || !node.isInvokedWithinComposable()) return
val firstMethodName = node.methodName?.first() ?: return
if (firstMethodName !in 'A'..'Z') return
val lastArgumentIndex = node.valueArguments.lastIndex
node.valueArguments.fastForEachIndexed { index, argument ->
if (index == lastArgumentIndex && argument is KotlinULambdaExpression) return
val expressionSourcePsi = argument.sourcePsi
val argumentParent = expressionSourcePsi?.node?.treeParent ?: return
val argumentFirstChildNode = argumentParent.firstChildNode
val argumentParentFirstChildNode = argumentParent.treeParent.firstChildNode
if (!(
argumentFirstChildNode.isValueArgumentName() ||
argumentParentFirstChildNode.isValueArgumentName()
)
) {
context.report(
issue = NamedArgumentIssue,
scope = expressionSourcePsi,
location = context.getLocation(expressionSourcePsi),
message = Explanation,
)
return
}
}
}
}
private fun ASTNode.isValueArgumentName() =
this.elementType == VALUE_ARGUMENT_NAME
}
Detector code. In the example above, we were able to check whether success1 invokes Composable, but I can't think of a way to check whether MyComposable called by success1 is a Composable function.
I would appreciate it if you let me know if there is a way to check.