[kotlin] Visit calls and dot qualified expressions separately

KTIJ-28468 kotlinOptions to compilerOptions inspection (kts only)

GitOrigin-RevId: 5f2f30b77f24f9fda7b96c20474070ad2f6d3778
This commit is contained in:
Victoria.Petrakovich
2024-10-10 19:55:31 +00:00
committed by intellij-monorepo-bot
parent 2b77f37dd5
commit c0b0a4ab4a
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
private val kotlinCompileTasksNames = setOf(
"org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile",
@@ -59,55 +60,53 @@ internal class KotlinOptionsToCompilerOptionsInGradleScriptInspection : Abstract
isOnTheFly: Boolean,
): KtVisitorVoid {
return object : KtVisitorVoid() {
override fun visitReferenceExpression(expression: KtReferenceExpression) {
val referencedName = (expression as? KtNameReferenceExpression)?.getReferencedName() ?: return
// ATM, we don't have proper dependencies for tests to perform `analyze` in Gradle build scripts
if (referencedName == "android" && !isUnitTestMode()) {
if (elementIsAndroidDsl(expression)) return
}
if (referencedName != "kotlinOptions") return
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
val referenceExpression = expression.receiverExpression.referenceExpression() ?: return
if (!isApplicable(referenceExpression)) return
val expressionParent = expression.parent
if (elementContainsOperationForbiddenToReplaceOrCantBeProcessed(expressionParent)) return
addProblemToHolder(referenceExpression)
}
override fun visitCallExpression(callExpression: KtCallExpression) {
val referenceExpression = callExpression.referenceExpression() ?: return
if (!isApplicable(referenceExpression)) return
val lambdaStatements = callExpression.lambdaArguments.firstOrNull()
?.getLambdaExpression()?.bodyExpression?.statements?.requireNoNulls()
if (lambdaStatements?.any(::expressionsContainForbiddenOperations) == true) return
addProblemToHolder(referenceExpression)
}
private fun isApplicable(referenceExpression: KtReferenceExpression): Boolean {
val referencedName = (referenceExpression as? KtNameReferenceExpression)?.getReferencedName() ?: return false
if (referencedName != "kotlinOptions") return false
if (!isUnitTestMode()) { // ATM, we don't have proper dependencies for tests to perform `analyze` in Gradle build scripts
val jvmClassForKotlinCompileTask = analyze(expression) {
val symbol = expression.resolveToCall()
val jvmClassForKotlinCompileTask = analyze(referenceExpression) {
val symbol = referenceExpression.resolveToCall()
?.successfulFunctionCallOrNull()?.partiallyAppliedSymbol?.signature?.symbol
val containingDeclarationOrSymbol =
(symbol?.containingDeclaration as? KaClassLikeSymbol) ?: expression.resolveExpression()?.containingSymbol
(symbol?.containingDeclaration as? KaClassLikeSymbol)
?: referenceExpression.resolveExpression()?.containingSymbol
containingDeclarationOrSymbol?.importableFqName?.toString()
}
if (jvmClassForKotlinCompileTask !in kotlinCompileTasksNames) {
return
return false
}
}
when (expressionParent) {
is KtDotQualifiedExpression -> { // like `kotlinOptions.sourceMapEmbedSources` OR kotlinOptions.options
val parentOfExpressionParent = expressionParent.parent
if (elementContainsOperationForbiddenToReplaceOrCantBeProcessed(parentOfExpressionParent)) return
}
is KtCallExpression -> {
/*
Like the following. Raise a problem for this.
compileKotlin.kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += listOf("-module-name", "TheName")
apiVersion = "1.9"
}
*/
val lambdaStatements = expressionParent.lambdaArguments.firstOrNull()
?.getLambdaExpression()?.bodyExpression?.statements?.requireNoNulls()
// compileKotlin.kotlinOptions { .. }
if (lambdaStatements?.any(::expressionsContainForbiddenOperations) == true) return
}
else -> return
}
return true
}
private fun addProblemToHolder(referenceExpression: KtReferenceExpression) {
holder.problem(
expression,
referenceExpression,
KotlinBundle.message("inspection.kotlin.options.to.compiler.options.display.name")
)
.highlight(ProblemHighlightType.GENERIC_ERROR_OR_WARNING)
@@ -137,17 +136,6 @@ internal class KotlinOptionsToCompilerOptionsInGradleScriptInspection : Abstract
}
}
private fun elementIsAndroidDsl(expression: KtExpression): Boolean {
val importableFqName = analyze(expression) {
val symbol = expression.resolveToCall()
?.successfulFunctionCallOrNull()?.partiallyAppliedSymbol?.signature?.symbol
val kaSymbol =
(symbol?.containingDeclaration as? KaClassLikeSymbol) ?: expression.resolveExpression()
kaSymbol?.importableFqName?.toString()
}
return importableFqName == "org.gradle.kotlin.dsl.android"
}
private fun expressionsContainForbiddenOperations(element: PsiElement): Boolean {
if (element is KtBinaryExpression) { // for sth like `kotlinOptions.sourceMapEmbedSources = "inlining"`
if (expressionContainsOperationForbiddenToReplace(element)) return true