Skip to content

Commit

Permalink
SONARKT-400 Migrate ViewModelSuspendingFunctionsCheck to kotlin-analy…
Browse files Browse the repository at this point in the history
…sis-api
  • Loading branch information
Godin authored Dec 4, 2024
1 parent 6664e4b commit d16df82
Showing 1 changed file with 10 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,34 @@
*/
package org.sonarsource.kotlin.checks

import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.analysis.api.symbols.KaClassSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContext.FUNCTION
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
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.withKaSession

@org.sonarsource.kotlin.api.frontend.K1only
@Rule(key = "S6313")
class ViewModelSuspendingFunctionsCheck : AbstractCheck() {
private val viewModelClassId = ClassId.fromString("androidx/lifecycle/ViewModel")

override fun visitNamedFunction(function: KtNamedFunction, kotlinFileContext: KotlinFileContext) {
val bindingContext = kotlinFileContext.bindingContext
function.suspendModifier()?.let {
if (!function.isPrivate()
&& function.extendsViewModel(bindingContext)
&& function.extendsViewModel()
) {
kotlinFileContext.reportIssue(it,
"""Classes extending "ViewModel" should not expose suspending functions.""")
}
}
}
}

private fun KtNamedFunction.extendsViewModel(bindingContext: BindingContext): Boolean {
val classDescriptor = bindingContext[FUNCTION, this]?.containingDeclaration as? ClassDescriptor
return classDescriptor?.getAllSuperClassifiers()?.any {
it.fqNameOrNull()?.asString() == "androidx.lifecycle.ViewModel"
} ?: false
private fun KtNamedFunction.extendsViewModel(): Boolean = withKaSession {
val containingSymbol = symbol.containingSymbol
if (containingSymbol !is KaClassSymbol) return false
return containingSymbol.superTypes.any { it.isClassType(viewModelClassId) }
}
}

0 comments on commit d16df82

Please sign in to comment.