
io.gitlab.arturbosch.detekt.rules.style.ExplicitCollectionElementAccessMethod.kt Maven / Gradle / Ivy
package io.gitlab.arturbosch.detekt.rules.style
import io.gitlab.arturbosch.detekt.api.CodeSmell
import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.api.Debt
import io.gitlab.arturbosch.detekt.api.Entity
import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.rules.fqNameOrNull
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.supertypes
/**
* In Kotlin functions `get` or `set` can be replaced with the shorter operator — `[]`,
* see https://kotlinlang.org/docs/reference/operator-overloading.html#indexed.
* Prefer the usage of the indexed access operator `[]` for map or list element access or insert methods.
*
*
* val map = Map()
* map.put("key", "value")
* val value = map.get("key")
*
*
*
* val map = Map()
* map["key"] = "value"
* val value = map["key"]
*
*/
class ExplicitCollectionElementAccessMethod(config: Config = Config.empty) : Rule(config) {
private val ktCollections = setOf(
"kotlin.collections.Map",
"kotlin.collections.MutableMap",
"kotlin.collections.List",
"kotlin.collections.MutableList"
)
private val mapAccessMethods = setOf("get", "put")
private val ktAndJavaCollections = ktCollections + setOf("AbstractMap", "AbstractList")
override val issue: Issue =
Issue(
"ExplicitCollectionElementAccessMethod",
Severity.Style,
"Prefer usage of indexed access operator [] for map element access or insert methods",
Debt.FIVE_MINS
)
override fun visitCallExpression(expression: KtCallExpression) {
if (isMapMethod(expression) && isGetOrPut(expression)) {
report(CodeSmell(issue, Entity.from(expression), "Prefer usage of indexed access operator []."))
}
super.visitCallExpression(expression)
}
private fun isGetOrPut(expression: KtCallExpression): Boolean {
return expression.calleeExpression?.text in mapAccessMethods
}
private fun isMapMethod(expression: KtCallExpression): Boolean {
val dotExpression = expression.prevSibling
val caller = when (dotExpression?.parent) {
is KtDotQualifiedExpression -> dotExpression.prevSibling
else -> return false
}
return (caller as? KtElement).getResolvedCall(bindingContext)
?.resultingDescriptor
?.returnType
.isEligibleCollection()
}
private fun KotlinType?.isEligibleCollection(): Boolean {
if (this?.fqNameOrNull()?.asString() in ktCollections) return true
return this?.supertypes()?.any { it.constructor.toString() in ktAndJavaCollections } == true
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy