mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] Move methods to JavaCollectionsStaticMethodInspectionUtils,simplify calculating if type is list/mutableList
^KTIJ-31955 Fixed GitOrigin-RevId: 429d26cd2a10313b369fdae64aae1135409709d4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
009e4f2444
commit
da65c14e88
+58
-73
@@ -3,99 +3,84 @@ package org.jetbrains.kotlin.idea.codeinsights.impl.base.inspections
|
||||
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import org.jetbrains.kotlin.analysis.api.KaSession
|
||||
import org.jetbrains.kotlin.analysis.api.components.expandedSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.components.expressionType
|
||||
import org.jetbrains.kotlin.analysis.api.components.isSubtypeOf
|
||||
import org.jetbrains.kotlin.analysis.api.components.resolveToCall
|
||||
import org.jetbrains.kotlin.analysis.api.resolution.singleFunctionCallOrNull
|
||||
import org.jetbrains.kotlin.analysis.api.resolution.symbol
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaType
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.codeinsight.utils.callExpression
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||
|
||||
class JavaCollectionsStaticMethodInspectionUtils {
|
||||
object JavaCollectionsStaticMethodInspectionUtils {
|
||||
|
||||
companion object Utils {
|
||||
|
||||
context(_: KaSession)
|
||||
fun getTargetMethod(
|
||||
expression: KtDotQualifiedExpression,
|
||||
isValidFirstArgument: (KaType?) -> Boolean
|
||||
): Pair<String, KtValueArgument>? {
|
||||
val callExpression = expression.callExpression ?: return null
|
||||
val args = callExpression.valueArguments
|
||||
val firstArg = args.firstOrNull() ?: return null
|
||||
val firstArgType = firstArg.getArgumentExpression()?.expressionType
|
||||
if (!isValidFirstArgument(firstArgType)) return null
|
||||
|
||||
val call = callExpression.resolveToCall()?.singleFunctionCallOrNull() ?: return null
|
||||
val callableId = call.partiallyAppliedSymbol.symbol.callableId ?: return null
|
||||
val fqName = callableId.asSingleFqName().asString()
|
||||
|
||||
if (!canReplaceWithStdLib(expression, fqName, args)) return null
|
||||
|
||||
val methodName = fqName.split(".").last()
|
||||
return methodName to firstArg
|
||||
context(_: KaSession)
|
||||
fun getMethodIfItsArgumentIsMutableList(expression: KtDotQualifiedExpression): Pair<String, KtValueArgument>? =
|
||||
getMethodIfCanReplaceItWithStdlib(expression) { methodArgument ->
|
||||
isMutableListOrSubtype(methodArgument)
|
||||
}
|
||||
|
||||
private fun checkApiVersion(expression: KtDotQualifiedExpression): Boolean {
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(expression) ?: return true
|
||||
return module.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_2
|
||||
context(_: KaSession)
|
||||
fun getMethodIfItsArgumentIsImmutableList(expression: KtDotQualifiedExpression): Pair<String, KtValueArgument>? =
|
||||
getMethodIfCanReplaceItWithStdlib(expression) { methodArgument ->
|
||||
isListOrSubtype(methodArgument) && !isMutableListOrSubtype(
|
||||
methodArgument
|
||||
)
|
||||
}
|
||||
|
||||
private fun canReplaceWithStdLib(expression: KtDotQualifiedExpression, fqName: String, args: List<KtValueArgument>): Boolean {
|
||||
if (!fqName.startsWith("java.util.Collections.")) return false
|
||||
val size = args.size
|
||||
return when (fqName) {
|
||||
"java.util.Collections.fill" -> checkApiVersion(expression) && size == 2
|
||||
"java.util.Collections.reverse" -> size == 1
|
||||
"java.util.Collections.shuffle" -> checkApiVersion(expression) && (size == 1 || size == 2)
|
||||
"java.util.Collections.sort" -> {
|
||||
size == 1 || (size == 2 && args.getOrNull(1)?.getArgumentExpression() is KtLambdaExpression)
|
||||
}
|
||||
context(_: KaSession)
|
||||
private fun getMethodIfCanReplaceItWithStdlib(
|
||||
expression: KtDotQualifiedExpression,
|
||||
isValidFirstArgument: (KaType?) -> Boolean
|
||||
): Pair<String, KtValueArgument>? {
|
||||
val callExpression = expression.callExpression ?: return null
|
||||
val args = callExpression.valueArguments
|
||||
val firstArg = args.firstOrNull() ?: return null
|
||||
val firstArgType = firstArg.getArgumentExpression()?.expressionType
|
||||
if (!isValidFirstArgument(firstArgType)) return null
|
||||
|
||||
else -> false
|
||||
val call = callExpression.resolveToCall()?.singleFunctionCallOrNull() ?: return null
|
||||
val callableId = call.partiallyAppliedSymbol.symbol.callableId ?: return null
|
||||
val fqName = callableId.asSingleFqName().asString()
|
||||
|
||||
if (!canReplaceWithStdLib(expression, fqName, args)) return null
|
||||
|
||||
val methodName = fqName.split(".").last()
|
||||
return methodName to firstArg
|
||||
}
|
||||
|
||||
private fun checkApiVersion(expression: KtDotQualifiedExpression): Boolean {
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(expression) ?: return true
|
||||
return module.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_2
|
||||
}
|
||||
|
||||
private fun canReplaceWithStdLib(expression: KtDotQualifiedExpression, fqName: String, args: List<KtValueArgument>): Boolean {
|
||||
if (!fqName.startsWith("java.util.Collections.")) return false
|
||||
val size = args.size
|
||||
return when (fqName) {
|
||||
"java.util.Collections.fill" -> checkApiVersion(expression) && size == 2
|
||||
"java.util.Collections.reverse" -> size == 1
|
||||
"java.util.Collections.shuffle" -> checkApiVersion(expression) && (size == 1 || size == 2)
|
||||
"java.util.Collections.sort" -> {
|
||||
size == 1 || (size == 2 && args.getOrNull(1)?.getArgumentExpression() is KtLambdaExpression)
|
||||
}
|
||||
}
|
||||
|
||||
context(_: KaSession)
|
||||
fun isMutableListOrSubtype(type: KaType?): Boolean {
|
||||
return isListOrSubtype(type, isMutable = true)
|
||||
}
|
||||
|
||||
context(_: KaSession)
|
||||
fun isListOrSubtype(type: KaType?): Boolean {
|
||||
return isListOrSubtype(type, isMutable = false)
|
||||
}
|
||||
|
||||
context(_: KaSession)
|
||||
private fun isListOrSubtype(type: KaType?, isMutable: Boolean): Boolean {
|
||||
if (type == null) return false
|
||||
val fqName = getSingleFqName(type) ?: return false
|
||||
|
||||
val qualifiedName = if (isMutable) {
|
||||
if (fqName == StandardNames.FqNames.mutableList) return true
|
||||
StandardNames.FqNames.mutableList
|
||||
} else {
|
||||
if (fqName == StandardNames.FqNames.list) return true
|
||||
StandardNames.FqNames.list
|
||||
}
|
||||
val classSymbol = type.expandedSymbol ?: return false
|
||||
return classSymbol.superTypes.reversed().any { superType ->
|
||||
val fqNameOfSuperType = getSingleFqName(superType)
|
||||
fqNameOfSuperType == qualifiedName
|
||||
}
|
||||
}
|
||||
|
||||
context(_: KaSession)
|
||||
private fun getSingleFqName(type: KaType): FqName? {
|
||||
val classSymbol = type.expandedSymbol ?: return null
|
||||
return classSymbol.classId?.asSingleFqName()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
context(_: KaSession)
|
||||
private fun isMutableListOrSubtype(type: KaType?): Boolean {
|
||||
return type?.isSubtypeOf(StandardClassIds.MutableList) == true
|
||||
}
|
||||
|
||||
context(_: KaSession)
|
||||
private fun isListOrSubtype(type: KaType?): Boolean {
|
||||
return type?.isSubtypeOf(StandardClassIds.List) == true
|
||||
}
|
||||
}
|
||||
+3
-9
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.applicable.inspections.KotlinApplicableInspectionBase
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.ApplicabilityRange
|
||||
import org.jetbrains.kotlin.idea.codeinsight.utils.callExpression
|
||||
import org.jetbrains.kotlin.idea.codeinsights.impl.base.inspections.JavaCollectionsStaticMethodInspectionUtils.Utils
|
||||
import org.jetbrains.kotlin.idea.codeinsights.impl.base.inspections.JavaCollectionsStaticMethodInspectionUtils.getMethodIfItsArgumentIsImmutableList
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||
import org.jetbrains.kotlin.psi.KtVisitor
|
||||
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.psi.dotQualifiedExpressionVisitor
|
||||
internal class JavaCollectionsStaticMethodOnImmutableListInspection :
|
||||
KotlinApplicableInspectionBase<KtDotQualifiedExpression, JavaCollectionsStaticMethodOnImmutableListInspection.Context>() {
|
||||
|
||||
internal class Context(
|
||||
class Context(
|
||||
val methodName: String,
|
||||
val firstArg: KtValueArgument
|
||||
)
|
||||
@@ -43,16 +43,10 @@ internal class JavaCollectionsStaticMethodOnImmutableListInspection :
|
||||
)
|
||||
|
||||
override fun KaSession.prepareContext(element: KtDotQualifiedExpression): Context? {
|
||||
val (methodName, firstArg) = getTargetMethodOnImmutableList(element) ?: return null
|
||||
val (methodName, firstArg) = getMethodIfItsArgumentIsImmutableList(element) ?: return null
|
||||
return Context(methodName, firstArg)
|
||||
}
|
||||
|
||||
context(_: KaSession)
|
||||
private fun getTargetMethodOnImmutableList(expression: KtDotQualifiedExpression): Pair<String, KtValueArgument>? =
|
||||
Utils.getTargetMethod(expression) { type ->
|
||||
Utils.isListOrSubtype(type) && !Utils.isMutableListOrSubtype(type)
|
||||
}
|
||||
|
||||
override fun getApplicableRanges(element: KtDotQualifiedExpression): List<TextRange> =
|
||||
ApplicabilityRange.single(element) { it.callExpression?.calleeExpression }
|
||||
|
||||
|
||||
+2
-6
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.idea.codeinsight.api.applicable.inspections.KotlinAp
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.applicable.inspections.KotlinModCommandQuickFix
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.ApplicabilityRange
|
||||
import org.jetbrains.kotlin.idea.codeinsight.utils.callExpression
|
||||
import org.jetbrains.kotlin.idea.codeinsights.impl.base.inspections.JavaCollectionsStaticMethodInspectionUtils.Utils
|
||||
import org.jetbrains.kotlin.idea.codeinsights.impl.base.inspections.JavaCollectionsStaticMethodInspectionUtils.getMethodIfItsArgumentIsMutableList
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
// In K2, it's ReplaceJavaStaticMethodWithKotlinAnalogInspection
|
||||
@@ -52,17 +52,13 @@ internal class JavaCollectionsStaticMethodInspection :
|
||||
}
|
||||
|
||||
override fun KaSession.prepareContext(element: KtDotQualifiedExpression): Context? {
|
||||
val (methodName, firstArg) = getTargetMethodOnMutableList(element) ?: return null
|
||||
val (methodName, firstArg) = getMethodIfItsArgumentIsMutableList(element) ?: return null
|
||||
return Context(methodName, firstArg)
|
||||
}
|
||||
|
||||
override fun getApplicableRanges(element: KtDotQualifiedExpression): List<TextRange> =
|
||||
ApplicabilityRange.self(element)
|
||||
|
||||
context(_: KaSession)
|
||||
private fun getTargetMethodOnMutableList(expression: KtDotQualifiedExpression): Pair<String, KtValueArgument>? =
|
||||
Utils.getTargetMethod(expression) { type -> Utils.isMutableListOrSubtype(type) }
|
||||
|
||||
private class ReplaceWithStdLibFix(private val methodName: String, private val receiver: String) :
|
||||
KotlinModCommandQuickFix<KtDotQualifiedExpression>() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user