diff --git a/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/DialogButtonsInContentSlotDetector.kt b/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/DialogButtonsInContentSlotDetector.kt index 1cd1af3ab..3da9d3709 100644 --- a/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/DialogButtonsInContentSlotDetector.kt +++ b/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/DialogButtonsInContentSlotDetector.kt @@ -8,14 +8,10 @@ import com.android.tools.lint.detector.api.JavaContext import com.android.tools.lint.detector.api.Scope import com.android.tools.lint.detector.api.Severity import com.android.tools.lint.detector.api.SourceCodeScanner -import com.android.tools.lint.detector.api.computeKotlinArgumentMapping import com.intellij.psi.PsiElement -import com.intellij.psi.PsiJavaFile -import com.intellij.psi.PsiMember import com.intellij.psi.PsiMethod import org.jetbrains.uast.UBlockExpression import org.jetbrains.uast.UCallExpression -import org.jetbrains.uast.ULambdaExpression import org.jetbrains.uast.skipParenthesizedExprDown import org.jetbrains.uast.toUElement import org.jetbrains.uast.tryResolveNamed @@ -75,7 +71,6 @@ class DialogButtonsInContentSlotDetector : Detector(), SourceCodeScanner { ) } } - } private fun PsiElement.findAllBlockExpressionsInHierarchy(): List { @@ -87,26 +82,4 @@ class DialogButtonsInContentSlotDetector : Detector(), SourceCodeScanner { return expressions } - - private fun PsiMethod.getArgument( - node: UCallExpression, - argumentName: String, - ): ULambdaExpression? = computeKotlinArgumentMapping(node, this) - .orEmpty() - .filter { (_, parameter) -> - parameter.name == argumentName - } - .keys - .filterIsInstance() - .firstOrNull() - - private fun PsiMethod.isInPackageName(packageName: String): Boolean { - val actual = (containingFile as? PsiJavaFile)?.packageName - return packageName == actual - } - - private fun PsiElement.getPackageName(): String? = when (this) { - is PsiMember -> this.containingClass?.qualifiedName?.let { it.substring(0, it.lastIndexOf(".")) } - else -> null - } } diff --git a/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/LintUtils.kt b/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/LintUtils.kt index cdd0d08f7..e3e49a730 100644 --- a/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/LintUtils.kt +++ b/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/LintUtils.kt @@ -16,14 +16,45 @@ package kiwi.orbit.compose.lint.detectors +import com.android.tools.lint.detector.api.computeKotlinArgumentMapping +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiJavaFile +import com.intellij.psi.PsiMember +import com.intellij.psi.PsiMethod import org.jetbrains.kotlin.psi.KtLambdaExpression import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType import org.jetbrains.kotlin.psi.psiUtil.isAncestor +import org.jetbrains.uast.UCallExpression import org.jetbrains.uast.ULambdaExpression import org.jetbrains.uast.toUElement +internal fun PsiMethod.isInPackageName(packageName: String): Boolean { + val actual = (containingFile as? PsiJavaFile)?.packageName + return packageName == actual +} + +internal fun PsiElement.getPackageName(): String? = when (this) { + is PsiMember -> this.containingClass?.qualifiedName?.let { it.substring(0, it.lastIndexOf(".")) } + else -> null +} + +/** + * Get arguments of a method. Useful for retrieving Compose Lambda expression used as arguments. + */ +internal fun PsiMethod.getArgument( + node: UCallExpression, + argumentName: String, +): ULambdaExpression? = computeKotlinArgumentMapping(node, this) + .orEmpty() + .filter { (_, parameter) -> + parameter.name == argumentName + } + .keys + .filterIsInstance() + .firstOrNull() + /** * Returns a list of unreferenced parameters in [this]. If no parameters have been specified, but * there is an implicit `it` parameter, this will return a list containing an diff --git a/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/MaterialDesignInsteadOrbitDesignDetector.kt b/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/MaterialDesignInsteadOrbitDesignDetector.kt index bbe6e1aa3..4fa5bfb24 100644 --- a/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/MaterialDesignInsteadOrbitDesignDetector.kt +++ b/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/MaterialDesignInsteadOrbitDesignDetector.kt @@ -16,7 +16,6 @@ import org.jetbrains.uast.UCallExpression import org.jetbrains.uast.UElement import org.jetbrains.uast.UQualifiedReferenceExpression import org.jetbrains.uast.USimpleNameReferenceExpression -import org.jetbrains.uast.getContainingUClass import org.jetbrains.uast.toUElement import org.jetbrains.uast.tryResolveNamed @@ -33,8 +32,7 @@ class MaterialDesignInsteadOrbitDesignDetector : Detector(), Detector.UastScanne return object : UElementHandler() { override fun visitCallExpression(node: UCallExpression) { val name = node.methodName ?: return - val wrapperName = node.resolve()?.containingClass?.qualifiedName ?: return - val packageName = getPackageName(wrapperName) + val packageName = node.resolve()?.getPackageName()?: return val fqn = "$packageName.$name" val (preferredName) = METHOD_NAMES.entries.firstOrNull { it.value.contains(fqn) } ?: return @@ -44,8 +42,7 @@ class MaterialDesignInsteadOrbitDesignDetector : Detector(), Detector.UastScanne val parentExpression = node.sourcePsi?.parents?.find { it is KtCallExpression } val resolved = parentExpression.toUElement()?.tryResolveNamed() val parentName = resolved?.name - val parentWrapper = resolved.toUElement()?.getContainingUClass()?.qualifiedName ?: "" - val parentPackage = getPackageName(parentWrapper) + val parentPackage = resolved?.getPackageName() ?: "" val parentFqn = "$parentPackage.$parentName" if (allowedEntry.value.find { parentFqn.contains(it) } != null) { return @@ -222,9 +219,5 @@ class MaterialDesignInsteadOrbitDesignDetector : Detector(), Detector.UastScanne "Using $name instead of $preferredName", ) } - - private fun getPackageName(fullyQualifiedName: String): String { - return fullyQualifiedName.substring(0, fullyQualifiedName.lastIndexOf(".")) - } } } diff --git a/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/MaterialDialogWithOrbitButtonsDetector.kt b/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/MaterialDialogWithOrbitButtonsDetector.kt index 4f9ca5779..bb204955f 100644 --- a/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/MaterialDialogWithOrbitButtonsDetector.kt +++ b/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/MaterialDialogWithOrbitButtonsDetector.kt @@ -8,15 +8,10 @@ import com.android.tools.lint.detector.api.JavaContext import com.android.tools.lint.detector.api.Scope import com.android.tools.lint.detector.api.Severity import com.android.tools.lint.detector.api.SourceCodeScanner -import com.android.tools.lint.detector.api.computeKotlinArgumentMapping -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiJavaFile -import com.intellij.psi.PsiMember import com.intellij.psi.PsiMethod import com.intellij.psi.PsiNamedElement import org.jetbrains.uast.UBlockExpression import org.jetbrains.uast.UCallExpression -import org.jetbrains.uast.ULambdaExpression import org.jetbrains.uast.skipParenthesizedExprDown import org.jetbrains.uast.tryResolveNamed @@ -51,7 +46,7 @@ class MaterialDialogWithOrbitButtonsDetector : Detector(), SourceCodeScanner { override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) { if (method.isInPackageName(PACKAGE_MATERIAL_ALERT)) { - val confirmButtonArgument = getArgument(node, method, MATERIAL_ALERT_CONFIRM_BUTTON_PARAM) + val confirmButtonArgument = method.getArgument(node, MATERIAL_ALERT_CONFIRM_BUTTON_PARAM) (confirmButtonArgument?.body as? UBlockExpression)?.let { body -> val resolvedBodyExpression = body.resolveFirstBodyExpression() ?: return@let @@ -77,7 +72,7 @@ class MaterialDialogWithOrbitButtonsDetector : Detector(), SourceCodeScanner { } } - val dismissButtonArgument = getArgument(node, method, MATERIAL_ALERT_DISMISS_BUTTON_PARAM) + val dismissButtonArgument = method.getArgument(node, MATERIAL_ALERT_DISMISS_BUTTON_PARAM) (dismissButtonArgument?.body as? UBlockExpression)?.let { body -> val resolvedBodyExpression = body.resolveFirstBodyExpression() ?: return@let @@ -105,29 +100,6 @@ class MaterialDialogWithOrbitButtonsDetector : Detector(), SourceCodeScanner { } } - private fun getArgument( - node: UCallExpression, - method: PsiMethod, - argumentName: String, - ): ULambdaExpression? = computeKotlinArgumentMapping(node, method) - .orEmpty() - .filter { (_, parameter) -> - parameter.name == argumentName - } - .keys - .filterIsInstance() - .firstOrNull() - - private fun PsiMethod.isInPackageName(packageName: String): Boolean { - val actual = (containingFile as? PsiJavaFile)?.packageName - return packageName == actual - } - - private fun PsiElement.getPackageName(): String? = when (this) { - is PsiMember -> this.containingClass?.qualifiedName?.let { it.substring(0, it.lastIndexOf(".")) } - else -> null - } - private fun UBlockExpression.resolveFirstBodyExpression(): PsiNamedElement? { return expressions.firstOrNull()?.skipParenthesizedExprDown()?.tryResolveNamed() } diff --git a/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/ScaffoldContentPaddingDetector.kt b/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/ScaffoldContentPaddingDetector.kt index 84f997cd8..58bbf9d5f 100644 --- a/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/ScaffoldContentPaddingDetector.kt +++ b/lint/src/main/kotlin/kiwi/orbit/compose/lint/detectors/ScaffoldContentPaddingDetector.kt @@ -25,7 +25,6 @@ import com.android.tools.lint.detector.api.Scope import com.android.tools.lint.detector.api.Severity import com.android.tools.lint.detector.api.SourceCodeScanner import com.android.tools.lint.detector.api.computeKotlinArgumentMapping -import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiMethod import java.util.EnumSet import org.jetbrains.uast.UCallExpression @@ -86,9 +85,4 @@ class ScaffoldContentPaddingDetector : } } } - - private fun PsiMethod.isInPackageName(packageName: String): Boolean { - val actual = (containingFile as? PsiJavaFile)?.packageName - return packageName == actual - } }