I’m creating a Detekt rule which suggests replacing map.getOrDefault(key, defaultExpression) with map.getOrElse(key) { defaultExpression } but I’m having difficulty checking the type of the receiver since I only want this rule to apply when `getOrDefault(key, defaultExpression) is called on an instance of a map.
This is the new rule:
import io.gitlab.arturbosch.detekt.api.Debt.Companion.FIVE_MINS
import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity.Warning
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
class GetOrDefaultShouldBeReplacedWithGetOrElse : Rule() {
override val defaultRuleIdAliases = setOf("USE_GET_OR_ELSE_INSTEAD_OF_GET_OR_DEFAULT")
override val issue: Issue = Issue(
id = javaClass.simpleName,
severity = Warning,
description = "replace map.getOrDefault(key, defaultValue) with map.getOrElse(key) { defaultValue }",
debt = FIVE_MINS
)
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
super.visitDotQualifiedExpression(expression)
val receiver = expression.receiverExpression as? KtReferenceExpression ?: return
val references = receiver.references
// Boo! references is an empty array!
val type = references?.find { it is KtSimpleNameExpression }?.resolve() ?: return
// TODO: Check if the type is a subtype of Map
}
}
Here is my test for context:
@Test
fun `usage of getOrDefault is flagged`() {
val findings = GetOrDefaultShouldBeReplacedWithGetOrElse().lint(
"""
fun usage() {
val map = mapOf("Dan" to 3)
if(map.getOrDefault("Dan", 0) > 3) {
println("Gotcha!")
}
}
""".trimIndent()
)
Assertions.assertThat(findings).hasSize(1)
}
Any ideas why references is an empty array or does anyone have any other suggestions for checking the type of the receiver?