Skip to content

Commit

Permalink
SONARKT-400 Migrate UnusedPrivateMethodCheck 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 ce78158 commit e3cb651
Showing 1 changed file with 9 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ import org.jetbrains.kotlin.psi.KtOperationReferenceExpression
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
import org.jetbrains.kotlin.resolve.BindingContext
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.withKaSession

// Serializable method should not raise any issue in Kotlin.
private val IGNORED_METHODS: Set<String> = setOf(
Expand All @@ -46,13 +46,12 @@ private val COMMON_ANNOTATIONS = listOf(
"kotlin.jvm.Throws",
)

@org.sonarsource.kotlin.api.frontend.K1only
@Rule(key = "S1144")
class UnusedPrivateMethodCheck : AbstractCheck() {

override fun visitClass(klass: KtClass, context: KotlinFileContext) {
if (!klass.isTopLevel()) return
klass.collectDescendantsOfType<KtNamedFunction> { it.shouldCheckForUsage(context.bindingContext) }
klass.collectDescendantsOfType<KtNamedFunction> { it.shouldCheckForUsage() }
.forEach {
val functionName = it.name!!
if (!IGNORED_METHODS.contains(functionName) && !it.isReferencedIn(klass, functionName)) {
Expand All @@ -71,15 +70,15 @@ class UnusedPrivateMethodCheck : AbstractCheck() {
private fun KtClass.hasInfixReferences(name: String) =
anyDescendantOfType<KtOperationReferenceExpression> { it.getReferencedName() == name }

private fun KtNamedFunction.shouldCheckForUsage(bindingContext: BindingContext) =
private fun KtNamedFunction.shouldCheckForUsage() =
isPrivate()
&& !hasModifier(KtTokens.OPERATOR_KEYWORD)
&& (annotationEntries.isEmpty() || annotatedWithCommonAnnotations(bindingContext))
&& (annotationEntries.isEmpty() || annotatedWithCommonAnnotations())

private fun KtNamedFunction.annotatedWithCommonAnnotations(bindingContext: BindingContext) =
bindingContext[BindingContext.FUNCTION, this]
?.annotations
?.all { it.fqName?.asString() in COMMON_ANNOTATIONS }
?: false
private fun KtNamedFunction.annotatedWithCommonAnnotations() = withKaSession {
symbol.annotations.all {
it.classId?.asFqNameString() in COMMON_ANNOTATIONS
}
}

}

0 comments on commit e3cb651

Please sign in to comment.