diff --git a/idea/resources/inspectionDescriptions/LiftReturnOrAssignment.html b/idea/resources/inspectionDescriptions/LiftReturnOrAssignment.html index 4f10ebf98d8..bb5754fb7a3 100644 --- a/idea/resources/inspectionDescriptions/LiftReturnOrAssignment.html +++ b/idea/resources/inspectionDescriptions/LiftReturnOrAssignment.html @@ -1,6 +1,6 @@ -This inspection reports if and when statements that can be converted to expressions +This inspection reports if, when and try statements that can be converted to expressions by lifting return or assignment out. Typical example:
 fun foo(arg: Boolean): String {
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/LiftReturnOrAssignmentInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/LiftReturnOrAssignmentInspection.kt
index fff89647eeb..5446fb84ed0 100644
--- a/idea/src/org/jetbrains/kotlin/idea/inspections/LiftReturnOrAssignmentInspection.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/LiftReturnOrAssignmentInspection.kt
@@ -30,7 +30,7 @@ class LiftReturnOrAssignmentInspection : AbstractKotlinInspection() {
 
     override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
             object : KtVisitorVoid() {
-                private fun visitIfOrWhen(expression: KtExpression, keyword: PsiElement) {
+                private fun visitIfOrWhenOrTry(expression: KtExpression, keyword: PsiElement) {
                     if (expression.lineCount() > LINES_LIMIT) return
                     if (expression.isElseIf()) return
 
@@ -60,12 +60,19 @@ class LiftReturnOrAssignmentInspection : AbstractKotlinInspection() {
 
                 override fun visitIfExpression(expression: KtIfExpression) {
                     super.visitIfExpression(expression)
-                    visitIfOrWhen(expression, expression.ifKeyword)
+                    visitIfOrWhenOrTry(expression, expression.ifKeyword)
                 }
 
                 override fun visitWhenExpression(expression: KtWhenExpression) {
                     super.visitWhenExpression(expression)
-                    visitIfOrWhen(expression, expression.whenKeyword)
+                    visitIfOrWhenOrTry(expression, expression.whenKeyword)
+                }
+
+                override fun visitTryExpression(expression: KtTryExpression) {
+                    super.visitTryExpression(expression)
+                    expression.tryKeyword?.let {
+                        visitIfOrWhenOrTry(expression, it)
+                    }
                 }
             }
 
diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedFoldingUtils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedFoldingUtils.kt
index dc13095d2fd..3f094c0976f 100644
--- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedFoldingUtils.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedFoldingUtils.kt
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.idea.intentions.branches
 import org.jetbrains.kotlin.lexer.KtTokens
 import org.jetbrains.kotlin.psi.*
 import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
+import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
 import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
 import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
 import org.jetbrains.kotlin.types.typeUtil.isNothing
@@ -75,6 +76,12 @@ object BranchedFoldingUtils {
                     assignment != null || collectAssignmentsAndCheck(branch?.lastBlockStatementOrThis())
                 }
             }
+            is KtTryExpression -> {
+                e.tryBlockAndCatchBodies().all {
+                    val assignment = getFoldableBranchedAssignment(it)?.run { assignments.add(this) }
+                    assignment != null || collectAssignmentsAndCheck(it?.lastBlockStatementOrThis())
+                }
+            }
             is KtCallExpression -> {
                 e.analyze().getType(e)?.isNothing() ?: false
             }
@@ -83,13 +90,19 @@ object BranchedFoldingUtils {
             else -> false
         }
         if (!collectAssignmentsAndCheck(expression)) return -1
-        val firstAssignment = assignments.firstOrNull()
-        if (firstAssignment != null && assignments.any { !BranchedFoldingUtils.checkAssignmentsMatch(it, firstAssignment) }) {
+        val firstAssignment = assignments.firstOrNull() ?: return 0
+        if (assignments.any { !BranchedFoldingUtils.checkAssignmentsMatch(it, firstAssignment) }) {
             return -1
         }
         if (expression.anyDescendantOfType(
                 predicate = {
-                    it.operationToken in KtTokens.ALL_ASSIGNMENTS && it !in assignments
+                    if (it.operationToken in KtTokens.ALL_ASSIGNMENTS)
+                        if (it.getNonStrictParentOfType() != null)
+                            BranchedFoldingUtils.checkAssignmentsMatch(it, firstAssignment)
+                        else
+                            it !in assignments
+                    else
+                        false
                 }
         )) {
             return -1
@@ -128,6 +141,12 @@ object BranchedFoldingUtils {
                 else -> getFoldableReturns(branches)
             }
         }
+        is KtTryExpression -> {
+            if (expression.finallyBlock?.finalExpression?.let { getFoldableReturns(listOf(it)) }?.isNotEmpty() == true)
+                null
+            else
+                getFoldableReturns(expression.tryBlockAndCatchBodies())
+        }
         is KtCallExpression -> {
             if (expression.analyze().getType(expression)?.isNothing() == true) emptyList() else null
         }
@@ -157,6 +176,9 @@ object BranchedFoldingUtils {
                 is KtIfExpression -> e.branches.forEach { branch ->
                     getFoldableBranchedAssignment(branch)?.replaceWithRHS() ?: lift(branch?.lastBlockStatementOrThis())
                 }
+                is KtTryExpression -> e.tryBlockAndCatchBodies().forEach {
+                    getFoldableBranchedAssignment(it)?.replaceWithRHS() ?: lift(it?.lastBlockStatementOrThis())
+                }
             }
         }
         lift(expression)
@@ -177,9 +199,16 @@ object BranchedFoldingUtils {
                     getFoldableBranchedReturn(branch)?.replaceWithReturned() ?:
                     lift(branch?.lastBlockStatementOrThis())
                 }
+                is KtTryExpression -> e.tryBlockAndCatchBodies().forEach {
+                    getFoldableBranchedReturn(it)?.replaceWithReturned() ?:
+                    lift(it?.lastBlockStatementOrThis())
+                }
             }
         }
         lift(expression)
         expression.replace(KtPsiFactory(expression).createExpressionByPattern("return $0", expression))
     }
+
+    private fun KtTryExpression.tryBlockAndCatchBodies(): List = listOf(tryBlock) + catchClauses.map { it.catchBody }
+
 }
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/.inspection b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/.inspection
new file mode 100644
index 00000000000..6440b445789
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/.inspection
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.inspections.LiftReturnOrAssignmentInspection
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/basic.kt b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/basic.kt
new file mode 100644
index 00000000000..7abac1510c4
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/basic.kt
@@ -0,0 +1,11 @@
+// HIGHLIGHT: INFORMATION
+
+fun test() {
+    var res: String? = null
+
+    try {
+        res = "success"
+    } catch (e: Exception) {
+        throw e
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/basic.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/basic.kt.after
new file mode 100644
index 00000000000..42a8620149d
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/basic.kt.after
@@ -0,0 +1,11 @@
+// HIGHLIGHT: INFORMATION
+
+fun test() {
+    var res: String? = null
+
+    res = try {
+        "success"
+    } catch (e: Exception) {
+        throw e
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/block.kt b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/block.kt
new file mode 100644
index 00000000000..ebe301b9d96
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/block.kt
@@ -0,0 +1,15 @@
+// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
+
+fun doSomething() {}
+
+fun test() {
+    var res: String? = null
+
+    try {
+        doSomething()
+        res = "success"
+    } catch (e: Exception) {
+        doSomething()
+        res = "failure"
+    }
+}
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/block.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/block.kt.after
new file mode 100644
index 00000000000..3d210c002cf
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/block.kt.after
@@ -0,0 +1,15 @@
+// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
+
+fun doSomething() {}
+
+fun test() {
+    var res: String? = null
+
+    res = try {
+        doSomething()
+        "success"
+    } catch (e: Exception) {
+        doSomething()
+        "failure"
+    }
+}
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/cascade.kt b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/cascade.kt
new file mode 100644
index 00000000000..4f33dd59753
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/cascade.kt
@@ -0,0 +1,18 @@
+// WITH_RUNTIME
+fun test() {
+    var res: String? = null
+
+    try {
+        try {
+            res = "success"
+        } catch (e: Exception) {
+            TODO()
+        }
+    } catch (e: Exception) {
+        try {
+            TODO()
+        } catch (e: Exception) {
+            res = "failure"
+        }
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/cascade.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/cascade.kt.after
new file mode 100644
index 00000000000..f68d5353080
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/cascade.kt.after
@@ -0,0 +1,18 @@
+// WITH_RUNTIME
+fun test() {
+    var res: String? = null
+
+    res = try {
+        try {
+            "success"
+        } catch (e: Exception) {
+            TODO()
+        }
+    } catch (e: Exception) {
+        try {
+            TODO()
+        } catch (e: Exception) {
+            "failure"
+        }
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finally.kt b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finally.kt
new file mode 100644
index 00000000000..1409e5684fa
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finally.kt
@@ -0,0 +1,13 @@
+fun doSomething() {}
+
+fun test() {
+    var res: String? = null
+
+    try {
+        res = "success"
+    } catch (e: Exception) {
+        res = "failure"
+    } finally {
+        doSomething()
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finally.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finally.kt.after
new file mode 100644
index 00000000000..919c27e80f5
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finally.kt.after
@@ -0,0 +1,13 @@
+fun doSomething() {}
+
+fun test() {
+    var res: String? = null
+
+    res = try {
+        "success"
+    } catch (e: Exception) {
+        "failure"
+    } finally {
+        doSomething()
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithAssignment.kt b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithAssignment.kt
new file mode 100644
index 00000000000..7fc088c7e94
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithAssignment.kt
@@ -0,0 +1,12 @@
+// PROBLEM: none
+fun test() {
+    var res: String? = null
+
+    try {
+        res = "success"
+    } catch (e: Exception) {
+        res = "failure"
+    } finally {
+        res = "finally"
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithCascadeAssignment.kt b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithCascadeAssignment.kt
new file mode 100644
index 00000000000..ae4816aa4c1
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithCascadeAssignment.kt
@@ -0,0 +1,17 @@
+// PROBLEM: none
+fun doSomething() {}
+
+fun test(n: Int) {
+    var res: String? = null
+
+    try {
+        res = "success"
+    } catch (e: Exception) {
+        throw e
+    } finally {
+        if (n == 1)
+            doSomething()
+        else
+            res = "finally"
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithCascadeUnmatchedAssignment.kt b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithCascadeUnmatchedAssignment.kt
new file mode 100644
index 00000000000..b2b659d3a38
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithCascadeUnmatchedAssignment.kt
@@ -0,0 +1,17 @@
+fun doSomething() {}
+
+fun test(n: Int) {
+    var res: String? = null
+    var foo: String? = null
+
+    try {
+        res = "success"
+    } catch (e: Exception) {
+        throw e
+    } finally {
+        if (n == 1)
+            doSomething()
+        else
+            foo = "finally"
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithCascadeUnmatchedAssignment.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithCascadeUnmatchedAssignment.kt.after
new file mode 100644
index 00000000000..2a288f6b0cc
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithCascadeUnmatchedAssignment.kt.after
@@ -0,0 +1,17 @@
+fun doSomething() {}
+
+fun test(n: Int) {
+    var res: String? = null
+    var foo: String? = null
+
+    res = try {
+        "success"
+    } catch (e: Exception) {
+        throw e
+    } finally {
+        if (n == 1)
+            doSomething()
+        else
+            foo = "finally"
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithUnmatchedAssignments.kt b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithUnmatchedAssignments.kt
new file mode 100644
index 00000000000..ecc7b4d34fe
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithUnmatchedAssignments.kt
@@ -0,0 +1,12 @@
+fun test() {
+    var res: String? = null
+    var foo: String? = null
+
+    try {
+        res = "success"
+    } catch (e: Exception) {
+        res = "failure"
+    } finally {
+        foo = "finally"
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithUnmatchedAssignments.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithUnmatchedAssignments.kt.after
new file mode 100644
index 00000000000..b659a76aa87
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithUnmatchedAssignments.kt.after
@@ -0,0 +1,12 @@
+fun test() {
+    var res: String? = null
+    var foo: String? = null
+
+    res = try {
+        "success"
+    } catch (e: Exception) {
+        "failure"
+    } finally {
+        foo = "finally"
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/inner.kt b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/inner.kt
new file mode 100644
index 00000000000..53fec80dfbf
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/inner.kt
@@ -0,0 +1,14 @@
+fun test(n: Int) {
+    var res: String? = null
+
+    if (n == 1) {
+        try {
+            res = "success"
+        } catch (e: Exception) {
+            throw e
+        }
+    }
+    else {
+        res = "else"
+    }
+}
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/inner.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/inner.kt.after
new file mode 100644
index 00000000000..7552979c131
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/inner.kt.after
@@ -0,0 +1,14 @@
+fun test(n: Int) {
+    var res: String? = null
+
+    if (n == 1) {
+        res = try {
+            "success"
+        } catch (e: Exception) {
+            throw e
+        }
+    }
+    else {
+        res = "else"
+    }
+}
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/withUnmatchedAssignments.kt b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/withUnmatchedAssignments.kt
new file mode 100644
index 00000000000..26440dff32a
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/withUnmatchedAssignments.kt
@@ -0,0 +1,11 @@
+// PROBLEM: none
+fun test() {
+    var res: String? = null
+    var foo: String? = null
+
+    try {
+        res = "success"
+    } catch (e: Exception) {
+        foo = "exception"
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToAssignment/withoutTerminatingAssignment.kt b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/withoutTerminatingAssignment.kt
new file mode 100644
index 00000000000..a4ab7eb3fbc
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToAssignment/withoutTerminatingAssignment.kt
@@ -0,0 +1,13 @@
+// PROBLEM: none
+fun doSomething() {}
+
+fun test() {
+    var res: String? = null
+
+    try {
+        res = "success"
+    } catch (e: Exception) {
+        res = "failure"
+        doSomething()
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/.inspection b/idea/testData/inspectionsLocal/liftOut/tryToReturn/.inspection
new file mode 100644
index 00000000000..6440b445789
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/.inspection
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.inspections.LiftReturnOrAssignmentInspection
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/basic.kt b/idea/testData/inspectionsLocal/liftOut/tryToReturn/basic.kt
new file mode 100644
index 00000000000..36cc2a70eb7
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/basic.kt
@@ -0,0 +1,9 @@
+// HIGHLIGHT: INFORMATION
+
+fun test(): String {
+    try {
+        return "success"
+    } catch (e: Exception) {
+        throw e
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/basic.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToReturn/basic.kt.after
new file mode 100644
index 00000000000..a149d62093a
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/basic.kt.after
@@ -0,0 +1,9 @@
+// HIGHLIGHT: INFORMATION
+
+fun test(): String {
+    return try {
+        "success"
+    } catch (e: Exception) {
+        throw e
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/block.kt b/idea/testData/inspectionsLocal/liftOut/tryToReturn/block.kt
new file mode 100644
index 00000000000..15a33efef2c
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/block.kt
@@ -0,0 +1,13 @@
+// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
+
+fun doSomething() {}
+
+fun test(): String {
+    try {
+        doSomething()
+        return "success"
+    } catch (e: Exception) {
+        doSomething()
+        return "failure"
+    }
+}
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/block.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToReturn/block.kt.after
new file mode 100644
index 00000000000..4ae23d81b6a
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/block.kt.after
@@ -0,0 +1,13 @@
+// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
+
+fun doSomething() {}
+
+fun test(): String {
+    return try {
+        doSomething()
+        "success"
+    } catch (e: Exception) {
+        doSomething()
+        "failure"
+    }
+}
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/cascade.kt b/idea/testData/inspectionsLocal/liftOut/tryToReturn/cascade.kt
new file mode 100644
index 00000000000..3a3ad993910
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/cascade.kt
@@ -0,0 +1,16 @@
+// WITH_RUNTIME
+fun test(): String {
+    try {
+        try {
+            return "success"
+        } catch (e: Exception) {
+            TODO()
+        }
+    } catch (e: Exception) {
+        try {
+            TODO()
+        } catch (e: Exception) {
+            return "failure"
+        }
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/cascade.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToReturn/cascade.kt.after
new file mode 100644
index 00000000000..0b6a1789058
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/cascade.kt.after
@@ -0,0 +1,16 @@
+// WITH_RUNTIME
+fun test(): String {
+    return try {
+        try {
+            "success"
+        } catch (e: Exception) {
+            TODO()
+        }
+    } catch (e: Exception) {
+        try {
+            TODO()
+        } catch (e: Exception) {
+            "failure"
+        }
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/finally.kt b/idea/testData/inspectionsLocal/liftOut/tryToReturn/finally.kt
new file mode 100644
index 00000000000..ecee03fc466
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/finally.kt
@@ -0,0 +1,11 @@
+fun doSomething() {}
+
+fun test(): String {
+    try {
+        return "success"
+    } catch (e: Exception) {
+        return "failure"
+    } finally {
+        doSomething()
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/finally.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToReturn/finally.kt.after
new file mode 100644
index 00000000000..8f333970227
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/finally.kt.after
@@ -0,0 +1,11 @@
+fun doSomething() {}
+
+fun test(): String {
+    return try {
+        "success"
+    } catch (e: Exception) {
+        "failure"
+    } finally {
+        doSomething()
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/finallyWithCascadeReturn.kt b/idea/testData/inspectionsLocal/liftOut/tryToReturn/finallyWithCascadeReturn.kt
new file mode 100644
index 00000000000..37444b1248c
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/finallyWithCascadeReturn.kt
@@ -0,0 +1,14 @@
+fun doSomething() {}
+
+fun test(n: Int): String {
+    try {
+        return "success"
+    } catch (e: Exception) {
+        throw e
+    } finally {
+        if (n == 1)
+            doSomething()
+        else
+            return "finally"
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/finallyWithCascadeReturn.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToReturn/finallyWithCascadeReturn.kt.after
new file mode 100644
index 00000000000..bde085ac45d
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/finallyWithCascadeReturn.kt.after
@@ -0,0 +1,14 @@
+fun doSomething() {}
+
+fun test(n: Int): String {
+    return try {
+        "success"
+    } catch (e: Exception) {
+        throw e
+    } finally {
+        if (n == 1)
+            doSomething()
+        else
+            return "finally"
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/finallyWithReturn.kt b/idea/testData/inspectionsLocal/liftOut/tryToReturn/finallyWithReturn.kt
new file mode 100644
index 00000000000..8163a7c29bb
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/finallyWithReturn.kt
@@ -0,0 +1,10 @@
+// PROBLEM: none
+fun test(): String {
+    try {
+        return "success"
+    } catch (e: Exception) {
+        return "failure"
+    } finally {
+        return "finally"
+    }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/inner.kt b/idea/testData/inspectionsLocal/liftOut/tryToReturn/inner.kt
new file mode 100644
index 00000000000..b43768d433f
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/inner.kt
@@ -0,0 +1,12 @@
+fun test(n: Int): String {
+    if (n == 1) {
+        try {
+            return "success"
+        } catch (e: Exception) {
+            throw e
+        }
+    }
+    else {
+        return "else"
+    }
+}
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/inner.kt.after b/idea/testData/inspectionsLocal/liftOut/tryToReturn/inner.kt.after
new file mode 100644
index 00000000000..ee6417d68b0
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/inner.kt.after
@@ -0,0 +1,12 @@
+fun test(n: Int): String {
+    if (n == 1) {
+        return try {
+            "success"
+        } catch (e: Exception) {
+            throw e
+        }
+    }
+    else {
+        return "else"
+    }
+}
diff --git a/idea/testData/inspectionsLocal/liftOut/tryToReturn/withoutReturn.kt b/idea/testData/inspectionsLocal/liftOut/tryToReturn/withoutReturn.kt
new file mode 100644
index 00000000000..7c850582b10
--- /dev/null
+++ b/idea/testData/inspectionsLocal/liftOut/tryToReturn/withoutReturn.kt
@@ -0,0 +1,11 @@
+// ERROR: A 'return' expression required in a function with a block body ('{...}')
+// PROBLEM: none
+fun doSomething() {}
+
+fun test(): String {
+    try {
+        return "success"
+    } catch (e: Exception) {
+        doSomething()
+    }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
index 1f25bc0bae9..9d6ce6195bb 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
@@ -629,6 +629,138 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
             }
         }
 
+        @TestMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment")
+        @TestDataPath("$PROJECT_ROOT")
+        @RunWith(JUnit3RunnerWithInners.class)
+        public static class TryToAssignment extends AbstractLocalInspectionTest {
+            public void testAllFilesPresentInTryToAssignment() throws Exception {
+                KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/liftOut/tryToAssignment"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
+            }
+
+            @TestMetadata("basic.kt")
+            public void testBasic() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment/basic.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("block.kt")
+            public void testBlock() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment/block.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("cascade.kt")
+            public void testCascade() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment/cascade.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("finally.kt")
+            public void testFinally() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment/finally.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("finallyWithAssignment.kt")
+            public void testFinallyWithAssignment() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithAssignment.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("finallyWithCascadeAssignment.kt")
+            public void testFinallyWithCascadeAssignment() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithCascadeAssignment.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("finallyWithCascadeUnmatchedAssignment.kt")
+            public void testFinallyWithCascadeUnmatchedAssignment() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithCascadeUnmatchedAssignment.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("finallyWithUnmatchedAssignments.kt")
+            public void testFinallyWithUnmatchedAssignments() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment/finallyWithUnmatchedAssignments.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("inner.kt")
+            public void testInner() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment/inner.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("withUnmatchedAssignments.kt")
+            public void testWithUnmatchedAssignments() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment/withUnmatchedAssignments.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("withoutTerminatingAssignment.kt")
+            public void testWithoutTerminatingAssignment() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToAssignment/withoutTerminatingAssignment.kt");
+                doTest(fileName);
+            }
+        }
+
+        @TestMetadata("idea/testData/inspectionsLocal/liftOut/tryToReturn")
+        @TestDataPath("$PROJECT_ROOT")
+        @RunWith(JUnit3RunnerWithInners.class)
+        public static class TryToReturn extends AbstractLocalInspectionTest {
+            public void testAllFilesPresentInTryToReturn() throws Exception {
+                KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/liftOut/tryToReturn"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
+            }
+
+            @TestMetadata("basic.kt")
+            public void testBasic() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToReturn/basic.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("block.kt")
+            public void testBlock() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToReturn/block.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("cascade.kt")
+            public void testCascade() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToReturn/cascade.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("finally.kt")
+            public void testFinally() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToReturn/finally.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("finallyWithCascadeReturn.kt")
+            public void testFinallyWithCascadeReturn() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToReturn/finallyWithCascadeReturn.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("finallyWithReturn.kt")
+            public void testFinallyWithReturn() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToReturn/finallyWithReturn.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("inner.kt")
+            public void testInner() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToReturn/inner.kt");
+                doTest(fileName);
+            }
+
+            @TestMetadata("withoutReturn.kt")
+            public void testWithoutReturn() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/liftOut/tryToReturn/withoutReturn.kt");
+                doTest(fileName);
+            }
+        }
+
         @TestMetadata("idea/testData/inspectionsLocal/liftOut/whenToAssignment")
         @TestDataPath("$PROJECT_ROOT")
         @RunWith(JUnit3RunnerWithInners.class)