Redundant async: extract generateConversion, integrate arguments inside

This commit is contained in:
Mikhail Glukhikh
2018-11-28 14:40:44 +03:00
parent d909162a89
commit c4717d17d9
2 changed files with 39 additions and 28 deletions
@@ -63,7 +63,7 @@ abstract class AbstractCallChainChecker : AbstractKotlinInspection() {
constructor(first: KtExpression, second: KtExpression) : this(first.text, second.text) constructor(first: KtExpression, second: KtExpression) : this(first.text, second.text)
} }
data class Conversion(val firstFqName: String, val secondFqName: String, val replacement: String) { data class Conversion(val firstFqName: String, val secondFqName: String, val replacement: String, val argumentList: String? = null) {
private fun String.convertToShort() = takeLastWhile { it != '.' } private fun String.convertToShort() = takeLastWhile { it != '.' }
val id: ConversionId get() = ConversionId(firstName, secondName) val id: ConversionId get() = ConversionId(firstName, secondName)
@@ -71,6 +71,10 @@ abstract class AbstractCallChainChecker : AbstractKotlinInspection() {
val firstName = firstFqName.convertToShort() val firstName = firstFqName.convertToShort()
val secondName = secondFqName.convertToShort() val secondName = secondFqName.convertToShort()
fun withArgumentList(argumentList: String) = Conversion(firstFqName, secondFqName, replacement, argumentList)
val fullReplacement: String get() = replacement + (argumentList ?: "")
} }
companion object { companion object {
@@ -15,43 +15,50 @@ import org.jetbrains.kotlin.psi.qualifiedExpressionVisitor
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
class RedundantAsyncInspection : AbstractCallChainChecker() { class RedundantAsyncInspection : AbstractCallChainChecker() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) =
qualifiedExpressionVisitor(fun(expression) {
var defaultContext: Boolean? = null
var defaultStart: Boolean? = null
// Temporary forbid cases with explicit scope
if (expression.receiverExpression is KtQualifiedExpression) return
val conversion = findQualifiedConversion(expression, conversionGroups) check@{ _, firstResolvedCall, _, _ -> private fun generateConversion(expression: KtQualifiedExpression): Conversion? {
for ((parameterDescriptor, valueArgument) in firstResolvedCall.valueArguments) { var defaultContext: Boolean? = null
val default = valueArgument is DefaultValueArgument var defaultStart: Boolean? = null
when (parameterDescriptor.name.asString()) { // Temporary forbid cases with explicit scope
"context" -> defaultContext = default if (expression.receiverExpression is KtQualifiedExpression) return null
"start" -> defaultStart = default
}
}
true
} ?: return
defaultContext ?: return
defaultStart ?: return
if (defaultContext!! && !defaultStart!!) return
var replacement = conversion.replacement var conversion = findQualifiedConversion(expression, conversionGroups) check@{ _, firstResolvedCall, _, _ ->
if (defaultContext!! && defaultStart!!) { for ((parameterDescriptor, valueArgument) in firstResolvedCall.valueArguments) {
if (conversion === conversions[0]) { val default = valueArgument is DefaultValueArgument
replacement += "($defaultAsyncArgument)" when (parameterDescriptor.name.asString()) {
} else { "context" -> defaultContext = default
replacement += "($defaultAsyncArgumentExperimental)" "start" -> defaultStart = default
} }
} }
true
} ?: return null
defaultContext ?: return null
defaultStart ?: return null
if (defaultContext!! && !defaultStart!!) return null
if (defaultContext!! && defaultStart!!) {
conversion = conversion.withArgumentList(
if (conversion === conversions[0]) {
"($defaultAsyncArgument)"
} else {
"($defaultAsyncArgumentExperimental)"
}
)
}
return conversion
}
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) =
qualifiedExpressionVisitor(fun(expression) {
val conversion = generateConversion(expression) ?: return
val fullReplacement = conversion.fullReplacement
val descriptor = holder.manager.createProblemDescriptor( val descriptor = holder.manager.createProblemDescriptor(
expression, expression,
expression.firstCalleeExpression()!!.textRange.shiftRight(-expression.startOffset), expression.firstCalleeExpression()!!.textRange.shiftRight(-expression.startOffset),
"Redundant 'async' call may be reduced to '$replacement'", "Redundant 'async' call may be reduced to '$fullReplacement'",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
isOnTheFly, isOnTheFly,
SimplifyCallChainFix(replacement) SimplifyCallChainFix(fullReplacement)
) )
holder.registerProblem(descriptor) holder.registerProblem(descriptor)
}) })