Skip to content

Commit

Permalink
Fix false-positive on ExplicitCollectionElementAccessMethod (#4400)
Browse files Browse the repository at this point in the history
  • Loading branch information
BraisGabin committed Dec 27, 2021
1 parent 1f1924f commit 73203f3
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 8 deletions.
Expand Up @@ -10,6 +10,7 @@ import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.api.internal.RequiresTypeResolution
import io.gitlab.arturbosch.detekt.rules.fqNameOrNull
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.load.java.isFromJava
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
Expand Down Expand Up @@ -57,21 +58,23 @@ class ExplicitCollectionElementAccessMethod(config: Config = Config.empty) : Rul
}

private fun isIndexableGetter(expression: KtCallExpression): Boolean =
expression.calleeExpression?.text == "get" && isOperatorFunction(expression)
expression.calleeExpression?.text == "get" && expression.getFunctionDescriptor()?.isOperator == true

private fun isIndexableSetter(expression: KtCallExpression): Boolean =
when (expression.calleeExpression?.text) {
"set" -> isOperatorFunction(expression)
"set" -> {
val function = expression.getFunctionDescriptor()
when {
function == null -> false
!function.isOperator -> false
else -> !(function.isFromJava && function.valueParameters.size > 2)
}
}
// `put` isn't an operator function, but can be replaced with indexer when the caller is Map.
"put" -> isCallerMap(expression)
else -> false
}

private fun isOperatorFunction(expression: KtCallExpression): Boolean {
val function = (expression.getResolvedCall(bindingContext)?.resultingDescriptor as? FunctionDescriptor)
return function?.isOperator == true
}

private fun isCallerMap(expression: KtCallExpression): Boolean {
val caller = expression.getQualifiedExpressionForSelector()?.receiverExpression
val type = caller.getResolvedCall(bindingContext)?.resultingDescriptor?.returnType
Expand All @@ -84,4 +87,8 @@ class ExplicitCollectionElementAccessMethod(config: Config = Config.empty) : Rul

private fun unusedReturnValue(expression: KtCallExpression): Boolean =
expression.parent.parent is KtBlockExpression

private fun KtCallExpression.getFunctionDescriptor(): FunctionDescriptor? {
return getResolvedCall(bindingContext)?.resultingDescriptor as? FunctionDescriptor
}
}
@@ -1,5 +1,6 @@
package io.gitlab.arturbosch.detekt.rules.style

import io.github.detekt.test.utils.resourceAsPath
import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.rules.setupKotlinEnvironment
import io.gitlab.arturbosch.detekt.test.compileAndLintWithContext
Expand All @@ -10,7 +11,7 @@ import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe

class ExplicitCollectionElementAccessMethodSpec : Spek({
setupKotlinEnvironment()
setupKotlinEnvironment(additionalJavaSourceRootPath = resourceAsPath("java"))

val env: KotlinCoreEnvironment by memoized()
val subject by memoized { ExplicitCollectionElementAccessMethod(Config.empty) }
Expand Down Expand Up @@ -344,5 +345,17 @@ class ExplicitCollectionElementAccessMethodSpec : Spek({
"""
assertThat(subject.compileAndLintWithContext(env, code)).isEmpty()
}

it("does not report if the function has 3 or more arguments and it's defined in java - #4288") {
val code = """
import com.example.fromjava.Rect
fun foo() {
val rect = Rect()
rect.set(0, 1, 2)
}
"""
assertThat(subject.lintWithContext(env, code)).isEmpty()
}
}
})
@@ -0,0 +1,5 @@
package com.example.fromjava;

class Rect {
void set(int left, int top, int right) {}
}

0 comments on commit 73203f3

Please sign in to comment.