From c0b0a4ab4af9d5e53de4d35185ec5faa5b98a843 Mon Sep 17 00:00:00 2001 From: "Victoria.Petrakovich" Date: Thu, 10 Oct 2024 20:29:09 +0200 Subject: [PATCH] [kotlin] Visit calls and dot qualified expressions separately KTIJ-28468 kotlinOptions to compilerOptions inspection (kts only) GitOrigin-RevId: 5f2f30b77f24f9fda7b96c20474070ad2f6d3778 --- ...CompilerOptionsInGradleScriptInspection.kt | 82 ++++++++----------- 1 file changed, 35 insertions(+), 47 deletions(-) diff --git a/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/KotlinOptionsToCompilerOptionsInGradleScriptInspection.kt b/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/KotlinOptionsToCompilerOptionsInGradleScriptInspection.kt index 138fe36d7e34..fe27d4f65d51 100644 --- a/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/KotlinOptionsToCompilerOptionsInGradleScriptInspection.kt +++ b/plugins/kotlin/code-insight/inspections-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/inspections/KotlinOptionsToCompilerOptionsInGradleScriptInspection.kt @@ -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