Skip to content

Commit

Permalink
(WIP) SimplifyFilteringBeforeTerminalOperationCheck
Browse files Browse the repository at this point in the history
  • Loading branch information
Godin committed Oct 21, 2024
1 parent a10f4f3 commit 0b5a2a6
Showing 1 changed file with 15 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,23 @@
*/
package org.sonarsource.kotlin.checks

import org.jetbrains.kotlin.analysis.api.resolution.KaFunctionCall
import org.jetbrains.kotlin.analysis.api.resolution.singleFunctionCallOrNull
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.psi2ir.deparenthesize
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI
import org.sonar.check.Rule
import org.sonarsource.kotlin.api.checks.CallAbstractCheck
import org.sonarsource.kotlin.api.checks.FunMatcher
import org.sonarsource.kotlin.api.frontend.KotlinFileContext
import org.sonarsource.kotlin.api.reporting.message
import org.sonarsource.kotlin.api.visiting.analyze

private const val KOTLIN_COLLECTIONS_QUALIFIER = "kotlin.collections"
private val FILTER_MATCHER = FunMatcher(qualifier = KOTLIN_COLLECTIONS_QUALIFIER, name = "filter") { withArguments("kotlin.Function1") }

@org.sonarsource.kotlin.api.frontend.K1only("easy?")
@Rule(key = "S6527")
class SimplifyFilteringBeforeTerminalOperationCheck : CallAbstractCheck() {
override val functionsToVisit = listOf(
Expand All @@ -43,20 +45,22 @@ class SimplifyFilteringBeforeTerminalOperationCheck : CallAbstractCheck() {
}
)

// TODO easy?
@OptIn(IDEAPluginsCompatibilityAPI::class)
override fun visitFunctionCall(callExpression: KtCallExpression, resolvedCall: ResolvedCall<*>, kotlinFileContext: KotlinFileContext) {
callExpression.parent
override fun visitFunctionCall(callExpression: KtCallExpression, resolvedCall: KaFunctionCall<*>, kotlinFileContext: KotlinFileContext): Unit = analyze {
val x = callExpression.parent
.let { it as? KtDotQualifiedExpression }
?.receiverExpression
?.getCall(kotlinFileContext.bindingContext)
?.takeIf { callBeforeTerminalOp -> FILTER_MATCHER.matches(callBeforeTerminalOp, kotlinFileContext.bindingContext) }
// TODO note that resolveToCall doesn't deparenthesize unlike getCall
?.deparenthesize()
x?.resolveToCall()?.singleFunctionCallOrNull()
?.takeIf { callBeforeTerminalOp -> FILTER_MATCHER.matches(callBeforeTerminalOp) }
?.let { filterCallBeforeTerminalOp ->
val filterCallText = filterCallBeforeTerminalOp.callElement.text
val filterPredicateText = filterCallBeforeTerminalOp.valueArguments[0].asElement().text
// TODO pay attention on next line
val callElement = if (x is KtDotQualifiedExpression) x.selectorExpression!! else x
val filterCallText = callElement.text
val filterPredicateText = filterCallBeforeTerminalOp.argumentMapping.keys.first().text
val terminalOpCallText = callExpression.text
val terminalOpWithPredicate = "${callExpression.calleeExpression!!.text} $filterPredicateText"

val message = message {
+"Remove "
code(filterCallText)
Expand All @@ -67,7 +71,7 @@ class SimplifyFilteringBeforeTerminalOperationCheck : CallAbstractCheck() {
+"."
}

kotlinFileContext.reportIssue(filterCallBeforeTerminalOp.callElement, message)
kotlinFileContext.reportIssue(callElement, message)
}
}
}

0 comments on commit 0b5a2a6

Please sign in to comment.