Skip to content

Commit

Permalink
SONARKT-400 Migrate ExposedMutableFlowCheck to kotlin-analysis-api
Browse files Browse the repository at this point in the history
  • Loading branch information
Godin committed Dec 3, 2024
1 parent 6664e4b commit 3c5ba69
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.sonarsource.kotlin.api.visiting.withKaSession
import org.jetbrains.kotlin.analysis.api.types.KaClassType
import org.jetbrains.kotlin.analysis.api.types.KaType
import org.jetbrains.kotlin.coroutines.hasSuspendFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
Expand Down Expand Up @@ -334,25 +337,55 @@ fun KtCallExpression.expressionTypeFqn(bindingContext: BindingContext): String?
return type.getKotlinTypeFqName(false)
}

/**
* See examples of [org.jetbrains.kotlin.analysis.api.types.KaFlexibleType]
* (aka [platform type](https://kotlin.github.io/analysis-api/kaflexibletype.html)) in
* [KtNamedFunction.returnTypeAsString] and [KtProperty.determineTypeAsString].
*
* TODO according to [Kotlin Analysis API Documentation](https://kotlin.github.io/analysis-api/types.html#example)
* > Avoid using [org.jetbrains.kotlin.name.FqName]s or raw strings for type comparison.
* > Use [org.jetbrains.kotlin.name.ClassId]s instead
*/
private fun KaType.asFqNameString(): String? = withKaSession {
(lowerBoundIfFlexible() as? KaClassType)?.classId?.asFqNameString()
}

@Deprecated("use kotlin-analysis-api instead", ReplaceWith("this.determineType()"))
private fun KtProperty.determineType(bindingContext: BindingContext) =
(typeReference?.let { bindingContext[BindingContext.TYPE, it] }
?: bindingContext[BindingContext.EXPRESSION_TYPE_INFO, initializer]?.type)

private fun KtProperty.determineType(): KaType? = withKaSession { typeReference?.type ?: initializer?.expressionType }

@Deprecated("use kotlin-analysis-api instead", ReplaceWith("this.determineTypeAsString()"))
fun KtProperty.determineTypeAsString(bindingContext: BindingContext, printTypeArguments: Boolean = false) =
determineType(bindingContext)?.getKotlinTypeFqName(printTypeArguments)

/**
* ```
* val flexibleAkaPlatformType = java.lang.String.valueOf(1)
* ```
*/
fun KtProperty.determineTypeAsString(): String? = withKaSession { determineType()?.asFqNameString() }

fun KtExpression.determineTypeAsString(bindingContext: BindingContext, printTypeArguments: Boolean = false) =
determineType(bindingContext)?.let {
if (it.constructor.declarationDescriptor != null) it.getKotlinTypeFqName(printTypeArguments)
else null
}

@Deprecated("use kotlin-analysis-api instead", ReplaceWith("this.determineType()"))
private fun KtParameter.determineType(bindingContext: BindingContext) =
bindingContext[BindingContext.TYPE, typeReference]

private fun KtParameter.determineType(): KaType? = withKaSession { typeReference?.type }

@Deprecated("use kotlin-analysis-api instead", ReplaceWith("this.determineTypeAsString()"))
fun KtParameter.determineTypeAsString(bindingContext: BindingContext, printTypeArguments: Boolean = false) =
determineType(bindingContext)?.getKotlinTypeFqName(printTypeArguments)

fun KtParameter.determineTypeAsString(): String? = withKaSession { determineType()?.asFqNameString() }

private fun KtTypeReference.determineType(bindingContext: BindingContext) =
bindingContext[BindingContext.TYPE, this]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,16 @@ private val DISALLOWED_TYPES = listOf(

private const val MESSAGE = "Don't expose mutable flow types."

@org.sonarsource.kotlin.api.frontend.K1only
@Rule(key = "S6305")
class ExposedMutableFlowCheck : AbstractCheck() {
override fun visitProperty(property: KtProperty, kotlinFileContext: KotlinFileContext) {
if (isEligible(property) && property.determineTypeAsString(kotlinFileContext.bindingContext) in DISALLOWED_TYPES) {
if (isEligible(property) && property.determineTypeAsString() in DISALLOWED_TYPES) {
kotlinFileContext.reportIssue(property, MESSAGE)
}
}

override fun visitParameter(parameter: KtParameter, kotlinFileContext: KotlinFileContext) {
if (isEligible(parameter) && parameter.determineTypeAsString(kotlinFileContext.bindingContext) in DISALLOWED_TYPES) {
if (isEligible(parameter) && parameter.determineTypeAsString() in DISALLOWED_TYPES) {
kotlinFileContext.reportIssue(parameter, MESSAGE)
}
}
Expand Down

0 comments on commit 3c5ba69

Please sign in to comment.