diktat icon indicating copy to clipboard operation
diktat copied to clipboard

Deprecated replaceWith - support in diktat

Open orchestr7 opened this issue 3 years ago • 6 comments

Kotlin has outstanding logic (deprecation scenarios) - library author can help user to fix the code. Probably in the future, when we will have all information about the project (and new framework)

@Deprecated("Old stuff", ReplaceWith("test2"))

orchestr7 avatar Jun 03 '22 13:06 orchestr7

Do you mean support it in diktat with autofix? "replaceWith" doesn't mean replacement 1:1

nulls avatar Jun 07 '22 06:06 nulls

Do you mean support it in diktat with autofix? "replaceWith" doesn't mean replacement 1:1

No, it actually does the logic in 90% of scenarios. IDEA uses it: https://dev.to/mreichelt/the-hidden-kotlin-gem-you-didn-t-think-you-ll-love-deprecations-with-replacewith-3blo

orchestr7 avatar Jun 07 '22 06:06 orchestr7

If we will support it as autofix logic -- we will produce irrelevant code in 10% of scenarios.

nulls avatar Jun 07 '22 06:06 nulls

If we will support it as autofix logic -- we will produce irrelevant code in 10% of scenarios.

How IDEA filters out false positives? They do absolutely the same

orchestr7 avatar Jun 07 '22 06:06 orchestr7

Yep, looks like I didn't get properly kotlin.ReplaceWith Tested locally -- IDEA doesn't check that ReplaceWith.expression is valid (developer is who triggers a replacement in IDEA). But I guess there is the assumption: if ReplaceWith.expression is set, it must be applicable and valid.

Make the following example (inspired by com.pinterest.ktlint.core.KtLint.ExperimentalParams vs com.pinterest.ktlint.core.KtLint.Params)

  1. replaceWith is valid
data class ParamsOld(
    val arg1: String,
    val arg2: String,
)

@Deprecated(
    message = "extended params",
    replaceWith = ReplaceWith("this.doLogicNew(ParamsNew(params.arg1, params.arg2, arg3))", imports = ["ParamsNew"])
)
fun doLogicOld(params: ParamsOld, arg3: String) {
    println("${params.arg1} -> ${params.arg2} -> ${arg3}")
}

data class ParamsNew(
    val arg1: String,
    val arg2: String,
    val arg3: String,
)

fun doLogicNew(params: ParamsNew) {
    println("${params.arg1} -> ${params.arg2} -> ${params.arg3}")
}

Usage:

fun test() {
    doLogicOld(ParamsOld("1", "2"), "3")
}

IDEA transforms it to (problem with whitespaces on new line)

fun test() {
    val params = ParamsOld("1", "2")
 doLogicNew(ParamsNew(params.arg1, params.arg2, "3"))
}
  1. replaceWith is invalid
// same example as previously, but
@Deprecated(
    message = "extended params",
    replaceWith = ReplaceWith("this.doLogicInvalid(ParamsNew(params.arg1, params.arg2, arg3))", imports = ["ParamsNew"])
)
fun doLogicOld(params: ParamsOld, arg3: String) {
    println("${params.arg1} -> ${params.arg2} -> ${arg3}")
}

IDEA transforms it to (funny, but it doesn't have problem with whitespaces on new line)

fun test() {
    val params = ParamsOld("1", "2")
    this.doLogicInvalid(ParamsNew(params.arg1, params.arg2, "3"))
}

nulls avatar Jun 07 '22 06:06 nulls

In response to the previous comment:

But I guess there is the assumption: if ReplaceWith.expression is set, it must be applicable and valid.

Exactly. And if my memory fails me not, there's an equivalent quickfix action in IDEA itself.

Additionally, a user can always switch a particular DiKTat inspection off is they desire so.