Skip to content

Commit

Permalink
Merge #7026
Browse files Browse the repository at this point in the history
7026: Improve `Convert to type` quick-fixes r=Undin a=Undin

These changes:
- refactor `Convert to type` quick-fixes. All common code is extracted into a single place, new base `ConvertToTyFix` class.
Also, now you can only pass `RsExpr` to the corresponding quick-fixes instead of any psi object
- omit default type parameters in a quick-fix text

changelog: Omit default type parameters in a `Convert to type` quick-fix text

Co-authored-by: Arseniy Pendryak <a.pendryak@yandex.ru>
  • Loading branch information
bors[bot] and Undin committed Mar 26, 2021
2 parents b3e6f53 + c9017b9 commit 72ff067
Show file tree
Hide file tree
Showing 14 changed files with 199 additions and 173 deletions.
2 changes: 1 addition & 1 deletion src/main/kotlin/org/rust/ide/annotator/fixes/AddAsTyFix.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import org.rust.lang.core.types.ty.Ty
/**
* For the given `expr` adds cast to the given type `ty`
*/
class AddAsTyFix(expr: PsiElement, val ty: Ty) : LocalQuickFixAndIntentionActionOnPsiElement(expr) {
class AddAsTyFix(expr: RsExpr, val ty: Ty) : LocalQuickFixAndIntentionActionOnPsiElement(expr) {

override fun getFamilyName(): String = "Add safe cast"

Expand Down
26 changes: 5 additions & 21 deletions src/main/kotlin/org/rust/ide/annotator/fixes/ConvertToStrFix.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

package org.rust.ide.annotator.fixes

import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
Expand All @@ -17,29 +16,14 @@ import org.rust.lang.core.psi.RsPsiFactory
* For the given `expr` adds `as_str()`/`as_mut_str()` method call. Note the fix doesn't attempt to verify that the type
* of `expr` is `String` and so doesn't check if adding the function call will produce a valid expression.
*/
abstract class ConvertToStrFix(expr: PsiElement) : LocalQuickFixAndIntentionActionOnPsiElement(expr) {

override fun getFamilyName(): String = "Convert to type"

override fun getText(): String = "Convert to ${getStrTypeName()} using `${getStrMethodName()}` method"
abstract class ConvertToStrFix(expr: RsExpr, strTypeName: String, private val strMethodName: String) :
ConvertToTyFix(expr, strTypeName, "`$strMethodName` method") {

override fun invoke(project: Project, file: PsiFile, editor: Editor?, startElement: PsiElement, endElement: PsiElement) {
if (startElement !is RsExpr) return
startElement.replace(RsPsiFactory(project).createNoArgsMethodCall(startElement, getStrMethodName()))
startElement.replace(RsPsiFactory(project).createNoArgsMethodCall(startElement, strMethodName))
}

protected abstract fun getStrMethodName(): String
protected abstract fun getStrTypeName(): String
}

class ConvertToImmutableStrFix(expr: PsiElement) : ConvertToStrFix(expr) {
override fun getStrMethodName(): String = "as_str"

override fun getStrTypeName(): String = "&str"
}

class ConvertToMutStrFix(expr: PsiElement) : ConvertToStrFix(expr) {
override fun getStrMethodName(): String = "as_mut_str"

override fun getStrTypeName(): String = "&mut str"
}
class ConvertToImmutableStrFix(expr: RsExpr) : ConvertToStrFix(expr, "&str", "as_str")
class ConvertToMutStrFix(expr: RsExpr) : ConvertToStrFix(expr, "&mut str", "as_mut_str")
29 changes: 29 additions & 0 deletions src/main/kotlin/org/rust/ide/annotator/fixes/ConvertToTyFix.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Use of this source code is governed by the MIT license that can be
* found in the LICENSE file.
*/

package org.rust.ide.annotator.fixes

import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement
import com.intellij.psi.PsiElement
import org.rust.ide.presentation.render
import org.rust.lang.core.psi.RsExpr
import org.rust.lang.core.types.ty.Ty

abstract class ConvertToTyFix : LocalQuickFixAndIntentionActionOnPsiElement {

private val tyName: String
private val convertSubject: String

constructor(expr: RsExpr, tyName: String, convertSubject: String): super(expr) {
this.tyName = tyName
this.convertSubject = convertSubject
}

constructor(expr: RsExpr, ty: Ty, convertSubject: String) :
this(expr, ty.render(skipUnchangedDefaultTypeArguments = true), convertSubject)

override fun getFamilyName(): String = "Convert to type"
override fun getText(): String = "Convert to $tyName using $convertSubject"
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

package org.rust.ide.annotator.fixes

import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
Expand All @@ -18,11 +17,7 @@ import org.rust.lang.core.types.ty.Ty
/**
* For the given `expr` converts it to the type `ty` with `ty::from(expr)`
*/
class ConvertToTyUsingFromTraitFix(expr: PsiElement, val ty: Ty) : LocalQuickFixAndIntentionActionOnPsiElement(expr) {
override fun getFamilyName(): String = "Convert to type"

override fun getText(): String = "Convert to $ty using `From` trait"

class ConvertToTyUsingFromTraitFix(expr: RsExpr, val ty: Ty) : ConvertToTyUsingTraitFix(expr, ty, "From") {
override fun invoke(
project: Project,
file: PsiFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

package org.rust.ide.annotator.fixes

import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
Expand All @@ -14,22 +13,27 @@ import org.rust.lang.core.psi.RsExpr
import org.rust.lang.core.psi.RsPsiFactory
import org.rust.lang.core.types.ty.Ty

abstract class ConvertToTyUsingTraitFix : ConvertToTyFix {
constructor(expr: RsExpr, tyName: String, traitName: String) : super(expr, tyName, "`$traitName` trait")
constructor(expr: RsExpr, ty: Ty, traitName: String) : super(expr, ty, "`$traitName` trait")
}

/**
* For the given `expr` adds method call defined by [methodName]. Note the fix doesn't attempt to check the type
* of `expr` and so doesn't check if adding the function call will produce a valid expression. The conversion trait
* [traitName] and resulting type [tyName] are used only for messaging.
*/
abstract class ConvertToTyUsingTraitFix(
expr: PsiElement,
private val tyName: String,
private val traitName: String,
private val methodName: String) : LocalQuickFixAndIntentionActionOnPsiElement(expr) {
abstract class ConvertToTyUsingTraitMethodFix : ConvertToTyUsingTraitFix {

constructor(expr: PsiElement, ty: Ty, traitName: String, methodName: String) : this(expr, ty.toString(), traitName, methodName)
private val methodName: String

override fun getFamilyName(): String = "Convert to type"
constructor(expr: RsExpr, tyName: String, traitName: String, methodName: String) : super(expr, tyName, traitName) {
this.methodName = methodName
}

override fun getText(): String = "Convert to $tyName using `$traitName` trait"
constructor(expr: RsExpr, ty: Ty, traitName: String, methodName: String) : super(expr, ty, traitName) {
this.methodName = methodName
}

override fun invoke(project: Project, file: PsiFile, editor: Editor?, startElement: PsiElement, endElement: PsiElement) {
if (startElement !is RsExpr) return
Expand All @@ -40,30 +44,30 @@ abstract class ConvertToTyUsingTraitFix(
/**
* For the given `expr` converts it to the borrowed type with `borrow()` method.
*/
class ConvertToBorrowedTyFix(expr: PsiElement, ty: Ty) : ConvertToTyUsingTraitFix(expr, ty, "Borrow", "borrow")
class ConvertToBorrowedTyFix(expr: RsExpr, ty: Ty) : ConvertToTyUsingTraitMethodFix(expr, ty, "Borrow", "borrow")

/**
* For the given `expr` converts it to the borrowed type with `borrow_mut()` method.
*/
class ConvertToBorrowedTyWithMutFix(expr: PsiElement, ty: Ty) : ConvertToTyUsingTraitFix(expr, ty, "BorrowMut", "borrow_mut")
class ConvertToBorrowedTyWithMutFix(expr: RsExpr, ty: Ty) : ConvertToTyUsingTraitMethodFix(expr, ty, "BorrowMut", "borrow_mut")

/**
* For the given `expr` converts it to the borrowed type with `as_mut()` method.
*/
class ConvertToMutTyFix(expr: PsiElement, ty: Ty) : ConvertToTyUsingTraitFix(expr, ty, "AsMut", "as_mut")
class ConvertToMutTyFix(expr: RsExpr, ty: Ty) : ConvertToTyUsingTraitMethodFix(expr, ty, "AsMut", "as_mut")

/**
* For the given `expr` converts it to the reference type with `as_ref()` method.
*/
class ConvertToRefTyFix(expr: PsiElement, ty: Ty) : ConvertToTyUsingTraitFix(expr, ty, "AsRef", "as_ref")
class ConvertToRefTyFix(expr: RsExpr, ty: Ty) : ConvertToTyUsingTraitMethodFix(expr, ty, "AsRef", "as_ref")

/**
* For the given `expr` converts it to the owned type with `to_owned()` method.
*/
class ConvertToOwnedTyFix(expr: PsiElement, ty: Ty): ConvertToTyUsingTraitFix(expr, ty, "ToOwned", "to_owned")
class ConvertToOwnedTyFix(expr: RsExpr, ty: Ty): ConvertToTyUsingTraitMethodFix(expr, ty, "ToOwned", "to_owned")

/**
* For the given `expr` adds `to_string()` call. Note the fix doesn't attempt to check if adding the function call
* will produce a valid expression.
*/
class ConvertToStringFix(expr: PsiElement) : ConvertToTyUsingTraitFix(expr, "String", "ToString", "to_string")
class ConvertToStringFix(expr: RsExpr) : ConvertToTyUsingTraitMethodFix(expr, "String", "ToString", "to_string")
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

package org.rust.ide.annotator.fixes

import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
Expand All @@ -26,45 +25,41 @@ import org.rust.lang.core.types.type
* [fromCallMaker] is also not checked.
*/
abstract class ConvertToTyUsingTryTraitFix(
expr: PsiElement,
internal val ty: Ty,
private val traitName: String,
private val fromCallMaker: ConvertToTyUsingTryTraitFix.(RsPsiFactory, RsExpr) -> RsExpr)
: LocalQuickFixAndIntentionActionOnPsiElement(expr) {

override fun getFamilyName(): String = "Convert to type"

override fun getText(): String = "Convert to $ty using `$traitName` trait"
expr: RsExpr,
private val ty: Ty,
traitName: String,
private val fromCallMaker: ConvertToTyUsingTryTraitFix.(RsPsiFactory, RsExpr, Ty) -> RsExpr
) : ConvertToTyUsingTraitFix(expr, ty, traitName) {

override fun invoke(project: Project, file: PsiFile, editor: Editor?, startElement: PsiElement, endElement: PsiElement) {
if (startElement !is RsExpr) return
val rsPsiFactory = RsPsiFactory(project)
val fromCall = fromCallMaker(rsPsiFactory, startElement)
addFromCall(rsPsiFactory, startElement, fromCall)
val psiFactory = RsPsiFactory(project)
val fromCall = fromCallMaker(psiFactory, startElement, ty)
addFromCall(psiFactory, startElement, fromCall)
}

open fun addFromCall(rsPsiFactory: RsPsiFactory, startElement: RsExpr, fromCall: RsExpr) {
startElement.replace(fromCall)
open fun addFromCall(psiFactory: RsPsiFactory, expr: RsExpr, fromCall: RsExpr) {
expr.replace(fromCall)
}
}

/**
* Similar to [ConvertToTyUsingTryTraitFix], but also "unwraps" the result with `unwrap()` or `?`.
*/
abstract class ConvertToTyUsingTryTraitAndUnpackFix(
expr: PsiElement,
expr: RsExpr,
ty: Ty,
private val errTy: Ty,
traitName: String,
fromCallMaker: ConvertToTyUsingTryTraitFix.(RsPsiFactory, RsExpr) -> RsExpr)
: ConvertToTyUsingTryTraitFix(expr, ty, traitName, fromCallMaker) {
fromCallMaker: ConvertToTyUsingTryTraitFix.(RsPsiFactory, RsExpr, Ty) -> RsExpr
) : ConvertToTyUsingTryTraitFix(expr, ty, traitName, fromCallMaker) {

override fun addFromCall(rsPsiFactory: RsPsiFactory, startElement: RsExpr, fromCall: RsExpr) {
val parentFnRetTy = findParentFnOrLambdaRetTy(startElement)
override fun addFromCall(psiFactory: RsPsiFactory, expr: RsExpr, fromCall: RsExpr) {
val parentFnRetTy = findParentFnOrLambdaRetTy(expr)
when {
parentFnRetTy != null && isFnRetTyResultAndMatchErrTy(startElement, parentFnRetTy) ->
startElement.replace(rsPsiFactory.createTryExpression(fromCall))
else -> startElement.replace(rsPsiFactory.createNoArgsMethodCall(fromCall, "unwrap"))
parentFnRetTy != null && isFnRetTyResultAndMatchErrTy(expr, parentFnRetTy) ->
expr.replace(psiFactory.createTryExpression(fromCall))
else -> expr.replace(psiFactory.createNoArgsMethodCall(fromCall, "unwrap"))
}
}

Expand Down Expand Up @@ -92,35 +87,35 @@ abstract class ConvertToTyUsingTryTraitAndUnpackFix(
}

private const val TRY_FROM_TRAIT = "TryFrom"
private val TRY_FROM_CALL_MAKER: ConvertToTyUsingTryTraitFix.(RsPsiFactory, RsExpr) -> RsExpr =
{ rsPsiFactory, startElement -> rsPsiFactory.createAssocFunctionCall(ty.render(includeTypeArguments = false), "try_from", listOf(startElement)) }
private val TRY_FROM_CALL_MAKER: ConvertToTyUsingTryTraitFix.(RsPsiFactory, RsExpr, Ty) -> RsExpr =
{ psiFactory, expr, ty -> psiFactory.createAssocFunctionCall(ty.render(includeTypeArguments = false), "try_from", listOf(expr)) }

/**
* For the given `expr` converts it to the type `Result<ty, _>` with `ty::try_from(expr)`.
*/
class ConvertToTyUsingTryFromTraitFix(expr: PsiElement, ty: Ty) :
class ConvertToTyUsingTryFromTraitFix(expr: RsExpr, ty: Ty) :
ConvertToTyUsingTryTraitFix(expr, ty, TRY_FROM_TRAIT, TRY_FROM_CALL_MAKER)

/**
* For the given `expr` converts it to the type [ty] with `ty::try_from(expr).unwrap()` or `ty::try_from(expr)?` if
* possible.
*/
class ConvertToTyUsingTryFromTraitAndUnpackFix(expr: PsiElement, ty: Ty, errTy: Ty) :
class ConvertToTyUsingTryFromTraitAndUnpackFix(expr: RsExpr, ty: Ty, errTy: Ty) :
ConvertToTyUsingTryTraitAndUnpackFix(expr, ty, errTy, TRY_FROM_TRAIT, TRY_FROM_CALL_MAKER)

private const val FROM_STR_TRAIT = "FromStr"
private val PARSE_CALL_MAKER: ConvertToTyUsingTryTraitFix.(RsPsiFactory, RsExpr) -> RsExpr =
{ rsPsiFactory, startElement -> rsPsiFactory.createNoArgsMethodCall(startElement, "parse") }
private val PARSE_CALL_MAKER: ConvertToTyUsingTryTraitFix.(RsPsiFactory, RsExpr, Ty) -> RsExpr =
{ psiFactory, expr, _ -> psiFactory.createNoArgsMethodCall(expr, "parse") }

/**
* For the given `strExpr` converts it to the type `Result<ty, _>` with `strExpr.parse()`.
*/
class ConvertToTyUsingFromStrFix(strExpr: PsiElement, ty: Ty):
class ConvertToTyUsingFromStrFix(strExpr: RsExpr, ty: Ty):
ConvertToTyUsingTryTraitFix(strExpr, ty, FROM_STR_TRAIT, PARSE_CALL_MAKER)

/**
* For the given `strExpr` converts it to the type [ty] with `strExpr.parse().unwrap()` or
* `strExpr.parse()?` if possible.
*/
class ConvertToTyUsingFromStrAndUnpackFix(strExpr: PsiElement, ty: Ty, errTy: Ty) :
class ConvertToTyUsingFromStrAndUnpackFix(strExpr: RsExpr, ty: Ty, errTy: Ty) :
ConvertToTyUsingTryTraitAndUnpackFix(strExpr, ty, errTy, FROM_STR_TRAIT, PARSE_CALL_MAKER)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

package org.rust.ide.annotator.fixes

import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
Expand All @@ -27,14 +26,10 @@ data class DerefRefPath(val derefs: Int, val refs: List<Mutability>)
* `path.refs`. Note that correctness of the generated code is not verified.
*/
class ConvertToTyWithDerefsRefsFix(
expr: PsiElement,
val ty: Ty,
expr: RsExpr,
ty: Ty,
val path: DerefRefPath
) : LocalQuickFixAndIntentionActionOnPsiElement(expr) {
override fun getFamilyName(): String = "Convert to type"

override fun getText(): String = "Convert to $ty using ${formatRefs(path)}"

) : ConvertToTyFix(expr, ty, formatRefs(path)) {
override fun invoke(
project: Project,
file: PsiFile,
Expand Down

0 comments on commit 72ff067

Please sign in to comment.