16
16
*/
17
17
package org.sonarsource.kotlin.api.regex
18
18
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
19
23
import org.jetbrains.kotlin.psi.KtBinaryExpression
20
24
import org.jetbrains.kotlin.psi.KtCallExpression
21
25
import org.jetbrains.kotlin.psi.KtExpression
@@ -24,9 +28,6 @@ import org.jetbrains.kotlin.psi.KtReferenceExpression
24
28
import org.jetbrains.kotlin.psi.KtStringTemplateEntryWithExpression
25
29
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
26
30
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
30
31
import org.sonar.api.batch.fs.TextRange
31
32
import org.sonarsource.analyzer.commons.regex.RegexIssueLocation
32
33
import org.sonarsource.analyzer.commons.regex.RegexParseResult
@@ -41,25 +42,29 @@ import org.sonarsource.kotlin.api.checks.STRING_TYPE
41
42
import org.sonarsource.kotlin.api.checks.predictRuntimeValueExpression
42
43
import org.sonarsource.kotlin.api.frontend.KotlinFileContext
43
44
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
46
45
import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange
46
+ import org.sonarsource.kotlin.api.reporting.SecondaryLocation
47
+ import org.sonarsource.kotlin.api.visiting.withKaSession
47
48
import java.util.regex.Pattern
49
+ import org.sonarsource.kotlin.api.checks.isPlus as isConcat
48
50
49
51
val PATTERN_COMPILE_MATCHER = FunMatcher (qualifier = " java.util.regex.Pattern" , name = " compile" )
50
52
val REGEX_MATCHER = ConstructorMatcher (typeName = " kotlin.text.Regex" )
51
53
val TO_REGEX_MATCHER = FunMatcher (qualifier = " kotlin.text" , name = " toRegex" , isExtensionFunction = true )
52
54
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 )
55
57
}
56
58
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
+ }
59
64
}
60
65
61
66
// 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 (
63
68
REGEX_MATCHER to (argGetter(0 ) to argGetter(1 )),
64
69
TO_REGEX_MATCHER to (referenceTargetGetter to argGetter(0 )),
65
70
PATTERN_COMPILE_MATCHER to (argGetter(0 ) to argGetter(1 )),
@@ -102,13 +107,14 @@ abstract class AbstractRegexCheck : CallAbstractCheck() {
102
107
103
108
override fun visitFunctionCall (
104
109
callExpression : KtCallExpression ,
105
- resolvedCall : ResolvedCall <* >,
110
+ resolvedCall : KaFunctionCall <* >,
106
111
matchedFun : FunMatcherImpl ,
107
112
kotlinFileContext : KotlinFileContext
108
113
) {
114
+
109
115
REGEX_FUNCTIONS [matchedFun]!! .let { (regexStringArgExtractor, flagsArgExtractor) ->
110
116
val regexCtx = regexStringArgExtractor(resolvedCall)
111
- .collectResolvedListOfStringTemplates(kotlinFileContext.bindingContext )
117
+ .collectResolvedListOfStringTemplates()
112
118
// For now, we simply don't use any sequence that contains nulls (i.e. non-resolvable parts)
113
119
.takeIf { null !in it }?.filterNotNull()
114
120
?.flatMap { it.entries.asSequence() }
@@ -118,7 +124,7 @@ abstract class AbstractRegexCheck : CallAbstractCheck() {
118
124
RegexContext (sourceTemplates.asIterable(), kotlinFileContext)
119
125
} ? : return
120
126
121
- flagsArgExtractor(resolvedCall).extractRegexFlags(kotlinFileContext.bindingContext )
127
+ flagsArgExtractor(resolvedCall).extractRegexFlags()
122
128
.takeIf { flags -> Pattern .LITERAL !in flags }
123
129
?.let { flags ->
124
130
@@ -168,24 +174,24 @@ private data class AnalyzerIssueReportInfo(
168
174
val gap : Double? ,
169
175
)
170
176
171
- private fun KtExpression?.extractRegexFlags (bindingContext : BindingContext ): FlagSet =
177
+ private fun KtExpression?.extractRegexFlags (): FlagSet =
172
178
FlagSet (
173
179
this ?.collectDescendantsOfType<KtReferenceExpression >()
174
- ?.map { it.predictRuntimeValueExpression(bindingContext ) }
180
+ ?.map { it.predictRuntimeValueExpression() }
175
181
?.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] }
178
184
?.fold(0 , Int ::or )
179
185
? : 0
180
186
)
181
187
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 ->
184
190
when {
185
191
predictedValue is KtStringTemplateExpression -> sequenceOf(predictedValue)
186
192
predictedValue is KtBinaryExpression && predictedValue.isConcat() ->
187
- predictedValue.left.collectResolvedListOfStringTemplates(bindingContext ) +
188
- predictedValue.right.collectResolvedListOfStringTemplates(bindingContext )
193
+ predictedValue.left.collectResolvedListOfStringTemplates() +
194
+ predictedValue.right.collectResolvedListOfStringTemplates()
189
195
else -> sequenceOf(null )
190
196
}
191
197
}
0 commit comments