Guide for writing a lint detector for a specific composable (Jetpack compose)

84 views
Skip to first unread message

colto...@protonmail.com

unread,
May 25, 2021, 2:56:42 PM5/25/21
to lint-dev
I have a simple use case where I have a `MyButton()` composable, and I want to prevent people from using Button from the material library. I know how to write a lint detector for a specific import, but an import lint detector places the error on the import statement line and not at the call site of the Button. Can anyone nudge me in the right direction?

digis...@gmail.com

unread,
May 25, 2021, 5:14:58 PM5/25/21
to lint-dev
Since composables are functions, you can override getApplicableMethodNames to find them at their call sites.

colto...@protonmail.com

unread,
May 27, 2021, 12:04:59 AM5/27/21
to lint-dev
I want to also make sure that I'm searching for the function name that comes from the material package.

Does this make sense or is it horribly wrong? (it works, I just want to make sure that theres no better way to check for package location)

```
override fun getApplicableMethodNames(): List<String>? = listOf("OutlinedTextField")

override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
val evaluator = context.evaluator
if (evaluator.getPackage(method).toString().contains("androidx.compose.material")) {
reportUsage(context, node)
}
}
```

Tor Norbye

unread,
May 28, 2021, 7:13:09 PM5/28/21
to lint-dev
Looking up by method name (in this case a constructor method) and then filtering by containing class is the right approach.
Instead of looking up the package itself, it's probably better (more efficient) to just take the qualified name of the class and check its prefix.
e.g.   if (method.containingClass()?.qualifiedName().startsWith("androidx.compose.material.") == true) { ... }

-- Tor

colto...@protonmail.com

unread,
May 28, 2021, 8:00:26 PM5/28/21
to lint-dev
That's a great point. Thank you.

This is what I ended up with. I wonder if the !! or ? is better to take on here, but I'll keep !! for now and test with this to see if anything goes horribly wrong. I suppose a method should always have a containing class, and therefore a qualified name... right? =)

```
if (method.containingClass!!.qualifiedName!!.startsWith("androidx.compose.material.")) {
reportUsage(context, node)
}
```

Tor Norbye

unread,
Jun 1, 2021, 12:12:22 PM6/1/21
to colto...@protonmail.com, lint-dev
Methods aren't guaranteed to have a surrounding class so probably safest to use the ?. operator...

public interface PsiJvmMember extends PsiMember, JvmMember, PsiJvmModifiersOwner {
    @Nullable
    PsiClass getContainingClass();
}

--
You received this message because you are subscribed to the Google Groups "lint-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lint-dev+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lint-dev/2e78a126-9013-40f7-99ef-4b8ba9155a6bn%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages