KT-12100 convert try / finally to use: report intention only at try {
This commit is contained in:
+22
-18
@@ -17,11 +17,14 @@
|
||||
package org.jetbrains.kotlin.idea.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.contentRange
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
@@ -33,7 +36,7 @@ class ConvertTryFinallyToUseCallInspection : IntentionBasedInspection<KtTryExpre
|
||||
override fun inspectionTarget(element: KtTryExpression) = element.tryKeyword ?: element.tryBlock
|
||||
}
|
||||
|
||||
class ConvertTryFinallyToUseCallIntention : SelfTargetingOffsetIndependentIntention<KtTryExpression>(
|
||||
class ConvertTryFinallyToUseCallIntention : SelfTargetingRangeIntention<KtTryExpression>(
|
||||
KtTryExpression::class.java, "Convert try-finally to .use()"
|
||||
) {
|
||||
override fun applyTo(element: KtTryExpression, editor: Editor?) {
|
||||
@@ -69,36 +72,37 @@ class ConvertTryFinallyToUseCallIntention : SelfTargetingOffsetIndependentIntent
|
||||
element.replace(useCallExpression)
|
||||
}
|
||||
|
||||
override fun isApplicableTo(element: KtTryExpression): Boolean {
|
||||
override fun applicabilityRange(element: KtTryExpression): TextRange? {
|
||||
// Single statement in finally, no catch blocks
|
||||
val finallySection = element.finallyBlock ?: return false
|
||||
val finallyExpression = finallySection.finalExpression.statements.singleOrNull() ?: return false
|
||||
if (element.catchClauses.isNotEmpty()) return false
|
||||
val finallySection = element.finallyBlock ?: return null
|
||||
val finallyExpression = finallySection.finalExpression.statements.singleOrNull() ?: return null
|
||||
if (element.catchClauses.isNotEmpty()) return null
|
||||
|
||||
val context = element.analyze()
|
||||
val resolvedCall = finallyExpression.getResolvedCall(context) ?: return false
|
||||
if (resolvedCall.candidateDescriptor.name.asString() != "close") return false
|
||||
if (resolvedCall.extensionReceiver != null) return false
|
||||
val receiver = resolvedCall.dispatchReceiver ?: return false
|
||||
val resolvedCall = finallyExpression.getResolvedCall(context) ?: return null
|
||||
if (resolvedCall.candidateDescriptor.name.asString() != "close") return null
|
||||
if (resolvedCall.extensionReceiver != null) return null
|
||||
val receiver = resolvedCall.dispatchReceiver ?: return null
|
||||
if (receiver.type.supertypes().all {
|
||||
it.constructor.declarationDescriptor?.fqNameSafe?.asString().let {
|
||||
it != "java.io.Closeable" && it != "java.lang.AutoCloseable"
|
||||
}
|
||||
}) return false
|
||||
}) return null
|
||||
|
||||
return when (receiver) {
|
||||
when (receiver) {
|
||||
is ExpressionReceiver -> {
|
||||
val expression = receiver.expression
|
||||
if (expression is KtThisExpression) true
|
||||
else {
|
||||
val resourceReference = expression as? KtReferenceExpression ?: return false
|
||||
if (expression !is KtThisExpression) {
|
||||
val resourceReference = expression as? KtReferenceExpression ?: return null
|
||||
val resourceDescriptor =
|
||||
context[BindingContext.REFERENCE_TARGET, resourceReference] as? VariableDescriptor ?: return false
|
||||
!resourceDescriptor.isVar
|
||||
context[BindingContext.REFERENCE_TARGET, resourceReference] as? VariableDescriptor ?: return null
|
||||
if (resourceDescriptor.isVar) return null
|
||||
}
|
||||
}
|
||||
is ImplicitReceiver -> true
|
||||
else -> false
|
||||
is ImplicitReceiver -> {}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
return TextRange(element.startOffset, element.tryBlock.lBrace?.endOffset ?: element.endOffset)
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,13 @@ import java.io.IOException
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val reader = File("hello-world.txt").bufferedReader()
|
||||
try {
|
||||
<caret>try {
|
||||
reader.readLine()
|
||||
}
|
||||
catch (e: IOException) {
|
||||
|
||||
}
|
||||
<caret>finally {
|
||||
finally {
|
||||
reader.close()
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@ import java.io.File
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val reader = File("hello-world.txt").bufferedReader()
|
||||
try {
|
||||
<caret>try {
|
||||
// do stuff with reader
|
||||
}
|
||||
<caret>finally {
|
||||
finally {
|
||||
reader.close()
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@ import java.io.File
|
||||
import java.io.BufferedReader
|
||||
|
||||
fun BufferedReader.foo() {
|
||||
try {
|
||||
try <caret>{
|
||||
readLine()
|
||||
}
|
||||
<caret>finally {
|
||||
finally {
|
||||
close()
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,10 @@ import java.io.File
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val reader = File("hello-world.txt").bufferedReader()
|
||||
try {
|
||||
<caret>try {
|
||||
reader.readLine()
|
||||
}
|
||||
<caret>finally {
|
||||
finally {
|
||||
reader.readLine()
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,10 @@ import java.io.File
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val reader = File("hello-world.txt").bufferedReader()
|
||||
try {
|
||||
try<caret> {
|
||||
reader.readLine()
|
||||
}
|
||||
<caret>finally {
|
||||
finally {
|
||||
reader.readLine()
|
||||
reader.close()
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ import java.io.File
|
||||
import java.io.BufferedReader
|
||||
|
||||
fun foo(reader: BufferedReader) {
|
||||
try {
|
||||
try <caret>{
|
||||
reader.readLine()
|
||||
}
|
||||
<caret>finally {
|
||||
finally {
|
||||
reader.close()
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,11 @@ import java.io.BufferedReader
|
||||
fun bar() {}
|
||||
|
||||
fun foo(reader: BufferedReader?) {
|
||||
try {
|
||||
<caret>try {
|
||||
reader?.readLine()
|
||||
bar()
|
||||
}
|
||||
<caret>finally {
|
||||
finally {
|
||||
reader?.close()
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@ import java.io.File
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val reader = File("hello-world.txt").bufferedReader()
|
||||
try {
|
||||
try <caret>{
|
||||
reader.readLine()
|
||||
}
|
||||
<caret>finally {
|
||||
finally {
|
||||
reader.close()
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@ import java.io.File
|
||||
import java.io.BufferedReader
|
||||
|
||||
fun BufferedReader.foo() {
|
||||
try {
|
||||
<caret>try {
|
||||
this.readLine()
|
||||
}
|
||||
<caret>finally {
|
||||
finally {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,10 @@ class MyCloseable : Closeable {
|
||||
fun process(x: Int) = x
|
||||
|
||||
fun Int.foo() {
|
||||
try {
|
||||
<caret>try {
|
||||
this@MyCloseable.process(this)
|
||||
}
|
||||
<caret>finally {
|
||||
finally {
|
||||
this@MyCloseable.close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ import java.io.File
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val writer = File("hello-world.txt").bufferedWriter()
|
||||
try {
|
||||
try <caret>{
|
||||
writer.write("123")
|
||||
writer.newLine()
|
||||
writer.write("456")
|
||||
}
|
||||
<caret>finally {
|
||||
finally {
|
||||
writer.close()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val reader = File("hello-world.txt").bufferedReader()
|
||||
try {
|
||||
reader.readLine()
|
||||
}
|
||||
finally {
|
||||
<caret>reader.close()
|
||||
}
|
||||
}
|
||||
@@ -6161,6 +6161,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertTryFinallyToUseCall/triple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("wrongCaret.kt")
|
||||
public void testWrongCaret() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertTryFinallyToUseCall/wrongCaret.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/copyConcatenatedStringToClipboard")
|
||||
|
||||
Reference in New Issue
Block a user