Skip to content

Commit b3fd933

Browse files
committed
SONARKT-400 Migrate AbstractRegexCheck to kotlin-analysis-api
1 parent a1dd1d1 commit b3fd933

File tree

1 file changed

+27
-21
lines changed

1 file changed

+27
-21
lines changed

sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/regex/AbstractRegexCheck.kt

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
*/
1717
package org.sonarsource.kotlin.api.regex
1818

19+
import org.jetbrains.kotlin.analysis.api.resolution.KaExplicitReceiverValue
20+
import org.jetbrains.kotlin.analysis.api.resolution.KaFunctionCall
21+
import org.jetbrains.kotlin.analysis.api.symbols.name
22+
import org.jetbrains.kotlin.idea.references.mainReference
1923
import org.jetbrains.kotlin.psi.KtBinaryExpression
2024
import org.jetbrains.kotlin.psi.KtCallExpression
2125
import org.jetbrains.kotlin.psi.KtExpression
@@ -24,9 +28,6 @@ import org.jetbrains.kotlin.psi.KtReferenceExpression
2428
import org.jetbrains.kotlin.psi.KtStringTemplateEntryWithExpression
2529
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
2630
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
27-
import org.jetbrains.kotlin.resolve.BindingContext
28-
import org.jetbrains.kotlin.resolve.calls.util.getReceiverExpression
29-
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
3031
import org.sonar.api.batch.fs.TextRange
3132
import org.sonarsource.analyzer.commons.regex.RegexIssueLocation
3233
import org.sonarsource.analyzer.commons.regex.RegexParseResult
@@ -41,25 +42,29 @@ import org.sonarsource.kotlin.api.checks.STRING_TYPE
4142
import org.sonarsource.kotlin.api.checks.predictRuntimeValueExpression
4243
import org.sonarsource.kotlin.api.frontend.KotlinFileContext
4344
import org.sonarsource.kotlin.api.frontend.TextRangeTracker
44-
import org.sonarsource.kotlin.api.checks.isPlus as isConcat
45-
import org.sonarsource.kotlin.api.reporting.SecondaryLocation
4645
import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange
46+
import org.sonarsource.kotlin.api.reporting.SecondaryLocation
47+
import org.sonarsource.kotlin.api.visiting.withKaSession
4748
import java.util.regex.Pattern
49+
import org.sonarsource.kotlin.api.checks.isPlus as isConcat
4850

4951
val PATTERN_COMPILE_MATCHER = FunMatcher(qualifier = "java.util.regex.Pattern", name = "compile")
5052
val REGEX_MATCHER = ConstructorMatcher(typeName = "kotlin.text.Regex")
5153
val TO_REGEX_MATCHER = FunMatcher(qualifier = "kotlin.text", name = "toRegex", isExtensionFunction = true)
5254

53-
private fun argGetter(argIndex: Int) = { resolvedCall: ResolvedCall<*> ->
54-
resolvedCall.valueArgumentsByIndex?.getOrNull(argIndex)?.arguments?.getOrNull(0)?.getArgumentExpression()
55+
private fun argGetter(argIndex: Int) = { resolvedCall: KaFunctionCall<*> ->
56+
resolvedCall.argumentMapping.keys.elementAtOrNull(argIndex)
5557
}
5658

57-
private val referenceTargetGetter = { resolvedCall: ResolvedCall<*> ->
58-
resolvedCall.getReceiverExpression()
59+
private val referenceTargetGetter = { resolvedCall: KaFunctionCall<*> ->
60+
when (val receiver = resolvedCall.partiallyAppliedSymbol.extensionReceiver) {
61+
is KaExplicitReceiverValue -> receiver.expression
62+
else -> null
63+
}
5964
}
6065

6166
// TODO: add org.apache.commons.lang3.RegExUtils
62-
private val REGEX_FUNCTIONS: Map<FunMatcherImpl, Pair<(ResolvedCall<*>) -> KtExpression?, (ResolvedCall<*>) -> KtExpression?>> = mapOf(
67+
private val REGEX_FUNCTIONS: Map<FunMatcherImpl, Pair<(KaFunctionCall<*>) -> KtExpression?, (KaFunctionCall<*>) -> KtExpression?>> = mapOf(
6368
REGEX_MATCHER to (argGetter(0) to argGetter(1)),
6469
TO_REGEX_MATCHER to (referenceTargetGetter to argGetter(0)),
6570
PATTERN_COMPILE_MATCHER to (argGetter(0) to argGetter(1)),
@@ -102,13 +107,14 @@ abstract class AbstractRegexCheck : CallAbstractCheck() {
102107

103108
override fun visitFunctionCall(
104109
callExpression: KtCallExpression,
105-
resolvedCall: ResolvedCall<*>,
110+
resolvedCall: KaFunctionCall<*>,
106111
matchedFun: FunMatcherImpl,
107112
kotlinFileContext: KotlinFileContext
108113
) {
114+
109115
REGEX_FUNCTIONS[matchedFun]!!.let { (regexStringArgExtractor, flagsArgExtractor) ->
110116
val regexCtx = regexStringArgExtractor(resolvedCall)
111-
.collectResolvedListOfStringTemplates(kotlinFileContext.bindingContext)
117+
.collectResolvedListOfStringTemplates()
112118
// For now, we simply don't use any sequence that contains nulls (i.e. non-resolvable parts)
113119
.takeIf { null !in it }?.filterNotNull()
114120
?.flatMap { it.entries.asSequence() }
@@ -118,7 +124,7 @@ abstract class AbstractRegexCheck : CallAbstractCheck() {
118124
RegexContext(sourceTemplates.asIterable(), kotlinFileContext)
119125
} ?: return
120126

121-
flagsArgExtractor(resolvedCall).extractRegexFlags(kotlinFileContext.bindingContext)
127+
flagsArgExtractor(resolvedCall).extractRegexFlags()
122128
.takeIf { flags -> Pattern.LITERAL !in flags }
123129
?.let { flags ->
124130

@@ -168,24 +174,24 @@ private data class AnalyzerIssueReportInfo(
168174
val gap: Double?,
169175
)
170176

171-
private fun KtExpression?.extractRegexFlags(bindingContext: BindingContext): FlagSet =
177+
private fun KtExpression?.extractRegexFlags(): FlagSet =
172178
FlagSet(
173179
this?.collectDescendantsOfType<KtReferenceExpression>()
174-
?.map { it.predictRuntimeValueExpression(bindingContext) }
180+
?.map { it.predictRuntimeValueExpression() }
175181
?.flatMap { it.collectDescendantsOfType<KtNameReferenceExpression>() }
176-
?.mapNotNull { bindingContext[BindingContext.REFERENCE_TARGET, it] }
177-
?.mapNotNull { FLAGS[it.name.asString()] }
182+
?.mapNotNull { withKaSession { it.mainReference.resolveToSymbol()?.name?.asString() } }
183+
?.mapNotNull { FLAGS[it] }
178184
?.fold(0, Int::or)
179185
?: 0
180186
)
181187

182-
private fun KtExpression?.collectResolvedListOfStringTemplates(bindingContext: BindingContext): Sequence<KtStringTemplateExpression?> =
183-
this?.predictRuntimeValueExpression(bindingContext).let { predictedValue ->
188+
private fun KtExpression?.collectResolvedListOfStringTemplates(): Sequence<KtStringTemplateExpression?> =
189+
this?.predictRuntimeValueExpression().let { predictedValue ->
184190
when {
185191
predictedValue is KtStringTemplateExpression -> sequenceOf(predictedValue)
186192
predictedValue is KtBinaryExpression && predictedValue.isConcat() ->
187-
predictedValue.left.collectResolvedListOfStringTemplates(bindingContext) +
188-
predictedValue.right.collectResolvedListOfStringTemplates(bindingContext)
193+
predictedValue.left.collectResolvedListOfStringTemplates() +
194+
predictedValue.right.collectResolvedListOfStringTemplates()
189195
else -> sequenceOf(null)
190196
}
191197
}

0 commit comments

Comments
 (0)