Inline refactoring: should remove redundant Unit
#KT-19443 Fixed
This commit is contained in:
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||
import org.jetbrains.kotlin.idea.core.*
|
||||
import org.jetbrains.kotlin.idea.inspections.RedundantUnitExpressionInspection
|
||||
import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention
|
||||
import org.jetbrains.kotlin.idea.util.CommentSaver
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
@@ -407,27 +408,29 @@ class CodeInliner<TCallElement : KtElement>(
|
||||
}
|
||||
|
||||
private fun postProcessInsertedCode(range: PsiChildRange, lexicalScope: LexicalScope?): PsiChildRange {
|
||||
val elements = range.filterIsInstance<KtElement>().toList()
|
||||
if (elements.isEmpty()) return PsiChildRange.EMPTY
|
||||
val pointers = range.filterIsInstance<KtElement>().map { it.createSmartPointer() }.toList()
|
||||
if (pointers.isEmpty()) return PsiChildRange.EMPTY
|
||||
|
||||
lexicalScope?.let {
|
||||
renameDuplicates(elements.dropLast(1).filterIsInstance<KtNamedDeclaration>(), it)
|
||||
renameDuplicates(pointers.dropLast(1).mapNotNull { pointer -> pointer.element as? KtNamedDeclaration }, it)
|
||||
}
|
||||
|
||||
elements.forEach {
|
||||
introduceNamedArguments(it)
|
||||
for (pointer in pointers) {
|
||||
val element = pointer.element ?: continue
|
||||
introduceNamedArguments(element)
|
||||
|
||||
restoreFunctionLiteralArguments(it)
|
||||
restoreFunctionLiteralArguments(element)
|
||||
|
||||
//TODO: do this earlier
|
||||
dropArgumentsForDefaultValues(it)
|
||||
dropArgumentsForDefaultValues(element)
|
||||
|
||||
simplifySpreadArrayOfArguments(it)
|
||||
simplifySpreadArrayOfArguments(element)
|
||||
|
||||
removeExplicitTypeArguments(it)
|
||||
removeExplicitTypeArguments(element)
|
||||
|
||||
removeRedundantUnitExpressions(element)
|
||||
}
|
||||
|
||||
|
||||
val shortenFilter = { element: PsiElement ->
|
||||
if (element[USER_CODE_KEY]) {
|
||||
ShortenReferences.FilterResult.SKIP
|
||||
@@ -440,11 +443,13 @@ class CodeInliner<TCallElement : KtElement>(
|
||||
}
|
||||
}
|
||||
|
||||
val newElements = elements.map {
|
||||
ShortenReferences { ShortenReferences.Options(removeThis = true) }.process(it, elementFilter = shortenFilter)
|
||||
val newElements = pointers.mapNotNull {
|
||||
it.element?.let { element ->
|
||||
ShortenReferences { ShortenReferences.Options(removeThis = true) }.process(element, elementFilter = shortenFilter)
|
||||
}
|
||||
}
|
||||
|
||||
newElements.forEach { element ->
|
||||
for (element in newElements) {
|
||||
// clean up user data
|
||||
element.forEachDescendantOfType<KtExpression> {
|
||||
it.clear(USER_CODE_KEY)
|
||||
@@ -460,7 +465,15 @@ class CodeInliner<TCallElement : KtElement>(
|
||||
}
|
||||
}
|
||||
|
||||
return PsiChildRange(newElements.first(), newElements.last())
|
||||
return if (newElements.isEmpty()) PsiChildRange.EMPTY else PsiChildRange(newElements.first(), newElements.last())
|
||||
}
|
||||
|
||||
private fun removeRedundantUnitExpressions(result: KtElement) {
|
||||
result.forEachDescendantOfType<KtReferenceExpression> {
|
||||
if (RedundantUnitExpressionInspection.isRedundantUnit(it)) {
|
||||
it.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun introduceNamedArguments(result: KtElement) {
|
||||
|
||||
@@ -2,9 +2,9 @@ fun <T> doIt(p: () -> T): T = TODO()
|
||||
|
||||
fun g(p: String?) {
|
||||
|
||||
p?.let { Unit }
|
||||
p?.let { }
|
||||
}
|
||||
|
||||
fun h() = Unit
|
||||
|
||||
fun x() = doIt { Unit }
|
||||
fun x() = doIt { }
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
fun <T> doIt(p: () -> T): T = p()
|
||||
fun Any.doDo() = Unit
|
||||
|
||||
abstract class A {
|
||||
abstract fun a()
|
||||
}
|
||||
|
||||
fun foo<caret>() {
|
||||
null?.doDo()
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
override fun a() = doIt {
|
||||
foo()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fun <T> doIt(p: () -> T): T = p()
|
||||
fun Any.doDo() = Unit
|
||||
|
||||
abstract class A {
|
||||
abstract fun a()
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
override fun a() = doIt {
|
||||
null?.doDo()
|
||||
Unit
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
fun <T> doIt(p: () -> T): T = p()
|
||||
fun Any.doDo() = Unit
|
||||
|
||||
abstract class A {
|
||||
abstract fun a()
|
||||
}
|
||||
|
||||
fun foo<caret>() {
|
||||
1.let { it.let { it.let { it.let { null?.doDo() } } } }
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
override fun a() = doIt {
|
||||
foo()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fun <T> doIt(p: () -> T): T = p()
|
||||
fun Any.doDo() = Unit
|
||||
|
||||
abstract class A {
|
||||
abstract fun a()
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
override fun a() = doIt {
|
||||
1.let { it.let { it.let { it.let { null?.doDo() } } } }
|
||||
Unit
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fun <T> doIt(p: () -> T): T = p()
|
||||
fun Any.doDo() = Unit
|
||||
|
||||
abstract class A {
|
||||
abstract fun a()
|
||||
}
|
||||
|
||||
fun foo<caret>(): Unit = doIt {
|
||||
1.let { it.let { it.let { it.let { null?.doDo() } } } }
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
override fun a() = foo()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fun <T> doIt(p: () -> T): T = p()
|
||||
fun Any.doDo() = Unit
|
||||
|
||||
abstract class A {
|
||||
abstract fun a()
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
override fun a() = doIt {
|
||||
1.let<Int, Unit> { it.let { it.let { it.let { null?.doDo() } } } }
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ class C {
|
||||
p?.let {
|
||||
println(3)
|
||||
println(4)
|
||||
Unit
|
||||
}
|
||||
|
||||
if (other != null) {
|
||||
@@ -26,6 +25,5 @@ class C {
|
||||
fun x() = doIt {
|
||||
println(9)
|
||||
println(10)
|
||||
Unit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
class C {
|
||||
fun <caret>f(p1: Int, p2: Int) {
|
||||
println(p1)
|
||||
nonUnit(p2)
|
||||
}
|
||||
|
||||
fun nonUnit(p: Int): Int = p
|
||||
|
||||
fun <T> doIt(p: () -> T): T = TODO()
|
||||
|
||||
fun x() = doIt<Unit> { f(9, 10) }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class C {
|
||||
|
||||
fun nonUnit(p: Int): Int = p
|
||||
|
||||
fun <T> doIt(p: () -> T): T = TODO()
|
||||
|
||||
fun x() = doIt<Unit> {
|
||||
println(9)
|
||||
nonUnit(10)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
fun <T> doIt(p: () -> T): T = p()
|
||||
fun Any.doDo() = Unit
|
||||
|
||||
abstract class A {
|
||||
abstract fun a()
|
||||
}
|
||||
|
||||
fun foo<caret>() {
|
||||
1.let { it.let { it.let { it.let { it?.doDo() } } } }
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
override fun a() = doIt {
|
||||
foo()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fun <T> doIt(p: () -> T): T = p()
|
||||
fun Any.doDo() = Unit
|
||||
|
||||
abstract class A {
|
||||
abstract fun a()
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
override fun a() = doIt {
|
||||
1.let { it.let { it.let { it.let { it?.doDo() } } } }
|
||||
}
|
||||
}
|
||||
+25
@@ -75,6 +75,21 @@ public class InlineTestGenerated extends AbstractInlineTest {
|
||||
runTest("idea/testData/refactoring/inline/function/MultipleReturns.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("NullableUnitReturnType.kt")
|
||||
public void testNullableUnitReturnType() throws Exception {
|
||||
runTest("idea/testData/refactoring/inline/function/NullableUnitReturnType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("NullableUnitReturnType2.kt")
|
||||
public void testNullableUnitReturnType2() throws Exception {
|
||||
runTest("idea/testData/refactoring/inline/function/NullableUnitReturnType2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("NullableUnitReturnType3.kt")
|
||||
public void testNullableUnitReturnType3() throws Exception {
|
||||
runTest("idea/testData/refactoring/inline/function/NullableUnitReturnType3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("OuterClassReceiver.kt")
|
||||
public void testOuterClassReceiver() throws Exception {
|
||||
runTest("idea/testData/refactoring/inline/function/OuterClassReceiver.kt");
|
||||
@@ -135,6 +150,16 @@ public class InlineTestGenerated extends AbstractInlineTest {
|
||||
runTest("idea/testData/refactoring/inline/function/UnitReturnType2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("UnitReturnType3.kt")
|
||||
public void testUnitReturnType3() throws Exception {
|
||||
runTest("idea/testData/refactoring/inline/function/UnitReturnType3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("UnitReturnType4.kt")
|
||||
public void testUnitReturnType4() throws Exception {
|
||||
runTest("idea/testData/refactoring/inline/function/UnitReturnType4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/refactoring/inline/function/expressionBody")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user