diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/ApiExtensions.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/ApiExtensions.kt index 099ac452f..3f8c600da 100644 --- a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/ApiExtensions.kt +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/ApiExtensions.kt @@ -71,7 +71,7 @@ import org.sonar.api.utils.Version import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.merge import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession annotation class Rewritten @@ -96,7 +96,7 @@ fun KtExpression.predictRuntimeStringValue() = predictRuntimeValueExpression().stringValue() @Rewritten -fun KtExpression.predictRuntimeIntValue(): Int? = analyze { +fun KtExpression.predictRuntimeIntValue(): Int? = withKaSession { val valueExpression = predictRuntimeValueExpression() if (valueExpression.expressionType?.isIntType == true) { valueExpression?.evaluate()?.value as? Int @@ -104,7 +104,7 @@ fun KtExpression.predictRuntimeIntValue(): Int? = analyze { } @Rewritten -fun KtExpression.predictRuntimeBooleanValue() = analyze { +fun KtExpression.predictRuntimeBooleanValue() = withKaSession { val valueExpression = predictRuntimeValueExpression() if (valueExpression.expressionType?.isBooleanType == true) { @@ -168,7 +168,7 @@ fun KtExpression.predictRuntimeValueExpression( declarations ) - is KtThisExpression -> analyze { + is KtThisExpression -> withKaSession { var symbol = deparenthesized.instanceReference.mainReference.resolveToSymbol() // In K1 the symbol is anonymous function symbol, in K2 it is a parameter if (symbol !is KaAnonymousFunctionSymbol) symbol = symbol?.containingSymbol @@ -176,7 +176,7 @@ fun KtExpression.predictRuntimeValueExpression( ?.findLetAlsoRunWithTargetExpression() } - else -> analyze { + else -> withKaSession { deparenthesized.resolveToCall()?.successfulFunctionCallOrNull()?.predictValueExpression() } } ?: deparenthesized as? KtExpression @@ -201,7 +201,7 @@ fun KtCallExpression.predictReceiverExpression( @Rewritten fun KtExpression.predictReceiverExpression( ): KtExpression? = - analyze { + withKaSession { val call = this@predictReceiverExpression.resolveToCall()?.successfulFunctionCallOrNull() val symbol = call?.partiallyAppliedSymbol val receiver = symbol?.extensionReceiver ?: symbol?.dispatchReceiver @@ -277,7 +277,7 @@ private fun KtExpression.stringValue( @Rewritten fun KtExpression.stringValue( declarations: MutableList = mutableListOf(), -): String? = analyze { +): String? = withKaSession { when (this@stringValue) { is KtStringTemplateExpression -> { val entries = entries.map { @@ -332,7 +332,7 @@ private fun KtReferenceExpression.extractFromInitializer( @Rewritten private fun KtReferenceExpression.extractFromInitializer( declarations: MutableList = mutableListOf(), -) = analyze { +) = withKaSession { (this@extractFromInitializer.mainReference.resolveToSymbol() as? KaVariableSymbol) ?.let { if (it.isVal) { @@ -379,7 +379,7 @@ private fun KaImplicitReceiverValue.findReceiverScopeFunctionLiteral( @Rewritten private fun KtReferenceExpression.findReceiverScopeFunctionLiteral(): KtFunctionLiteral? = - analyze { + withKaSession { when (val resolvedSymbol = this@findReceiverScopeFunctionLiteral.mainReference.resolveToSymbol()) { is KaValueParameterSymbol -> resolvedSymbol.containingSymbol?.findFunctionLiteral( this@findReceiverScopeFunctionLiteral @@ -410,9 +410,9 @@ private fun KtFunctionLiteral.findLetAlsoRunWithTargetExpression(bindingContext: @Rewritten private fun KtFunctionLiteral.findLetAlsoRunWithTargetExpression(): KtExpression? = - analyze { + withKaSession { (getParentCall() as? KaFunctionCall<*>)?.let { larwCallCandidate -> - analyze { + withKaSession { when (larwCallCandidate.partiallyAppliedSymbol.symbol.name?.asString()) { in KOTLIN_CHAIN_CALL_CONSTRUCTS -> { (larwCallCandidate.partiallyAppliedSymbol.extensionReceiver as? KaExplicitReceiverValue)?.expression?.predictRuntimeValueExpression() @@ -439,7 +439,7 @@ fun KtElement.getParentCall(): KaCall? { KtUnaryExpression::class.java, KtArrayAccessExpression::class.java ) val parentOfType = PsiTreeUtil.getParentOfType(this, *callExpressionTypes) - return analyze { parentOfType?.resolveToCall()?.successfulCallOrNull() } + return withKaSession { parentOfType?.resolveToCall()?.successfulCallOrNull() } } @@ -470,7 +470,7 @@ private fun DeclarationDescriptor.findFunctionLiteral( @Rewritten private fun KaSymbol.findFunctionLiteral( startNode: PsiElement, -): KtFunctionLiteral? = analyze { +): KtFunctionLiteral? = withKaSession { var curNode: PsiElement? = startNode for (i in 0 until MAX_AST_PARENT_TRAVERSALS) { curNode = curNode?.parent ?: break @@ -534,7 +534,7 @@ fun KtParameter.determineTypeAsString(bindingContext: BindingContext, printTypeA /** * TODO see also [FunMatcherImpl.checkReturnType] */ -fun KtDeclaration.determineTypeAsString() = analyze { +fun KtDeclaration.determineTypeAsString() = withKaSession { (this@determineTypeAsString.returnType as? KaClassType)?.classId?.asFqNameString() } @@ -545,13 +545,13 @@ private fun KtTypeReference.determineType(bindingContext: BindingContext) = fun KtTypeReference.determineTypeAsString(bindingContext: BindingContext, printTypeArguments: Boolean = false) = determineType(bindingContext)?.getKotlinTypeFqName(printTypeArguments) -fun KtTypeReference.determineTypeAsString() = analyze { +fun KtTypeReference.determineTypeAsString() = withKaSession { this@determineTypeAsString.type.symbol?.classId?.asFqNameString() } fun KtNamedFunction.returnTypeAsString(): String? { val namedFunction = this - analyze { + withKaSession { when (val returnType = namedFunction.returnType) { is KaClassType -> return returnType.classId.asFqNameString() else -> return null @@ -572,7 +572,7 @@ fun KtNamedFunction.isInfix() = hasModifier(KtTokens.INFIX_KEYWORD) * Checks whether the expression is a call, matches the FunMatchers in [STRING_TO_BYTE_FUNS] and is called on a constant string value. */ @Rewritten -fun KtExpression.isBytesInitializedFromString() = analyze { +fun KtExpression.isBytesInitializedFromString() = withKaSession { val resolveToCall = this@isBytesInitializedFromString.resolveToCall() val functionCall = resolveToCall?.successfulFunctionCallOrNull() @@ -657,7 +657,7 @@ fun KtExpression.isInitializedPredictably(searchStartNode: KtExpression, binding @Rewritten fun KtExpression.isInitializedPredictably(searchStartNode: KtExpression): Boolean { return this !is KtNameReferenceExpression || this.findUsages(searchStartNode) { - analyze { + withKaSession { it.getParentOfType(false)?.resolveToCall() ?.successfulFunctionCallOrNull() matches SECURE_RANDOM_FUNS } @@ -676,7 +676,7 @@ fun KtExpression?.isLocalVariable(bindingContext: BindingContext) = fun KtExpression?.isLocalVariable(): Boolean { if (this !is KtNameReferenceExpression) return false val expression = this - analyze { + withKaSession { return expression.mainReference.resolveToSymbol() is KaLocalVariableSymbol } } @@ -697,7 +697,7 @@ fun KtExpression?.setterMatches( fun KtExpression?.setterMatches( propertyName: String, matcher: FunMatcherImpl -): Boolean = analyze { +): Boolean = withKaSession { when (this@setterMatches) { is KtNameReferenceExpression -> (getReferencedName() == propertyName) && (matcher.matches(this@setterMatches.resolveToCall()?.successfulVariableAccessCall() ?: return false)) @@ -781,7 +781,7 @@ fun PsiElement?.determineType(bindingContext: BindingContext): KotlinType? = } -fun PsiElement?.determineType(): KaType? = analyze { +fun PsiElement?.determineType(): KaType? = withKaSession { this?.let { when (this@determineType) { is KtCallExpression -> determineTypeFromCall() @@ -803,7 +803,7 @@ fun PsiElement?.determineType(): KaType? = analyze { } } -private fun KtElement.determineTypeFromCall(): KaType? = analyze { +private fun KtElement.determineTypeFromCall(): KaType? = withKaSession { this@determineTypeFromCall.resolveToCall()?.let { (it.successfulFunctionCallOrNull() ?: it.singleVariableAccessCall()) ?.partiallyAppliedSymbol?.symbol?.returnType @@ -838,7 +838,7 @@ fun SensorContext.hasCacheEnabled(): Boolean { } @OptIn(KaIdeApi::class) -fun KtWhenExpression.isExhaustive(context: KotlinFileContext): Boolean = analyze { +fun KtWhenExpression.isExhaustive(context: KotlinFileContext): Boolean = withKaSession { return entries.any { it.isElse } || this@isExhaustive.computeMissingCases().isEmpty() // return entries.any { it.isElse } || context.bindingContext[BindingContext.EXHAUSTIVE_WHEN, this] == true } diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/CallAbstractCheck.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/CallAbstractCheck.kt index 7b86183ee..7e572a272 100644 --- a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/CallAbstractCheck.kt +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/CallAbstractCheck.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession abstract class CallAbstractCheck : AbstractCheck() { abstract val functionsToVisit: Iterable @@ -48,7 +48,7 @@ abstract class CallAbstractCheck : AbstractCheck() { open fun visitFunctionCall(callExpression: KtCallExpression, resolvedCall: KaFunctionCall<*>, kotlinFileContext: KotlinFileContext) = Unit final override fun visitCallExpression(callExpression: KtCallExpression, kotlinFileContext: KotlinFileContext) { - analyze { + withKaSession { val resolvedCall = callExpression.resolveToCall()?.singleFunctionCallOrNull() ?: return functionsToVisit.firstOrNull { it.matches(resolvedCall) } ?.let { visitFunctionCall(callExpression, resolvedCall, it, kotlinFileContext) } diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/FunMatcher.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/FunMatcher.kt index f3d5aba88..e3865485f 100644 --- a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/FunMatcher.kt +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/checks/FunMatcher.kt @@ -40,7 +40,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val VARARG_PREFIX = "vararg "; @@ -73,7 +73,7 @@ class FunMatcherImpl( matches(bindingContext[RESOLVED_CALL, call]?.resultingDescriptor) } - fun matches(node: KtCallExpression): Boolean = analyze { + fun matches(node: KtCallExpression): Boolean = withKaSession { val call = node.resolveToCall()?.successfulFunctionCallOrNull() return call != null && matches(call) } @@ -85,7 +85,7 @@ class FunMatcherImpl( } @OptIn(KaExperimentalApi::class) - fun matches(node: KtNamedFunction): Boolean = analyze { + fun matches(node: KtNamedFunction): Boolean = withKaSession { // TODO try node.resolveToCall return matches(null, node.symbol.asSignature()) } @@ -211,7 +211,7 @@ class FunMatcherImpl( } } - private fun checkSubType(functionDescriptor: KaCallableSignature<*>): Boolean = analyze { + private fun checkSubType(functionDescriptor: KaCallableSignature<*>): Boolean = withKaSession { if (functionDescriptor.symbol is KaConstructorSymbol) return false return functionDescriptor.symbol.allOverriddenSymbols.any { val className: String? = it.callableId?.asSingleFqName()?.parent()?.asString() diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/regex/AbstractRegexCheck.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/regex/AbstractRegexCheck.kt index f9f2429d1..6ee5defcb 100644 --- a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/regex/AbstractRegexCheck.kt +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/regex/AbstractRegexCheck.kt @@ -43,7 +43,7 @@ import org.sonarsource.kotlin.api.frontend.TextRangeTracker import org.sonarsource.kotlin.api.checks.isPlus as isConcat import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession import java.util.regex.Pattern val PATTERN_COMPILE_MATCHER = FunMatcher(qualifier = "java.util.regex.Pattern", name = "compile") @@ -203,7 +203,7 @@ private fun KtExpression?.extractRegexFlags(): FlagSet = } ?.flatMap { it.collectDescendantsOfType() } ?.mapNotNull { - analyze { it.mainReference.resolveToSymbol()?.name?.asString() } + withKaSession { it.mainReference.resolveToSymbol()?.name?.asString() } } ?.mapNotNull { FLAGS[it] } ?.fold(0, Int::or) diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/visiting/KotlinFileVisitor.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/visiting/KotlinFileVisitor.kt index df12c76ce..eda832e55 100644 --- a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/visiting/KotlinFileVisitor.kt +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/visiting/KotlinFileVisitor.kt @@ -23,9 +23,6 @@ import org.sonarsource.kotlin.api.checks.InputFileContext import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.frontend.KotlinTree -@Deprecated("use withKaSession instead", ReplaceWith("withKaSession(action)")) -inline fun analyze(action: KaSession.() -> R) = withKaSession(action) - /** * Executes the given [action] in a [KaSession] context * providing access to [Kotlin Analysis API](https://kotl.in/analysis-api). diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ArrayHashCodeAndToStringCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ArrayHashCodeAndToStringCheck.kt index b1753b2a0..10e4e3b26 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ArrayHashCodeAndToStringCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ArrayHashCodeAndToStringCheck.kt @@ -27,7 +27,7 @@ import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.FunMatcherImpl import org.sonarsource.kotlin.api.checks.predictReceiverExpression import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val OBJECT_ARRAY_MATCHER = FunMatcher(qualifier = "kotlin.Array") { withNames("hashCode", "toString") @@ -78,7 +78,7 @@ class ArrayHashCodeAndToStringCheck : CallAbstractCheck() { } } - private fun receiverIsArrayOfArray(callExpression: KtCallExpression): Boolean = analyze { + private fun receiverIsArrayOfArray(callExpression: KtCallExpression): Boolean = withKaSession { val argument = callExpression.predictReceiverExpression()?.expressionType?.arrayElementType return ARRAY_QUALIFIERS.contains(argument?.symbol?.classId?.asFqNameString()) } diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AuthorisingNonAuthenticatedUsersCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AuthorisingNonAuthenticatedUsersCheck.kt index 49f3fada8..777edcb09 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AuthorisingNonAuthenticatedUsersCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AuthorisingNonAuthenticatedUsersCheck.kt @@ -31,7 +31,7 @@ import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val BUILDER = "android.security.keystore.KeyGenParameterSpec.Builder" @@ -52,14 +52,14 @@ class AuthorisingNonAuthenticatedUsersCheck : CallAbstractCheck() { matchedFun: FunMatcherImpl, kotlinFileContext: KotlinFileContext ) { - var receiver = analyze { callExpression.resolveToCall()?.successfulFunctionCallOrNull() } ?: return + var receiver = withKaSession { callExpression.resolveToCall()?.successfulFunctionCallOrNull() } ?: return var callElement = callExpression val secondaryLocations = mutableListOf() while (!KEY_GEN_BUILDER_MATCHER.matches(receiver)) { if (KEY_GEN_BUILDER_SET_AUTH_MATCHER.matches(receiver)) { - analyze { + withKaSession { if (receiver.argumentMapping.keys.toList().first().predictRuntimeBooleanValue() != false) return secondaryLocations.add(SecondaryLocation(kotlinFileContext.textRange(callElement.calleeExpression!!))) @@ -72,7 +72,7 @@ class AuthorisingNonAuthenticatedUsersCheck : CallAbstractCheck() { else -> null } ?: return - receiver = analyze { receiverExpression?.resolveToCall()?.singleFunctionCallOrNull() } ?: return + receiver = withKaSession { receiverExpression?.resolveToCall()?.singleFunctionCallOrNull() } ?: return } kotlinFileContext.reportIssue(callElement.calleeExpression!!, "Make sure authorizing non-authenticated users to use this key is safe here.", diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherBlockChainingCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherBlockChainingCheck.kt index 2e3721d1c..56389c3dc 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherBlockChainingCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherBlockChainingCheck.kt @@ -36,7 +36,7 @@ import org.sonarsource.kotlin.api.checks.predictRuntimeStringValue import org.sonarsource.kotlin.api.checks.predictRuntimeValueExpression import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val CIPHER_INIT_MATCHER = FunMatcher(qualifier = "javax.crypto.Cipher", name = "init") { withArguments(INT_TYPE, "java.security.Key", "java.security.spec.AlgorithmParameterSpec") @@ -69,7 +69,7 @@ class CipherBlockChainingCheck : CallAbstractCheck() { } } -private fun KtExpression.isInitializedWithToByteArray() = analyze { +private fun KtExpression.isInitializedWithToByteArray() = withKaSession { firstArgumentOfInitializer(IV_PARAMETER_SPEC_MATCHER) ?.predictRuntimeValueExpression() ?.resolveToCall() @@ -85,7 +85,7 @@ private fun KtExpression.isCBC() = ?.contains("CBC", ignoreCase = true) ?: false -private fun KtExpression.firstArgumentOfInitializer(matcher: FunMatcherImpl) = analyze { +private fun KtExpression.firstArgumentOfInitializer(matcher: FunMatcherImpl) = withKaSession { predictRuntimeValueExpression() .resolveToCall() ?.successfulFunctionCallOrNull()?.let { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherModeOperationCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherModeOperationCheck.kt index 33e780df3..84982678f 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherModeOperationCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherModeOperationCheck.kt @@ -29,7 +29,7 @@ import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val CIPHER_INIT_MATCHER = FunMatcher(qualifier = "javax.crypto.Cipher", name = "init") { withArguments(INT_TYPE, "java.security.Key", "java.security.spec.AlgorithmParameterSpec") @@ -82,7 +82,7 @@ private fun generateSecondaryLocations(secondaries: List, kotlinFile private fun KtExpression.getByteExpression(secondaries: MutableList) = with(predictRuntimeValueExpression(secondaries)) { - analyze { + withKaSession { this@with.resolveToCall() ?.successfulFunctionCallOrNull() ?.let { @@ -92,7 +92,7 @@ private fun KtExpression.getByteExpression(secondaries: MutableList) } } -private fun KtExpression.getGCMExpression(secondaries: MutableList) = analyze { +private fun KtExpression.getGCMExpression(secondaries: MutableList) = withKaSession { predictRuntimeValueExpression() .resolveToCall() ?.successfulFunctionCallOrNull() diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ClearTextProtocolCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ClearTextProtocolCheck.kt index 8758c8759..7322e5a79 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ClearTextProtocolCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ClearTextProtocolCheck.kt @@ -30,7 +30,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.visiting.KtTreeVisitor -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val CLEARTEXT_FQN = "okhttp3.ConnectionSpec.Companion.CLEARTEXT" @@ -81,7 +81,7 @@ class ClearTextProtocolCheck : CallAbstractCheck() { if (matchedFun in UNSAFE_CALLS_OK_HTTP) { analyzeOkHttpCall(kotlinFileContext, callExpression) } else if (matchedFun == ANDROID_SET_MIXED_CONTENT_MODE) { - analyze { + withKaSession { checkAndroidMixedContentArgument( kotlinFileContext, deparenthesize( @@ -94,7 +94,7 @@ class ClearTextProtocolCheck : CallAbstractCheck() { } override fun visitBinaryExpression(expression: KtBinaryExpression, ctx: KotlinFileContext) { - analyze { + withKaSession { val left = deparenthesize(expression.left) ?: return left.predictRuntimeValueExpression() if (expression.operationToken == KtTokens.EQ && @@ -121,7 +121,7 @@ private class OkHttpArgumentFinder( private val issueReporter: (KtSimpleNameExpression) -> Unit, ) : KtTreeVisitor() { override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { - analyze { + withKaSession { if (expression.mainReference.resolveToSymbol()?.importableFqName?.asString() == CLEARTEXT_FQN) issueReporter( expression ) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionInappropriateCallsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionInappropriateCallsCheck.kt index 7aa6bfa68..982a6fcd0 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionInappropriateCallsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionInappropriateCallsCheck.kt @@ -28,7 +28,7 @@ import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.FunMatcherImpl import org.sonarsource.kotlin.api.checks.predictReceiverExpression import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession const val qualifier = "kotlin.collections" @@ -78,7 +78,7 @@ class CollectionInappropriateCallsCheck : CallAbstractCheck() { matchedFun: FunMatcherImpl, kotlinFileContext: KotlinFileContext ) { - analyze { + withKaSession { // all evaluated methods have one and one only argument val arg = callExpression.valueArguments.first() var argType = arg.getArgumentExpression()?.expressionType ?: return diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionShouldBeImmutableCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionShouldBeImmutableCheck.kt index 5d2cf7414..e61cfd6e3 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionShouldBeImmutableCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionShouldBeImmutableCheck.kt @@ -29,7 +29,7 @@ import org.jetbrains.kotlin.js.descriptorUtils.getKotlinTypeFqName import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val nonMutatingFunctions = FunMatcher { withDefiningSupertypes( @@ -115,7 +115,7 @@ class CollectionShouldBeImmutableCheck : AbstractCheck() { private fun PsiElement?.isMutatingUsage(): Boolean { return when(this) { - is KtDotQualifiedExpression -> analyze { + is KtDotQualifiedExpression -> withKaSession { val resolveToCall = this@isMutatingUsage.resolveToCall() val kaCallableMemberCall: KaCallableMemberCall<*,*>? = @@ -129,7 +129,7 @@ class CollectionShouldBeImmutableCheck : AbstractCheck() { receiverType !in imMutableCollections } - is KtValueArgument -> analyze { + is KtValueArgument -> withKaSession { val resolveToCall = parent.parentOfType()?.resolveToCall() val parameterIndex = (parent as? KtValueArgumentList)?.arguments?.indexOf(this@isMutatingUsage) ?: -1 diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionSizeAndArrayLengthCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionSizeAndArrayLengthCheck.kt index 4f5d453b8..23a63ffce 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionSizeAndArrayLengthCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionSizeAndArrayLengthCheck.kt @@ -29,7 +29,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.predictRuntimeIntValue import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession val COLLECTION_SIZE_METHOD = FunMatcher(qualifier = "kotlin.collections.Collection", name = "size") { withNoArguments() @@ -73,7 +73,7 @@ class CollectionSizeAndArrayLengthCheck : AbstractCheck() { opWithoutEq: KtSingleValueToken, ): String? { if (testedExpr is KtDotQualifiedExpression && - analyze { + withKaSession { val functionCall = testedExpr.resolveToCall()?.singleVariableAccessCall() ?: return null MATCHERS.any { it.matches(functionCall) } }) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutineScopeFunSuspendingCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutineScopeFunSuspendingCheck.kt index 63d6f32e2..7e4e937ca 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutineScopeFunSuspendingCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutineScopeFunSuspendingCheck.kt @@ -24,7 +24,7 @@ import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.checks.suspendModifier import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val COROUTINE_SCOPE = "kotlinx.coroutines.CoroutineScope" private const val MESSAGE = "Extension functions on CoroutineScope should not be suspending." @@ -35,7 +35,7 @@ class CoroutineScopeFunSuspendingCheck : AbstractCheck() { // Only applicable for suspending extension functions val suspendModifier = function.suspendModifier() ?: return val receiverType = function.receiverTypeReference ?: return - analyze { + withKaSession { receiverType.type.allSupertypes if (receiverType.type.symbol?.classId?.asFqNameString() == COROUTINE_SCOPE || receiverType.type.allSupertypes.any { it.symbol?.classId?.asFqNameString() == COROUTINE_SCOPE } diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutinesTimeoutApiUnusedCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutinesTimeoutApiUnusedCheck.kt index 7c299d410..8efda11c1 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutinesTimeoutApiUnusedCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutinesTimeoutApiUnusedCheck.kt @@ -32,7 +32,7 @@ import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val MESSAGE = """Use "withTimeoutOrNull { }" instead of manual delayed cancellation.""" @@ -53,7 +53,7 @@ class CoroutinesTimeoutApiUnusedCheck : CallAbstractCheck() { ) { val cancelCallCalleeExpression = callExpression.calleeExpression ?: return - val kaSymbol = analyze { + val kaSymbol = withKaSession { (callExpression.context as? KtDotQualifiedExpression) ?.receiverExpression?.mainReference?.resolveToSymbol() } ?: return @@ -78,7 +78,7 @@ class CoroutinesTimeoutApiUnusedCheck : CallAbstractCheck() { ) } - private fun asDelayCallIfMatching(element: PsiElement): KtExpression? = analyze { + private fun asDelayCallIfMatching(element: PsiElement): KtExpression? = withKaSession { if (element is KtCallExpression && element.resolveToCall()?.successfulFunctionCallOrNull() matches DELAY_MATCHER) { element.calleeExpression @@ -88,7 +88,7 @@ class CoroutinesTimeoutApiUnusedCheck : CallAbstractCheck() { private fun asInitializerCallIfMatching( element: PsiElement, targetInitializer: KaSymbol?, - ): KtExpression? = analyze { + ): KtExpression? = withKaSession { if (element is KtProperty && element.symbol == targetInitializer) { val initializer = element.initializer as? KtCallExpression ?: return null if (initializer.resolveToCall()?.successfulFunctionCallOrNull() matches LAUNCH_ASYNC_MATCHER) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DelegationPatternCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DelegationPatternCheck.kt index 7376ac0a1..fcbdadb85 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DelegationPatternCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DelegationPatternCheck.kt @@ -27,13 +27,13 @@ import org.jetbrains.kotlin.psi.psiUtil.isPublic import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S6514") class DelegationPatternCheck : AbstractCheck() { override fun visitClassOrObject(classOrObject: KtClassOrObject, context: KotlinFileContext) { - analyze { + withKaSession { val classSymbol = classOrObject.classSymbol ?: return if (classSymbol.classKind == KaClassKind.INTERFACE) return val superInterfaces: Set = classSymbol.getSuperInterfaces() @@ -67,7 +67,7 @@ class DelegationPatternCheck : AbstractCheck() { private fun isFunctionInInterface( function: KtNamedFunction, superInterface1: KaClassSymbol -): Boolean = analyze { +): Boolean = withKaSession { val classDeclaration = superInterface1.psi as? KtClass ?: return false return classDeclaration.declarations.any { it is KtNamedFunction && haveCompatibleFunctionSignature(it.symbol, function.symbol) @@ -77,7 +77,7 @@ private fun isFunctionInInterface( private fun haveCompatibleFunctionSignature( function1: KaFunctionSymbol, function2: KaFunctionSymbol, -) = analyze { +) = withKaSession { function1.returnType.sameOrTypeParam(function2.returnType) && function1.name == function2.name && function1.valueParameters.allPaired(function2.valueParameters) { p1, p2 -> @@ -85,7 +85,7 @@ private fun haveCompatibleFunctionSignature( } } -fun KaType.sameOrTypeParam(other: KaType): Boolean = analyze { +fun KaType.sameOrTypeParam(other: KaType): Boolean = withKaSession { if (this@sameOrTypeParam is KaTypeParameterType && other is KaTypeParameterType) return true return symbol != null && other.symbol != null && symbol == other.symbol } @@ -98,7 +98,7 @@ fun getCommonSuperInterfaces(superInterfaces: Set, otherType: KaT fun KaType.getSuperInterfaces(): Set = (symbol as? KaClassSymbol)?.getSuperInterfaces() ?: emptySet() -fun KaClassSymbol.getSuperInterfaces(): Set = analyze { +fun KaClassSymbol.getSuperInterfaces(): Set = withKaSession { val superTypes = this@getSuperInterfaces.superTypes.filter { !it.isAnyType } val symbols: Collection = superTypes.mapNotNull { it.symbol as? KaClassSymbol } val hierarchy: List = superTypes.flatMap { it.getSuperInterfaces() } @@ -107,7 +107,7 @@ fun KaClassSymbol.getSuperInterfaces(): Set = analyze { .toSet() } -private fun getDelegeeOrNull(function: KtNamedFunction): KtNameReferenceExpression? = analyze { +private fun getDelegeeOrNull(function: KtNamedFunction): KtNameReferenceExpression? = withKaSession { val qualifiedCallExpression = getFunctionSingleBodyElementOrNull(function) as? KtDotQualifiedExpression ?: return null val receiverExpression = qualifiedCallExpression.receiverExpression as? KtNameReferenceExpression ?: return null val callExpression = qualifiedCallExpression.selectorExpression as? KtCallExpression ?: return null @@ -120,7 +120,7 @@ private fun getDelegeeOrNull(function: KtNamedFunction): KtNameReferenceExpressi }) receiverExpression else null } -private fun isDelegatedParameter(parameter: KtParameter, arguments: KtValueArgument): Boolean = analyze { +private fun isDelegatedParameter(parameter: KtParameter, arguments: KtValueArgument): Boolean = withKaSession { val argumentExpression = arguments.getArgumentExpression() as? KtNameReferenceExpression ?: return false if (parameter.name != argumentExpression.getReferencedName()) return false val argumentType = argumentExpression.determineType() ?: return false diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeCheck.kt index 5a49f0517..a6aedbca1 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeCheck.kt @@ -27,14 +27,14 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.annotatedElement import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S1133") class DeprecatedCodeCheck : AbstractCheck() { override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry, context: KotlinFileContext) { - analyze { + withKaSession { val annotationType = annotationEntry.typeReference?.type?.symbol?.classId?.asFqNameString() if ("kotlin.Deprecated" == annotationType) { context.reportIssue( diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicateBranchCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicateBranchCheck.kt index c60dd9061..e1563eb20 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicateBranchCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicateBranchCheck.kt @@ -24,7 +24,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S1871") class DuplicateBranchCheck : AbstractBranchDuplication() { @@ -52,11 +52,11 @@ class DuplicateBranchCheck : AbstractBranchDuplication() { } } -private fun KtQualifiedExpression.hasSameSignature(other: KtQualifiedExpression): Boolean = analyze { +private fun KtQualifiedExpression.hasSameSignature(other: KtQualifiedExpression): Boolean = withKaSession { this@hasSameSignature.determineSignature() == other.determineSignature() } -private fun KtQualifiedExpression?.determineSignature(): KaSymbol? = analyze { +private fun KtQualifiedExpression?.determineSignature(): KaSymbol? = withKaSession { when (val selectorExpr = this@determineSignature?.selectorExpression) { is KtCallExpression -> selectorExpr.getCallNameExpression()?.mainReference?.resolveToSymbol() diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyLineRegexCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyLineRegexCheck.kt index 745f4827e..3bf31d490 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyLineRegexCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyLineRegexCheck.kt @@ -44,7 +44,7 @@ import org.sonarsource.kotlin.api.regex.RegexContext import org.sonarsource.kotlin.api.regex.TO_REGEX_MATCHER import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.frontend.secondaryOf -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val MESSAGE = "Remove MULTILINE mode or change the regex." @@ -99,7 +99,7 @@ class EmptyLineRegexCheck : AbstractRegexCheck() { private fun getSecondariesForToRegex( callExpression: KtCallExpression - ): Pair, KtElement?> = analyze { + ): Pair, KtElement?> = withKaSession { getSecondaries(callExpression.parent?.parent, ::getStringInRegexFind) to (callExpression.parent as? KtExpression)?.resolveToCall() ?.successfulFunctionCallOrNull()?.getReceiverExpression() @@ -199,7 +199,7 @@ private fun isNonCapturingWithoutChild(tree: RegexTree): Boolean { return tree.`is`(RegexTree.Kind.NON_CAPTURING_GROUP) && (tree as NonCapturingGroupTree).element == null } -private fun getStringInMatcherFind(ref: KtElement): KtExpression? = analyze { +private fun getStringInMatcherFind(ref: KtElement): KtExpression? = withKaSession { val resolvedCall = (ref.parent as? KtExpression)?.resolveToCall()?.successfulFunctionCallOrNull() ?: return null @@ -219,7 +219,7 @@ private fun getStringInMatcherFind(ref: KtElement): KtExpression? = analyze { } private fun getStringInRegexFind(ref: KtElement): KtExpression? { - val resolvedCall = analyze { + val resolvedCall = withKaSession { (ref.parent as? KtExpression)?.resolveToCall()?.successfulFunctionCallOrNull() ?: return null } return if (resolvedCall matches REGEX_FIND) extractArgument(resolvedCall) else null @@ -245,7 +245,7 @@ private fun KtExpression.canBeEmpty(): Boolean = val runtimeStringValue = deparenthesized.predictRuntimeStringValue() runtimeStringValue?.isEmpty() ?: deparenthesized.findUsages(allUsages = true) { - analyze { + withKaSession { (it.parent as? KtExpression)?.resolveToCall() ?.successfulFunctionCallOrNull() matches STRING_IS_EMPTY || (it.parent as? KtBinaryExpression).isEmptinessCheck() @@ -271,5 +271,5 @@ fun KtElement.getParentCall(): KaFunctionCall<*>? { val parent = PsiTreeUtil.getParentOfType(this, *callExpressionTypes) - return analyze { parent?.resolveToCall()?.successfulFunctionCallOrNull() } + return withKaSession { parent?.resolveToCall()?.successfulFunctionCallOrNull() } } diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EncryptionAlgorithmCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EncryptionAlgorithmCheck.kt index 73f89fd25..7222afda2 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EncryptionAlgorithmCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EncryptionAlgorithmCheck.kt @@ -25,7 +25,7 @@ import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val ALGORITHM_PATTERN = Regex("([^/]+)/([^/]+)/([^/]+)") @@ -75,7 +75,7 @@ private fun String.getInsecureAlgorithmMessage(): String? { ?: return "Use secure mode and padding scheme." } -private fun KtExpression.predictRuntimeStringValueWithSecondaries() = analyze { +private fun KtExpression.predictRuntimeStringValueWithSecondaries() = withKaSession { mutableListOf().let { predictRuntimeValueExpression(it) .stringValue(it) to it diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsArgumentTypeCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsArgumentTypeCheck.kt index 2a04ebd11..984c60397 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsArgumentTypeCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsArgumentTypeCheck.kt @@ -39,7 +39,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.EQUALS_METHOD_NAME import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val EQUALS_MATCHER = FunMatcher { name = EQUALS_METHOD_NAME @@ -104,7 +104,7 @@ class EqualsArgumentTypeCheck : AbstractCheck() { isExpressionCorrectType(it.typeReference!!, klass) } - private fun isExpressionCorrectType(typeReference: KtTypeReference, klass: KtClass): Boolean = analyze { + private fun isExpressionCorrectType(typeReference: KtTypeReference, klass: KtClass): Boolean = withKaSession { val name = typeReference.nameForReceiverLabel() val parentNames = klass.superTypeListEntries.mapNotNull { it.typeReference!!.nameForReceiverLabel() } return klass.name == name || parentNames.contains(name) || diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExternalAndroidStorageAccessCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExternalAndroidStorageAccessCheck.kt index eebb35b56..e42145aa1 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExternalAndroidStorageAccessCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExternalAndroidStorageAccessCheck.kt @@ -29,7 +29,7 @@ import org.sonarsource.kotlin.api.checks.CallAbstractCheck import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.FunMatcherImpl import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val MESSAGE = "Make sure accessing the Android external storage is safe here." @@ -97,7 +97,7 @@ class ExternalAndroidStorageAccessCheck : CallAbstractCheck() { override fun visitReferenceExpression(expression: KtReferenceExpression, kotlinFileContext: KotlinFileContext) { if (expression is KtNameReferenceExpression && expression.getReferencedName() in HOTSPOT_PROPS_NAMES) { - analyze { + withKaSession { val successfulVariableAccessCall = expression.resolveToCall()?.successfulVariableAccessCall() if (successfulVariableAccessCall != null && HOTSPOT_PROPS_MATCHERS.any { it.matches(successfulVariableAccessCall) }) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FinalFlowOperationCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FinalFlowOperationCheck.kt index ef69c74f8..b073272a7 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FinalFlowOperationCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FinalFlowOperationCheck.kt @@ -24,7 +24,7 @@ import org.sonarsource.kotlin.api.checks.COROUTINES_FLOW 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.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val MESSAGE = "Unused coroutines Flow." @@ -33,7 +33,7 @@ class FinalFlowOperationCheck : CallAbstractCheck() { override val functionsToVisit = listOf(FunMatcher(returnType = COROUTINES_FLOW)) override fun visitFunctionCall(callExpression: KtCallExpression, resolvedCall: KaFunctionCall<*>, kotlinFileContext: KotlinFileContext) { - analyze { + withKaSession { if (!callExpression.isUsedAsExpression) { kotlinFileContext.reportIssue(callExpression.calleeExpression!!, MESSAGE) } diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IgnoredOperationStatusCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IgnoredOperationStatusCheck.kt index c35e3dbfc..484cbc1b2 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IgnoredOperationStatusCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IgnoredOperationStatusCheck.kt @@ -34,7 +34,7 @@ import org.sonarsource.kotlin.api.checks.CallAbstractCheck import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.simpleName import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S899") class IgnoredOperationStatusCheck : CallAbstractCheck() { @@ -64,7 +64,7 @@ class IgnoredOperationStatusCheck : CallAbstractCheck() { }, ) - override fun visitFunctionCall(callExpression: KtCallExpression, resolvedCall: KaFunctionCall<*>, kotlinFileContext: KotlinFileContext) = analyze { + override fun visitFunctionCall(callExpression: KtCallExpression, resolvedCall: KaFunctionCall<*>, kotlinFileContext: KotlinFileContext) = withKaSession { if (!callExpression.isUsedAsExpression) { // resolvedCall.resultingDescriptor?.let { resultingDescriptor -> val name = resolvedCall.partiallyAppliedSymbol.signature.symbol.name @@ -82,7 +82,7 @@ class IgnoredOperationStatusCheck : CallAbstractCheck() { * Replacement for [org.sonarsource.kotlin.api.checks.simpleName] ? */ @OptIn(KaExperimentalApi::class) - private fun KaType.simpleName(): String? = analyze { + private fun KaType.simpleName(): String? = withKaSession { this@simpleName.lowerBoundIfFlexible().symbol?.name?.asString() // this@simpleName.render( // KaTypeRendererForSource.WITH_SHORT_NAMES, diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InjectableDispatchersCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InjectableDispatchersCheck.kt index 5540cbd87..39b22163d 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InjectableDispatchersCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InjectableDispatchersCheck.kt @@ -26,7 +26,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.frontend.secondaryOf -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val MESSAGE = "Avoid hardcoded dispatchers." private const val DISPATCHERS_OBJECT = "$KOTLINX_COROUTINES_PACKAGE.Dispatchers" @@ -46,7 +46,7 @@ class InjectableDispatchersCheck : CallAbstractCheck() { val argExpr = arguments.first() val argValueExpr = argExpr.predictRuntimeValueExpression() as? KtQualifiedExpression ?: return - val variableAccessCall: KaVariableAccessCall = analyze { + val variableAccessCall: KaVariableAccessCall = withKaSession { argValueExpr.resolveToCall()?.singleVariableAccessCall() ?: return } val receiverFqn = (variableAccessCall.partiallyAppliedSymbol.dispatchReceiver?.type as? KaClassType) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InterfaceCouldBeFunctionalCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InterfaceCouldBeFunctionalCheck.kt index 9d5c0ee03..b09b0a203 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InterfaceCouldBeFunctionalCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InterfaceCouldBeFunctionalCheck.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.psi.KtProperty import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S6517") class InterfaceCouldBeFunctionalCheck : AbstractCheck() { @@ -65,6 +65,6 @@ private fun hasExactlyOneFunctionAndNoProperties(klass: KtClass): Boolean { } && functionCount > 0 } -private fun isFunctionalInterfaceAnnotation(annotation: KtAnnotationEntry): Boolean = analyze { +private fun isFunctionalInterfaceAnnotation(annotation: KtAnnotationEntry): Boolean = withKaSession { annotation.typeReference?.type?.symbol?.classId?.asFqNameString() == "java.lang.FunctionalInterface" } diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IsInstanceMethodCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IsInstanceMethodCheck.kt index 87525e43b..4f59fb808 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IsInstanceMethodCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IsInstanceMethodCheck.kt @@ -36,7 +36,7 @@ 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.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val JAVA_CLASS_KEYWORDS = listOf("java", "javaClass") @@ -81,7 +81,7 @@ class IsInstanceMethodCheck : CallAbstractCheck() { // TODO fails in K2 mode private fun KtReferenceExpression.isClass(ctx: KotlinFileContext): Boolean { val expression = this - analyze { + withKaSession { return expression.mainReference.resolveToSymbol() is KaClassSymbol } } diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MainSafeCoroutinesCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MainSafeCoroutinesCheck.kt index 714a423c0..b0c65f92a 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MainSafeCoroutinesCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MainSafeCoroutinesCheck.kt @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession val THREAD_SLEEP_MATCHER = FunMatcher(qualifier = "java.lang.Thread", name = "sleep") @@ -68,7 +68,7 @@ class MainSafeCoroutinesCheck : AbstractCheck() { } } - private fun KtElement.reportBlockingFunctionCalls(context: KotlinFileContext) = analyze { + private fun KtElement.reportBlockingFunctionCalls(context: KotlinFileContext) = withKaSession { forEachDescendantOfType { call -> val resolvedCall1 = call.resolveToCall()?.successfulFunctionCallOrNull() if (resolvedCall1 matches THREAD_SLEEP_MATCHER) { @@ -87,7 +87,7 @@ class MainSafeCoroutinesCheck : AbstractCheck() { } } -private fun KtCallExpression.isInsideNonSafeDispatcher(): Boolean = analyze { +private fun KtCallExpression.isInsideNonSafeDispatcher(): Boolean = withKaSession { var parentCallExpr: KtElement? = getParentCallExpr() ?: return true var resolvedCall1 = parentCallExpr?.resolveToCall()?.successfulFunctionCallOrNull() ?: return false @@ -103,7 +103,7 @@ private fun KtCallExpression.isInsideNonSafeDispatcher(): Boolean = analyze { return resolvedCall1.usesNonSafeDispatcher() } -private fun KaFunctionCall<*>.usesNonSafeDispatcher(): Boolean = analyze { +private fun KaFunctionCall<*>.usesNonSafeDispatcher(): Boolean = withKaSession { val arg = argumentMapping.entries .find { (_, signature) -> signature.name.asString() == "context" } ?.key @@ -116,7 +116,7 @@ private fun KaFunctionCall<*>.usesNonSafeDispatcher(): Boolean = analyze { || argValue == "$KOTLINX_COROUTINES_PACKAGE.Dispatchers.Default" } -private fun KtLambdaArgument.isSuspending() = analyze { +private fun KtLambdaArgument.isSuspending() = withKaSession { (parent as? KtCallExpression) ?.resolveToCall() ?.successfulFunctionCallOrNull() diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MapValuesShouldBeAccessedSafelyCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MapValuesShouldBeAccessedSafelyCheck.kt index c2d3963c8..7cec5cb7d 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MapValuesShouldBeAccessedSafelyCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MapValuesShouldBeAccessedSafelyCheck.kt @@ -30,7 +30,7 @@ import org.sonarsource.kotlin.api.checks.CallAbstractCheck import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.reporting.message import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S6611") class MapValuesShouldBeAccessedSafelyCheck : CallAbstractCheck() { @@ -65,7 +65,7 @@ class MapValuesShouldBeAccessedSafelyCheck : CallAbstractCheck() { } } - private fun checkSuperType(arrayAccessExpression: KtArrayAccessExpression): Boolean = analyze { + private fun checkSuperType(arrayAccessExpression: KtArrayAccessExpression): Boolean = withKaSession { val type = arrayAccessExpression.arrayExpression?.expressionType ?: return false if (checkIfSubtype(type)) return true return type.allSupertypes.any { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MobileDatabaseEncryptionKeysCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MobileDatabaseEncryptionKeysCheck.kt index 060c4233a..bc206e695 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MobileDatabaseEncryptionKeysCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MobileDatabaseEncryptionKeysCheck.kt @@ -36,7 +36,7 @@ import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val SQLITE = "net.sqlcipher.database.SQLiteDatabase" private const val ENCRYPTION_KEY = "encryptionKey" @@ -101,7 +101,7 @@ private fun KtElement.isHardCoded(secondaries: MutableList): Boolean } fun KtCallExpression.returnsHardcoded(secondaries: MutableList): Boolean = - analyze { + withKaSession { val resultingDescriptor = this@returnsHardcoded.resolveToCall()?.successfulFunctionCallOrNull() ?: return false val declaration = resultingDescriptor.partiallyAppliedSymbol.symbol.psi as? KtNamedFunction ?: return false diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PreparedStatementAndResultSetCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PreparedStatementAndResultSetCheck.kt index ab62e5ed3..1698de6c5 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PreparedStatementAndResultSetCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PreparedStatementAndResultSetCheck.kt @@ -31,7 +31,7 @@ import org.sonarsource.kotlin.api.checks.predictRuntimeIntValue import org.sonarsource.kotlin.api.checks.predictRuntimeStringValue import org.sonarsource.kotlin.api.checks.predictRuntimeValueExpression import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val PREPARE_STATEMENT = FunMatcher(qualifier = "java.sql.Connection", name = "prepareStatement") @@ -82,7 +82,7 @@ class PreparedStatementAndResultSetCheck : CallAbstractCheck() { } } -private fun getNumberOfParameters(receiver: KtExpression) = analyze { +private fun getNumberOfParameters(receiver: KtExpression) = withKaSession { receiver.predictRuntimeValueExpression() .resolveToCall()?.successfulFunctionCallOrNull() ?.let { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PropertyGetterAndSetterUsageCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PropertyGetterAndSetterUsageCheck.kt index dee79468f..c03eca83f 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PropertyGetterAndSetterUsageCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PropertyGetterAndSetterUsageCheck.kt @@ -34,7 +34,7 @@ import org.sonarsource.kotlin.api.checks.isAbstract import org.sonarsource.kotlin.api.checks.overrides import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.frontend.secondaryOf -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val GETTER_PREFIX = Regex("""^(get|is)\p{javaUpperCase}""") private val SETTER_PREFIX = Regex("""^set\p{javaUpperCase}""") @@ -56,7 +56,7 @@ class PropertyGetterAndSetterUsageCheck : AbstractCheck() { private fun checkProperty( prop: KtProperty, javaAccessors: Map>, ctx: KotlinFileContext - ): Unit = analyze { + ): Unit = withKaSession { prop.nameIdentifier?.let { propIdentifier -> prop.typeReference?.type?.let { val propName = prop.name!! @@ -83,7 +83,7 @@ private fun isGetterOrSetter(parameterCount: Int, functionName: String) = private fun findJavaStyleGetterFunc( propName: String, kaType: KaType, javaAccessors: Map> -): KtNamedFunction? = analyze { +): KtNamedFunction? = withKaSession { val capitalizedName = capitalize(propName) val functionsPrefixedByIs = if (kaType.matches("kotlin.Boolean")) { javaAccessors.getOrElse("is${capitalizedName}") { emptyList() } @@ -95,7 +95,7 @@ private fun findJavaStyleGetterFunc( .unambiguousFunction() } -private fun parameterMatchesType(parameter: KtParameter, kaType: KaType): Boolean = analyze { +private fun parameterMatchesType(parameter: KtParameter, kaType: KaType): Boolean = withKaSession { return !parameter.isVarArg && parameter.typeReference?.type?.semanticallyEquals(kaType) ?: false } @@ -103,7 +103,7 @@ private fun findJavaStyleSetterFunc( propName: String, kaType: KaType, javaAccessors: Map> -): KtNamedFunction? = analyze { +): KtNamedFunction? = withKaSession { javaAccessors.getOrElse("set${capitalize(propName)}") { emptyList() } .filter { it.returnType.matches("kotlin.Unit") } // isGetterOrSetter ensures setters have: valueParameters.size == 1 diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PseudoRandomCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PseudoRandomCheck.kt index 14ce387c1..055cd8b8c 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PseudoRandomCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PseudoRandomCheck.kt @@ -30,7 +30,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val MESSAGE = "Make sure that using this pseudorandom number generator is safe here." @@ -56,8 +56,8 @@ private val RANDOM_CONSTRUCTOR_TYPES = setOf( @Rule(key = "S2245") class PseudoRandomCheck : AbstractCheck() { - override fun visitCallExpression(expression: KtCallExpression, kotlinFileContext: KotlinFileContext) = analyze { - val calleeExpression = expression.calleeExpression ?: return@analyze + override fun visitCallExpression(expression: KtCallExpression, kotlinFileContext: KotlinFileContext) = withKaSession { + val calleeExpression = expression.calleeExpression ?: return@withKaSession if (MATH_RANDOM_MATCHER.matches(expression) || KOTLIN_RANDOM_MATCHER.matches(expression)) kotlinFileContext.reportIssue(calleeExpression, MESSAGE) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantSuspendModifierCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantSuspendModifierCheck.kt index 8b6d67aa0..ee3af72ae 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantSuspendModifierCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantSuspendModifierCheck.kt @@ -28,12 +28,12 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.overrides import org.sonarsource.kotlin.api.checks.suspendModifier import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S6318") class RedundantSuspendModifierCheck : AbstractCheck() { - override fun visitNamedFunction(function: KtNamedFunction, context: KotlinFileContext) = analyze { + override fun visitNamedFunction(function: KtNamedFunction, context: KotlinFileContext) = withKaSession { val suspendModifier = function.suspendModifier() ?: return with(function) { if (hasBody() && !overrides()) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReplaceGuavaWithKotlinCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReplaceGuavaWithKotlinCheck.kt index 0ca51117c..43a7b1515 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReplaceGuavaWithKotlinCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReplaceGuavaWithKotlinCheck.kt @@ -38,7 +38,7 @@ import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.FunMatcherImpl import org.sonarsource.kotlin.api.checks.overrides import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val GUAVA_OPTIONAL = "com.google.common.base.Optional" @@ -130,7 +130,7 @@ class ReplaceGuavaWithKotlinCheck : CallAbstractCheck() { else -> false } - private fun KtParameter.hasReferencesIn(elementToVisit: KtElement?): Boolean = analyze { + private fun KtParameter.hasReferencesIn(elementToVisit: KtElement?): Boolean = withKaSession { val variableSymbol = this@hasReferencesIn.symbol return elementToVisit?.collectDescendantsOfType() { expression -> @@ -138,7 +138,7 @@ class ReplaceGuavaWithKotlinCheck : CallAbstractCheck() { }?.isNotEmpty() ?: false } - private fun KtTypeReference.ifTypeReplacement(action: (String) -> Unit) = analyze { + private fun KtTypeReference.ifTypeReplacement(action: (String) -> Unit) = withKaSession { this@ifTypeReplacement.type.symbol?.classId?.asFqNameString() ?.let { REPLACEMENT_TYPES[it]?.let(action) } } diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RobustCryptographicKeysCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RobustCryptographicKeysCheck.kt index bd2de8989..2b58a2e25 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RobustCryptographicKeysCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RobustCryptographicKeysCheck.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.psi.KtCallExpression import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val ASYMMETRIC_INITIALIZE_MATCHER = FunMatcher { qualifier = "java.security.KeyPairGenerator" @@ -67,7 +67,7 @@ private const val EC_MIN_KEY_SIZE = 224 class RobustCryptographicKeysCheck : AbstractCheck() { override fun visitCallExpression(callExpr: KtCallExpression, context: KotlinFileContext) { - analyze { + withKaSession { callExpr.resolveToCall()?.successfulFunctionCallOrNull()?.let { resolvedCall -> when { resolvedCall matches ASYMMETRIC_INITIALIZE_MATCHER -> handleKeyGeneratorAndKeyPairGenerator( @@ -108,7 +108,7 @@ class RobustCryptographicKeysCheck : AbstractCheck() { getInstanceMatcher: FunMatcherImpl, context: KotlinFileContext, ) { - analyze { + withKaSession { val keySizeExpression = resolvedCall.getFirstArgumentExpression() ?: return val keySize = keySizeExpression.predictRuntimeIntValue() if (keySize != null && keySize < minKeySize) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SamConversionCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SamConversionCheck.kt index b8ab1d848..8e706ba0c 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SamConversionCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SamConversionCheck.kt @@ -25,7 +25,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.merge import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S6516") class SamConversionCheck : AbstractCheck() { @@ -34,7 +34,7 @@ class SamConversionCheck : AbstractCheck() { override fun visitObjectDeclaration(declaration: KtObjectDeclaration, context: KotlinFileContext) { val superTypeEntry = declaration.superTypeListEntries.singleOrNull() ?: return - analyze { + withKaSession { val typeReference = superTypeEntry.typeReference ?: return if ((typeReference.type.isFunctionalInterface || typeReference.type.functionTypeKind != null) && declaration.hasExactlyOneFunctionAndNoProperties()) { val textRange = context.merge(declaration.getDeclarationKeyword()!!, superTypeEntry) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt index ecd921528..c13746de5 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt @@ -28,7 +28,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.determineType import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val CERTIFICATE_EXCEPTION = "java.security.cert.CertificateException" @@ -89,13 +89,13 @@ class ServerCertificateCheck : AbstractCheck() { private var throwFound: Boolean = false private var catchFound: Boolean = false - override fun visitThrowExpression(expression: KtThrowExpression) = analyze { + override fun visitThrowExpression(expression: KtThrowExpression) = withKaSession { throwFound = throwFound || CERTIFICATE_EXCEPTION == expression.thrownExpression?.expressionType?.symbol?.classId?.asFqNameString() } - override fun visitCatchSection(catchClause: KtCatchClause) = analyze { + override fun visitCatchSection(catchClause: KtCatchClause) = withKaSession { catchFound = catchFound || CERTIFICATE_EXCEPTION == catchClause.catchParameter?.determineType()?.symbol?.classId?.asFqNameString() diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifyFilteringBeforeTerminalOperationCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifyFilteringBeforeTerminalOperationCheck.kt index 21072d2f0..d99294221 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifyFilteringBeforeTerminalOperationCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifyFilteringBeforeTerminalOperationCheck.kt @@ -28,7 +28,7 @@ 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 +import org.sonarsource.kotlin.api.visiting.withKaSession private const val KOTLIN_COLLECTIONS_QUALIFIER = "kotlin.collections" private val FILTER_MATCHER = FunMatcher(qualifier = KOTLIN_COLLECTIONS_QUALIFIER, name = "filter") { withArguments("kotlin.Function1") } @@ -42,7 +42,7 @@ class SimplifyFilteringBeforeTerminalOperationCheck : CallAbstractCheck() { } ) - override fun visitFunctionCall(callExpression: KtCallExpression, resolvedCall: KaFunctionCall<*>, kotlinFileContext: KotlinFileContext): Unit = analyze { + override fun visitFunctionCall(callExpression: KtCallExpression, resolvedCall: KaFunctionCall<*>, kotlinFileContext: KotlinFileContext): Unit = withKaSession { val x = callExpression.parent .let { it as? KtDotQualifiedExpression } ?.receiverExpression diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifySizeExpressionCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifySizeExpressionCheck.kt index 260d321bd..a7fedd587 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifySizeExpressionCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifySizeExpressionCheck.kt @@ -44,7 +44,7 @@ import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.FunMatcherImpl import org.sonarsource.kotlin.api.checks.predictRuntimeIntValue import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val PACKAGE_KOTLIN_COLLECTION = "kotlin.collections" private const val PACKAGE_KOTLIN_TEXT = "kotlin.text" @@ -103,7 +103,7 @@ class SimplifySizeExpressionCheck : CallAbstractCheck() { override fun visitReferenceExpression( expression: KtReferenceExpression, kotlinFileContext: KotlinFileContext, - ) = analyze { + ) = withKaSession { val resolvedCall = expression.resolveToCall()?.successfulVariableAccessCall() ?: return if (sizeFieldMatcher.matches(resolvedCall) || lengthFieldMatcher.matches(resolvedCall)) { checkSizeTest(expression, kotlinFileContext) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SingletonPatternCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SingletonPatternCheck.kt index dbac27310..0afaf138f 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SingletonPatternCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SingletonPatternCheck.kt @@ -38,7 +38,7 @@ import org.sonarsource.kotlin.api.checks.ConstructorMatcher import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.visiting.KtTreeVisitor -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val lazyInitializationMatcher = FunMatcher( name = "lazy", @@ -97,7 +97,7 @@ private class SingleConstructorCallExtractor( override fun visitCallExpression(expression: KtCallExpression) { if (singletonClassCandidates.isEmpty() || !constructorMatcher.matches(expression)) return - analyze { + withKaSession { val kaConstructorSymbol = expression.resolveToCall()?.successfulFunctionCallOrNull() ?.partiallyAppliedSymbol?.symbol as? KaConstructorSymbol ?: return val fqName = kaConstructorSymbol.containingClassId?.asFqNameString() ?: return diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StreamNotConsumedCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StreamNotConsumedCheck.kt index 904da2fb2..a0d6a3187 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StreamNotConsumedCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StreamNotConsumedCheck.kt @@ -24,7 +24,7 @@ import org.sonarsource.kotlin.api.checks.CallAbstractCheck import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.FunMatcherImpl import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val STREAM_MESSAGE = "Refactor the code so this stream pipeline is used." @@ -76,7 +76,7 @@ class StreamNotConsumedCheck : CallAbstractCheck() { resolvedCall: KaFunctionCall<*>, matchedFun: FunMatcherImpl, kotlinFileContext: KotlinFileContext, - ) = analyze { + ) = withKaSession { if (!callExpression.isUsedAsExpression) { val message = if (matchedFun == SEQUENCE_MATCHER) SEQUENCE_MESSAGE else STREAM_MESSAGE; kotlinFileContext.reportIssue(callExpression.calleeExpression!!, message) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StructuredConcurrencyPrinciplesCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StructuredConcurrencyPrinciplesCheck.kt index c226e7703..b310321d0 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StructuredConcurrencyPrinciplesCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StructuredConcurrencyPrinciplesCheck.kt @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val JOB_CONSTRUCTOR = FunMatcher(qualifier = KOTLINX_COROUTINES_PACKAGE, name = "Job") private val SUPERVISOR_JOB_CONSTRUCTOR = FunMatcher(qualifier = KOTLINX_COROUTINES_PACKAGE, name = "SupervisorJob") @@ -74,7 +74,7 @@ private fun KtExpression.checkOptInDelicateApi(): Boolean { private fun MutableList?.isAnnotatedWithOptInDelicateApi() = this?.let { - analyze { + withKaSession { it.any { annotation -> val typeFqn = annotation.typeReference?.determineTypeAsString() typeFqn == "kotlinx.coroutines.DelicateCoroutinesApi" || diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SuspendingFunCallerDispatcherCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SuspendingFunCallerDispatcherCheck.kt index f787f97f6..71af4db2f 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SuspendingFunCallerDispatcherCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SuspendingFunCallerDispatcherCheck.kt @@ -30,7 +30,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.CallAbstractCheck import org.sonarsource.kotlin.api.checks.FUNS_ACCEPTING_DISPATCHERS import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S6311") class SuspendingFunCallerDispatcherCheck : CallAbstractCheck() { @@ -41,7 +41,7 @@ class SuspendingFunCallerDispatcherCheck : CallAbstractCheck() { resolvedCall: KaFunctionCall<*>, // resolvedCall: ResolvedCall<*>, kotlinFileContext: KotlinFileContext, - ) = analyze { + ) = withKaSession { val bindingContext = kotlinFileContext.bindingContext // val arguments = resolvedCall.valueArgumentsByIndex diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedDatabaseOnMobileCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedDatabaseOnMobileCheck.kt index 0075f5722..fafe68b45 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedDatabaseOnMobileCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedDatabaseOnMobileCheck.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.psi.KtExpression import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val PROBLEMATIC_SIMPLE_CALLS = listOf( FunMatcher(definingSupertype = "android.app.Activity", name = "getPreferences"), @@ -41,7 +41,7 @@ private const val MESSAGE = "Make sure using an unencrypted database is safe her @Rule(key = "S6291") class UnencryptedDatabaseOnMobileCheck : AbstractCheck() { override fun visitCallExpression(callExpression: KtCallExpression, kotlinFileContext: KotlinFileContext) { - val resolvedCall = analyze { callExpression.resolveToCall()?.successfulFunctionCallOrNull() } + val resolvedCall = withKaSession { callExpression.resolveToCall()?.successfulFunctionCallOrNull() } if (PROBLEMATIC_SIMPLE_CALLS.any { resolvedCall matches it }) { kotlinFileContext.reportIssue(callExpression.calleeExpression!!, MESSAGE) } else if ( @@ -55,7 +55,7 @@ class UnencryptedDatabaseOnMobileCheck : AbstractCheck() { private fun KtExpression.findCallInPrecedingCallChain( matcher: FunMatcherImpl, -): Pair>? = analyze { +): Pair>? = withKaSession { var receiver = this@findCallInPrecedingCallChain var receiverResolved = receiver.resolveToCall()?.successfulFunctionCallOrNull() ?: return null while (!matcher.matches(receiverResolved)) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnnecessaryImportsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnnecessaryImportsCheck.kt index 961b8c846..3b8706c11 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnnecessaryImportsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnnecessaryImportsCheck.kt @@ -50,7 +50,7 @@ import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val MESSAGE_UNUSED = "Remove this unused import." private const val MESSAGE_REDUNDANT = "Remove this redundant import." @@ -64,7 +64,7 @@ class UnnecessaryImportsCheck : AbstractCheck() { @OptIn(KaIdeApi::class) override fun visitKtFile(file: KtFile, context: KotlinFileContext) { - analyze { + withKaSession { if (this !is KaFe10Session) { val analyzeImportsToOptimize = analyzeImportsToOptimize(file) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableHashSaltCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableHashSaltCheck.kt index 7ad2d9d19..3f6b7f08e 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableHashSaltCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableHashSaltCheck.kt @@ -32,7 +32,7 @@ import org.sonarsource.kotlin.api.checks.predictRuntimeIntValue import org.sonarsource.kotlin.api.checks.predictRuntimeValueExpression import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.frontend.secondaryOf -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val SPECS_PACKAGE = "javax.crypto.spec" private const val KEY_SPEC_FUN_NAME = "PBEKeySpec" @@ -78,7 +78,7 @@ class UnpredictableHashSaltCheck : CallAbstractCheck() { return } - val saltInitializer = analyze { predictedSaltValue.resolveToCall()?.successfulFunctionCallOrNull() + val saltInitializer = withKaSession { predictedSaltValue.resolveToCall()?.successfulFunctionCallOrNull() ?.takeIf { it matches BYTE_ARRAY_CONSTRUCTOR } ?: return } if (saltInitializer.byteArrayInitSizeTooSmall()) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableSecureRandomSaltCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableSecureRandomSaltCheck.kt index 7f927c511..c98bf73d8 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableSecureRandomSaltCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableSecureRandomSaltCheck.kt @@ -24,7 +24,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.frontend.secondaryOf import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private const val MESSAGE = "Change this seed value to something unpredictable, or remove the seed." private const val SECURE_RANDOM = "java.security.SecureRandom" @@ -47,7 +47,7 @@ class UnpredictableSecureRandomSaltCheck : CallAbstractCheck() { val saltArg = resolvedCall.argumentMapping.keys.toList().firstOrNull() ?: return val predictedSaltValue = saltArg.predictRuntimeValueExpression() - analyze { + withKaSession { if ( (predictedSaltValue is KtConstantExpression || predictedSaltValue.isBytesInitializedFromString()) || (predictedSaltValue.resolveToCall() diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedDeferredResultCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedDeferredResultCheck.kt index f3ee1f18c..f00dbe4d4 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedDeferredResultCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedDeferredResultCheck.kt @@ -23,13 +23,13 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.DEFERRED_FQN import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S6315") class UnusedDeferredResultCheck : AbstractCheck() { override fun visitCallExpression(expression: KtCallExpression, context: KotlinFileContext) { - analyze { + withKaSession { // FIXME avoid repeated construction of ClassId if (expression.expressionType!!.isClassType(ClassId.fromString(DEFERRED_FQN.replace('.', '/'))) && !expression.isUsedAsExpression) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedPrivateMethodCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedPrivateMethodCheck.kt index a7b6d5b0a..b86e65300 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedPrivateMethodCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedPrivateMethodCheck.kt @@ -28,7 +28,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.isInfix import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession // Serializable method should not raise any issue in Kotlin. private val IGNORED_METHODS: Set = setOf( @@ -75,7 +75,7 @@ class UnusedPrivateMethodCheck : AbstractCheck() { && !hasModifier(KtTokens.OPERATOR_KEYWORD) && (annotationEntries.isEmpty() || annotatedWithCommonAnnotations()) - private fun KtNamedFunction.annotatedWithCommonAnnotations() = analyze { + private fun KtNamedFunction.annotatedWithCommonAnnotations() = withKaSession { symbol.annotations.all { it.classId?.asFqNameString() in COMMON_ANNOTATIONS } diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessNullCheckCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessNullCheckCheck.kt index 4bca08556..5f51fba16 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessNullCheckCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessNullCheckCheck.kt @@ -37,7 +37,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.* import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.reporting.Message -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val NON_NULL_CHECK_FUNS = FunMatcher("kotlin") { withNames("requireNotNull", "checkNotNull") @@ -101,7 +101,7 @@ class UselessNullCheckCheck : AbstractCheck() { } override fun visitCallExpression(callExpression: KtCallExpression, kfc: KotlinFileContext) { - val resolvedCall = analyze { callExpression.resolveToCall()?.successfulFunctionCallOrNull() } ?: return + val resolvedCall = withKaSession { callExpression.resolveToCall()?.successfulFunctionCallOrNull() } ?: return if (resolvedCall matches NON_NULL_CHECK_FUNS) { val argExpression = resolvedCall.argumentMapping.keys.toList().first() // requireNotNull and checkNotNull have no implementations without parameters. The first parameter is always the value to check. @@ -174,7 +174,7 @@ private fun KtExpression.isNotNullable(): Boolean = is KtConstantExpression -> !isNull() is KtStringTemplateExpression -> true - else -> analyze { + else -> withKaSession { this@isNotNullable.expressionType?.let { resolvedType -> resolvedType !is KaErrorType && // TODO Remove when migrate to K2 mode diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VarShouldBeValCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VarShouldBeValCheck.kt index abe295954..7b32edf34 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VarShouldBeValCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VarShouldBeValCheck.kt @@ -39,7 +39,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.reporting.message -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S3353") class VarShouldBeValCheck : AbstractCheck() { @@ -54,7 +54,7 @@ class VarShouldBeValCheck : AbstractCheck() { val assignedDeclarations2 = assignedExpressions .mapNotNull { - analyze { + withKaSession { val successfulVariableAccessCall = it.resolveToCall()?.successfulVariableAccessCall() successfulVariableAccessCall?.symbol ?: it.mainReference.resolveToSymbol() } @@ -96,7 +96,7 @@ class VarShouldBeValCheck : AbstractCheck() { private fun KtNamedDeclaration.isNotReferenced( assignedDeclarations: Set, - ): Boolean = analyze { + ): Boolean = withKaSession { !assignedDeclarations.contains(this@isNotReferenced.symbol) } diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VerifiedServerHostnamesCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VerifiedServerHostnamesCheck.kt index fe90703d3..ecab04534 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VerifiedServerHostnamesCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VerifiedServerHostnamesCheck.kt @@ -25,7 +25,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.predictRuntimeBooleanValue import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S5527") class VerifiedServerHostnamesCheck : AbstractCheck() { @@ -73,5 +73,5 @@ class VerifiedServerHostnamesCheck : AbstractCheck() { } private fun KtExpression.isTrueConstant(): Boolean = - analyze { predictRuntimeBooleanValue() ?: false } + withKaSession { predictRuntimeBooleanValue() ?: false } } diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ViewModelSuspendingFunctionsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ViewModelSuspendingFunctionsCheck.kt index 3477fcd24..5be13d5e0 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ViewModelSuspendingFunctionsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ViewModelSuspendingFunctionsCheck.kt @@ -25,7 +25,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.suspendModifier import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S6313") class ViewModelSuspendingFunctionsCheck : AbstractCheck() { @@ -44,7 +44,7 @@ class ViewModelSuspendingFunctionsCheck : AbstractCheck() { private fun KtNamedFunction.extendsViewModel(): Boolean { val function = this - analyze { + withKaSession { val containingSymbol = function.symbol.containingSymbol if (containingSymbol is KaClassSymbol) { return containingSymbol.superTypes.any { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VoidShouldBeUnitCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VoidShouldBeUnitCheck.kt index a1060783c..d606e8c2b 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VoidShouldBeUnitCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VoidShouldBeUnitCheck.kt @@ -32,7 +32,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.isAbstract import org.sonarsource.kotlin.api.reporting.message import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession private val message = message { +"Replace this usage of " @@ -83,7 +83,7 @@ private tailrec fun flattenTypeProjections( private fun List.withoutStarProjection() = filter { projection -> projection !is StarProjectionImpl } -private fun KtTypeReference.isVoidTypeRef() = analyze { +private fun KtTypeReference.isVoidTypeRef() = withKaSession { this@isVoidTypeRef.type.symbol?.classId?.asFqNameString() == "java.lang.Void" } diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WeakSSLContextCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WeakSSLContextCheck.kt index f94ee87a1..37881c96f 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WeakSSLContextCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WeakSSLContextCheck.kt @@ -30,7 +30,7 @@ import org.sonarsource.kotlin.api.checks.predictRuntimeStringValue import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange import org.sonarsource.kotlin.api.frontend.KotlinFileContext -import org.sonarsource.kotlin.api.visiting.analyze +import org.sonarsource.kotlin.api.visiting.withKaSession @Rule(key = "S4423") class WeakSSLContextCheck : AbstractCheck() { @@ -77,7 +77,7 @@ class WeakSSLContextCheck : AbstractCheck() { private fun handleSSL( node: KtCallExpression, kotlinFileContext: KotlinFileContext, - ) = analyze { + ) = withKaSession { node.valueArguments .firstOrNull() ?.getArgumentExpression() @@ -116,7 +116,7 @@ class WeakSSLContextCheck : AbstractCheck() { } } - private fun KtExpression.value(): String? = analyze { + private fun KtExpression.value(): String? = withKaSession { when (this@value) { is KtStringTemplateExpression -> asConstant() is KtNameReferenceExpression -> predictRuntimeStringValue()