I'm trying to write a lint check, that visits call expressions, and report on some violation based on a generic type.
To make it more clear, let's say I have this code:
object Foo {
inline fun <reified T> bar() = T::class.java
}
And let's say that I want to write a lint check that complains when I call the bar
method with Int
as the generic type, but accept everything else.
So, with the following code, the second call to bar should trigger a warning:
object Whatever {
fun someMethod() {
val stringClass = Foo.bar<String>() // Should not complain
val intClass = Foo.bar<Int>() // Should raise a warning
}
}
How would one implement that? This is of course not the real use case, and what I'm really trying to do is have a proper detection of bar<Int>
.
So far, this is what I have:
class MyDetector : Detector(), SourceCodeScanner {
companion object Issues {
val ISSUE = Issue.create(
id = "IntBarTest",
briefDescription = "You used bar with an Int type!",
explanation = "Explanation",
category = Category.CORRECTNESS,
severity = FATAL,
implementation = Implementation(MyDetector::class.java, Scope.JAVA_FILE_SCOPE)
)
}
override fun getApplicableUastTypes() = listOf(UCallExpression::class.java)
override fun createUastHandler(context: JavaContext): UElementHandler {
return GenericTypeHandler(context)
}
inner class GenericTypeHandler(val context: JavaContext) : UElementHandler() {
override fun visitCallExpression(node: UCallExpression) {
if (isCallExpressionAnIntBar(node)) {
context.report(ISSUE,
context.getNameLocation(node),
"Oh no, I should not use bar<Int>")
}
}
private fun isCallExpressionAnIntBar(node: UCallExpression): Boolean {
return if ("bar".equals(node.methodName) ||
"Foo" == (node.receiverType as? PsiClassReferenceType)?.resolve()?.qualifiedName) {
// We know it's the method we are looking for but now we must identify the generic
TODO("Identify the generic")
} else {
false
}
}
}
}
As you can see, there is a big TODO :-P