Skip to content

Commit

Permalink
SONARKT-423 Migrate UnencryptedDatabaseOnMobileCheck to kotlin-analys…
Browse files Browse the repository at this point in the history
…is-api

Co-authored-by: Marharyta Nedzelska <[email protected]>
  • Loading branch information
Godin and leveretka authored Jan 27, 2025
1 parent ec64770 commit 88f3368
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.analysis.api.resolution.KaCall
import org.jetbrains.kotlin.analysis.api.resolution.KaExplicitReceiverValue
import org.jetbrains.kotlin.analysis.api.resolution.KaFunctionCall
import org.jetbrains.kotlin.analysis.api.resolution.KaImplicitReceiverValue
import org.jetbrains.kotlin.analysis.api.resolution.singleFunctionCallOrNull
import org.jetbrains.kotlin.analysis.api.resolution.successfulCallOrNull
import org.jetbrains.kotlin.analysis.api.resolution.successfulFunctionCallOrNull
import org.jetbrains.kotlin.analysis.api.resolution.symbol
Expand Down Expand Up @@ -665,13 +666,14 @@ fun CallableDescriptor.throwsExceptions(exceptions: Collection<String>) =

fun KtNamedFunction.isInfix() = hasModifier(KtTokens.INFIX_KEYWORD)

fun Call.findCallInPrecedingCallChain(matcher: FunMatcherImpl, bindingContext: BindingContext): Pair<Call, ResolvedCall<*>>? {
var receiver = this
var receiverResolved = receiver.getResolvedCall(bindingContext) ?: return null
fun KtExpression.findCallInPrecedingCallChain(
matcher: FunMatcherImpl,
): Pair<KtExpression, KaFunctionCall<*>>? = withKaSession {
var receiver = this@findCallInPrecedingCallChain
var receiverResolved = receiver.resolveToCall()?.successfulFunctionCallOrNull() ?: return null
while (!matcher.matches(receiverResolved)) {
val callElement = receiver.callElement as? KtCallExpression ?: return null
receiver = callElement.predictReceiverExpression(bindingContext)?.getCall(bindingContext) ?: return null
receiverResolved = receiver.getResolvedCall(bindingContext) ?: return null
receiver = receiver.predictReceiverExpression() ?: return null
receiverResolved = receiver.resolveToCall()?.singleFunctionCallOrNull() ?: return null
}
return receiver to receiverResolved
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
*/
package org.sonarsource.kotlin.checks

import org.jetbrains.kotlin.analysis.api.resolution.successfulFunctionCallOrNull
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.resolve.calls.util.getCall
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
import org.sonar.check.Rule
import org.sonarsource.kotlin.api.checks.AbstractCheck
import org.sonarsource.kotlin.api.checks.FunMatcher
import org.sonarsource.kotlin.api.checks.findCallInPrecedingCallChain
import org.sonarsource.kotlin.api.checks.matches
import org.sonarsource.kotlin.api.frontend.KotlinFileContext
import org.sonarsource.kotlin.api.visiting.withKaSession

private val PROBLEMATIC_SIMPLE_CALLS = listOf(
FunMatcher(definingSupertype = "android.app.Activity", name = "getPreferences"),
Expand All @@ -38,17 +38,15 @@ private val REALM_ENC_KEY_FUN = FunMatcher(definingSupertype = "io.realm.RealmCo

private const val MESSAGE = "Make sure using an unencrypted database is safe here."

@org.sonarsource.kotlin.api.frontend.K1only
@Rule(key = "S6291")
class UnencryptedDatabaseOnMobileCheck : AbstractCheck() {
override fun visitCallExpression(callExpression: KtCallExpression, kotlinFileContext: KotlinFileContext) {
val bindingContext = kotlinFileContext.bindingContext
val resolvedCall = callExpression.getResolvedCall(bindingContext)
val resolvedCall = withKaSession { callExpression.resolveToCall()?.successfulFunctionCallOrNull() }
if (PROBLEMATIC_SIMPLE_CALLS.any { resolvedCall matches it }) {
kotlinFileContext.reportIssue(callExpression.calleeExpression!!, MESSAGE)
} else if (
resolvedCall matches PROBLEMATIC_REALM_CALL &&
callExpression.getCall(bindingContext)?.findCallInPrecedingCallChain(REALM_ENC_KEY_FUN, bindingContext) == null
callExpression.findCallInPrecedingCallChain(REALM_ENC_KEY_FUN) == null
) {
kotlinFileContext.reportIssue(callExpression.calleeExpression!!, MESSAGE)
}
Expand Down

0 comments on commit 88f3368

Please sign in to comment.