[kotlin] Review fixes

KTIJ-28468 kotlinOptions to compilerOptions inspection (kts only)

GitOrigin-RevId: 503367d189a7b5bf5858b4209e5e5291a084314a
This commit is contained in:
Victoria.Petrakovich
2024-10-03 22:20:33 +00:00
committed by intellij-monorepo-bot
parent 8a23a1cbd6
commit 5f44d48b99
3 changed files with 75 additions and 79 deletions
@@ -42,50 +42,50 @@ private val kotlinCompileTasksNames = setOf(
internal class KotlinOptionsToCompilerOptionsInGradleScriptInspection : AbstractKotlinGradleScriptInspection() {
override fun isAvailableForFile(file: PsiFile): Boolean {
if (super.isAvailableForFile(file)) {
return if (super.isAvailableForFile(file)) {
if (isUnitTestMode()) {
// Inspection tests don't treat tested build script files properly, and thus they ignore Kotlin versions used in scripts
return true
true
} else {
return kotlinVersionIsEqualOrHigher(major = 2, minor = 0, patch = 0, file)
kotlinVersionIsEqualOrHigher(major = 2, minor = 0, patch = 0, file)
}
} else {
return false
false
}
}
override fun buildVisitor(
holder: ProblemsHolder,
isOnTheFly: Boolean
) = object : KtVisitorVoid() {
isOnTheFly: Boolean,
): KtVisitorVoid {
return object : KtVisitorVoid() {
override fun visitReferenceExpression(expression: KtReferenceExpression) {
if (expression.text.equals("kotlinOptions")) {
override fun visitReferenceExpression(expression: KtReferenceExpression) {
if (expression.text.equals("kotlinOptions")) {
if (isDescendantOfDslInWhichReplacementIsNotNeeded(expression)) return
if (isDescendantOfDslInWhichReplacementIsNotNeeded(expression)) return
val expressionParent = expression.parent
val expressionParent = expression.parent
if (!isUnitTestMode()) { // ATM, we don't have proper dependencies for tests on Gradle build scripts
analyze(expression) {
val jvmClassForKotlinCompileTask = (expression.resolveToCall()
?.successfulFunctionCallOrNull()?.partiallyAppliedSymbol?.signature?.symbol
?.containingDeclaration as? KaClassLikeSymbol)?.importableFqName?.toString()
if (!isUnitTestMode()) { // ATM, we don't have proper dependencies for tests on Gradle build scripts
analyze(expression) {
val jvmClassForKotlinCompileTask = (expression.resolveToCall()
?.successfulFunctionCallOrNull()?.partiallyAppliedSymbol?.signature?.symbol
?.containingDeclaration as? KaClassLikeSymbol)?.importableFqName?.toString()
?: expression.resolveExpression()?.containingSymbol?.importableFqName?.toString() ?: return
if (!kotlinCompileTasksNames.contains(jvmClassForKotlinCompileTask)) {
return
?: expression.resolveExpression()?.containingSymbol?.importableFqName?.toString() ?: return
if (!kotlinCompileTasksNames.contains(jvmClassForKotlinCompileTask)) {
return
}
}
}
}
when (expressionParent) {
is KtDotQualifiedExpression -> { // like `kotlinOptions.sourceMapEmbedSources` OR kotlinOptions.options
val parentOfExpressionParent = expressionParent.parent
if (elementContainsOperationForbiddenToReplaceOrCantBeProcessed(parentOfExpressionParent)) return
}
when (expressionParent) {
is KtDotQualifiedExpression -> { // like `kotlinOptions.sourceMapEmbedSources` OR kotlinOptions.options
val parentOfExpressionParent = expressionParent.parent
if (elementContainsOperationForbiddenToReplaceOrCantBeProcessed(parentOfExpressionParent)) return
}
is KtCallExpression -> {
/*
is KtCallExpression -> {
/*
Like the following. Raise a problem for this.
compileKotlin.kotlinOptions {
jvmTarget = "1.8"
@@ -93,27 +93,28 @@ internal class KotlinOptionsToCompilerOptionsInGradleScriptInspection : Abstract
apiVersion = "1.9"
}
*/
val lambdaStatements = expressionParent.lambdaArguments.getOrNull(0)
?.getLambdaExpression()?.bodyExpression?.statements?.requireNoNulls()
val lambdaStatements = expressionParent.lambdaArguments.getOrNull(0)
?.getLambdaExpression()?.bodyExpression?.statements?.requireNoNulls()
if (lambdaStatements?.isNotEmpty() == true) { // compileKotlin.kotlinOptions { .. }
lambdaStatements.forEach {
if (expressionsContainForbiddenOperations(it)) return
if (lambdaStatements?.isNotEmpty() == true) { // compileKotlin.kotlinOptions { .. }
lambdaStatements.forEach {
if (expressionsContainForbiddenOperations(it)) return
}
}
}
else -> return
}
else -> return
holder.problem(
expression,
KotlinBundle.message("inspection.kotlin.options.to.compiler.options.display.name")
)
.highlight(ProblemHighlightType.GENERIC_ERROR_OR_WARNING)
.fix(
ReplaceKotlinOptionsWithCompilerOptionsFix()
).register()
}
holder.problem(
expression,
KotlinBundle.message("inspection.kotlin.options.to.compiler.options.display.name")
)
.highlight(ProblemHighlightType.GENERIC_ERROR_OR_WARNING)
.fix(
ReplaceKotlinOptionsWithCompilerOptionsFix()
).register()
}
}
}
@@ -126,10 +127,10 @@ internal class KotlinOptionsToCompilerOptionsInGradleScriptInspection : Abstract
is KtDotQualifiedExpression -> {
val psiElementParent = psiElement.parent
if (psiElementParent is KtBinaryExpression) {
return expressionContainsOperationForbiddenToReplace(psiElementParent)
return if (psiElementParent is KtBinaryExpression) {
expressionContainsOperationForbiddenToReplace(psiElementParent)
} else { // Can't be processed
return true
true
}
}
@@ -140,11 +141,7 @@ internal class KotlinOptionsToCompilerOptionsInGradleScriptInspection : Abstract
private fun isDescendantOfDslInWhichReplacementIsNotNeeded(ktExpression: KtExpression): Boolean {
val scriptText = ktExpression.containingFile.text
if (scriptText.contains("android")) {
ktExpression.prevLeafs.forEach {
if ("android" == it.text) {
return true
}
}
return ktExpression.prevLeafs.any { it.text == "android" }
}
return false
}
@@ -153,25 +150,20 @@ internal class KotlinOptionsToCompilerOptionsInGradleScriptInspection : Abstract
if (element is KtBinaryExpression) { // for sth like `kotlinOptions.sourceMapEmbedSources = "inlining"`
if (expressionContainsOperationForbiddenToReplace(element)) return true
} else {
element.children.forEach {
if (expressionsContainForbiddenOperations(it)) return true
}
return element.children.any { expressionsContainForbiddenOperations(it) }
}
return false
}
}
private class ReplaceKotlinOptionsWithCompilerOptionsFix() : KotlinModCommandQuickFix<KtExpression>() {
override fun getFamilyName(): @IntentionFamilyName String {
return KotlinBundle.message("replace.kotlin.options.with.compiler.options")
}
override fun getFamilyName(): @IntentionFamilyName String = KotlinBundle.message("replace.kotlin.options.with.compiler.options")
override fun applyFix(
project: Project,
element: KtExpression,
updater: ModPsiUpdater
updater: ModPsiUpdater,
) {
val expressionsToFix = mutableListOf<Replacement>()
val expressionParent = element.parent
when (expressionParent) {
@@ -7,10 +7,10 @@ import org.jetbrains.kotlin.idea.codeinsight.api.classic.inspections.AbstractKot
abstract class AbstractKotlinGradleScriptInspection : AbstractKotlinInspection() {
override fun isAvailableForFile(file: PsiFile): Boolean {
if (file.name.endsWith(".gradle.kts")) {
return super.isAvailableForFile(file)
return if (file.virtualFile.nameSequence.endsWith(".gradle.kts")) {
super.isAvailableForFile(file)
} else {
return false
false
}
}
}
@@ -24,28 +24,28 @@ data class Replacement(val expressionToReplace: KtExpression, val replacement: S
@ApiStatus.Internal
fun expressionContainsOperationForbiddenToReplace(binaryExpression: KtBinaryExpression): Boolean {
val operationReference = binaryExpression.operationReference.text
if (operationReference == "-=") {
return true
return if (operationReference == "-=") {
true
} else {
val rightPartOfBinaryExpression = binaryExpression.right ?: return true
if (rightPartOfBinaryExpression is KtBinaryExpression) {
return checkIfExpressionContainsMinusOperator(rightPartOfBinaryExpression)
checkIfExpressionContainsMinusOperator(rightPartOfBinaryExpression)
} else {
return false
false
}
}
}
private fun checkIfExpressionContainsMinusOperator(binaryExpression: KtBinaryExpression): Boolean {
val operationReference = binaryExpression.operationReference.text
if (operationReference == "-") {
return true
return if (operationReference == "-") {
true
} else {
val leftPartOfBinaryExpression = binaryExpression.left ?: return true
if (leftPartOfBinaryExpression is KtBinaryExpression) {
return checkIfExpressionContainsMinusOperator(leftPartOfBinaryExpression)
checkIfExpressionContainsMinusOperator(leftPartOfBinaryExpression)
} else {
return false
false
}
}
}
@@ -235,7 +235,7 @@ private fun getCompilerOptionForVersionValue(
replacement: StringBuilder,
optionName: String,
operationReplacer: String,
): CompilerOption? {
): CompilerOption {
val processedOptionValue = optionValue.removeSurrounding("\"").removeSurrounding("'")
val convertedValue = versionOptionData.mappingRule.apply(processedOptionValue)
val compilerOptionValue = if (convertedValue != null) {
@@ -249,7 +249,6 @@ private fun getCompilerOptionForVersionValue(
"$optionName.$operationReplacer($compilerOptionValue)"
)
return CompilerOption(replacement.toString(), versionOptionData.fqClassName, compilerOptionValue)
return null
}
private fun getCompilerOptionForJsValue(
@@ -303,8 +302,11 @@ private fun jvmTargetValueMappingRule(inputValue: String): String? {
if (inputValue == "1.8") return "1_8"
val numericValue = inputValue.removePrefix("1.").toIntOrNull()
if (numericValue != null) {
if (numericValue <= 7) return null // JvmTarget class has values starting from 8
else return numericValue.toString()
return if (numericValue <= 7) {
null // JvmTarget class has values starting from 8
} else {
numericValue.toString()
}
}
// parse JavaVersion.VERSION_N.toString()
@@ -313,10 +315,10 @@ private fun jvmTargetValueMappingRule(inputValue: String): String? {
"1_8" -> return "1_8"
else -> {
val numericValue = version.removePrefix("1_").toIntOrNull() ?: return null
if (numericValue > 8) {
return numericValue.toString()
return if (numericValue > 8) {
numericValue.toString()
} else { // Kotlin doesn't support jvmTarget 7 and less
return null
null
}
}
}
@@ -325,9 +327,11 @@ private fun jvmTargetValueMappingRule(inputValue: String): String? {
private val kotlinVersionRegex = Regex("\\d\\.\\d")
private fun kotlinVersionValueMappingRule(inputValue: String): String? {
if (kotlinVersionRegex.matches(inputValue)) {
return inputValue.replace(".", "_")
} else return null
return if (kotlinVersionRegex.matches(inputValue)) {
inputValue.replace(".", "_")
} else {
null
}
}
private data class VersionOption(val newOptionType: String, val fqClassName: FqName, val mappingRule: Function<String, String?>)