From 9ea326870dc7c075eed94c3a3693ed373d6599c0 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 1 Dec 2016 19:36:53 +0300 Subject: [PATCH] KT-12100 convert try / finally to use: report intention only at try { --- .../ConvertTryFinallyToUseCallIntention.kt | 40 ++++++++++--------- .../convertTryFinallyToUseCall/catch.kt | 4 +- .../convertTryFinallyToUseCall/example.kt | 4 +- .../implicitReceiver.kt | 4 +- .../convertTryFinallyToUseCall/notClose.kt | 4 +- .../notOnlyClose.kt | 4 +- .../convertTryFinallyToUseCall/parameter.kt | 4 +- .../convertTryFinallyToUseCall/safeCall.kt | 4 +- .../convertTryFinallyToUseCall/simple.kt | 4 +- .../convertTryFinallyToUseCall/this.kt | 4 +- .../convertTryFinallyToUseCall/thisLabeled.kt | 4 +- .../convertTryFinallyToUseCall/triple.kt | 4 +- .../convertTryFinallyToUseCall/wrongCaret.kt | 13 ++++++ .../intentions/IntentionTestGenerated.java | 6 +++ 14 files changed, 63 insertions(+), 40 deletions(-) create mode 100644 idea/testData/intentions/convertTryFinallyToUseCall/wrongCaret.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertTryFinallyToUseCallIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertTryFinallyToUseCallIntention.kt index e54f2050936..093a89357e2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertTryFinallyToUseCallIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertTryFinallyToUseCallIntention.kt @@ -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( +class ConvertTryFinallyToUseCallIntention : SelfTargetingRangeIntention( 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) } } \ No newline at end of file diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/catch.kt b/idea/testData/intentions/convertTryFinallyToUseCall/catch.kt index 1291bd4e5f8..f9dabd8e879 100644 --- a/idea/testData/intentions/convertTryFinallyToUseCall/catch.kt +++ b/idea/testData/intentions/convertTryFinallyToUseCall/catch.kt @@ -5,13 +5,13 @@ import java.io.IOException fun main(args: Array) { val reader = File("hello-world.txt").bufferedReader() - try { + try { reader.readLine() } catch (e: IOException) { } - finally { + finally { reader.close() } } \ No newline at end of file diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/example.kt b/idea/testData/intentions/convertTryFinallyToUseCall/example.kt index 1b51cd6fe81..27636df1689 100644 --- a/idea/testData/intentions/convertTryFinallyToUseCall/example.kt +++ b/idea/testData/intentions/convertTryFinallyToUseCall/example.kt @@ -3,10 +3,10 @@ import java.io.File fun main(args: Array) { val reader = File("hello-world.txt").bufferedReader() - try { + try { // do stuff with reader } - finally { + finally { reader.close() } } \ No newline at end of file diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/implicitReceiver.kt b/idea/testData/intentions/convertTryFinallyToUseCall/implicitReceiver.kt index 1ad4cc0f859..a4c43758ff4 100644 --- a/idea/testData/intentions/convertTryFinallyToUseCall/implicitReceiver.kt +++ b/idea/testData/intentions/convertTryFinallyToUseCall/implicitReceiver.kt @@ -3,10 +3,10 @@ import java.io.File import java.io.BufferedReader fun BufferedReader.foo() { - try { + try { readLine() } - finally { + finally { close() } } \ No newline at end of file diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/notClose.kt b/idea/testData/intentions/convertTryFinallyToUseCall/notClose.kt index d364490ee37..d0276048d3a 100644 --- a/idea/testData/intentions/convertTryFinallyToUseCall/notClose.kt +++ b/idea/testData/intentions/convertTryFinallyToUseCall/notClose.kt @@ -4,10 +4,10 @@ import java.io.File fun main(args: Array) { val reader = File("hello-world.txt").bufferedReader() - try { + try { reader.readLine() } - finally { + finally { reader.readLine() } } \ No newline at end of file diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/notOnlyClose.kt b/idea/testData/intentions/convertTryFinallyToUseCall/notOnlyClose.kt index 0e394be0741..9e42c03a338 100644 --- a/idea/testData/intentions/convertTryFinallyToUseCall/notOnlyClose.kt +++ b/idea/testData/intentions/convertTryFinallyToUseCall/notOnlyClose.kt @@ -4,10 +4,10 @@ import java.io.File fun main(args: Array) { val reader = File("hello-world.txt").bufferedReader() - try { + try { reader.readLine() } - finally { + finally { reader.readLine() reader.close() } diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/parameter.kt b/idea/testData/intentions/convertTryFinallyToUseCall/parameter.kt index d1836d23e17..46ca6f5aad1 100644 --- a/idea/testData/intentions/convertTryFinallyToUseCall/parameter.kt +++ b/idea/testData/intentions/convertTryFinallyToUseCall/parameter.kt @@ -3,10 +3,10 @@ import java.io.File import java.io.BufferedReader fun foo(reader: BufferedReader) { - try { + try { reader.readLine() } - finally { + finally { reader.close() } } \ No newline at end of file diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/safeCall.kt b/idea/testData/intentions/convertTryFinallyToUseCall/safeCall.kt index 8602183c8a8..5fad830754b 100644 --- a/idea/testData/intentions/convertTryFinallyToUseCall/safeCall.kt +++ b/idea/testData/intentions/convertTryFinallyToUseCall/safeCall.kt @@ -5,11 +5,11 @@ import java.io.BufferedReader fun bar() {} fun foo(reader: BufferedReader?) { - try { + try { reader?.readLine() bar() } - finally { + finally { reader?.close() } } \ No newline at end of file diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/simple.kt b/idea/testData/intentions/convertTryFinallyToUseCall/simple.kt index 7285f1fd011..5b1267f8996 100644 --- a/idea/testData/intentions/convertTryFinallyToUseCall/simple.kt +++ b/idea/testData/intentions/convertTryFinallyToUseCall/simple.kt @@ -3,10 +3,10 @@ import java.io.File fun main(args: Array) { val reader = File("hello-world.txt").bufferedReader() - try { + try { reader.readLine() } - finally { + finally { reader.close() } } \ No newline at end of file diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/this.kt b/idea/testData/intentions/convertTryFinallyToUseCall/this.kt index 42b4efd1a72..253a21d6e05 100644 --- a/idea/testData/intentions/convertTryFinallyToUseCall/this.kt +++ b/idea/testData/intentions/convertTryFinallyToUseCall/this.kt @@ -3,10 +3,10 @@ import java.io.File import java.io.BufferedReader fun BufferedReader.foo() { - try { + try { this.readLine() } - finally { + finally { this.close() } } \ No newline at end of file diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/thisLabeled.kt b/idea/testData/intentions/convertTryFinallyToUseCall/thisLabeled.kt index c6cde4884cc..575a1e01a41 100644 --- a/idea/testData/intentions/convertTryFinallyToUseCall/thisLabeled.kt +++ b/idea/testData/intentions/convertTryFinallyToUseCall/thisLabeled.kt @@ -8,10 +8,10 @@ class MyCloseable : Closeable { fun process(x: Int) = x fun Int.foo() { - try { + try { this@MyCloseable.process(this) } - finally { + finally { this@MyCloseable.close() } } diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/triple.kt b/idea/testData/intentions/convertTryFinallyToUseCall/triple.kt index 2762562f952..199f2c7d129 100644 --- a/idea/testData/intentions/convertTryFinallyToUseCall/triple.kt +++ b/idea/testData/intentions/convertTryFinallyToUseCall/triple.kt @@ -3,12 +3,12 @@ import java.io.File fun main(args: Array) { val writer = File("hello-world.txt").bufferedWriter() - try { + try { writer.write("123") writer.newLine() writer.write("456") } - finally { + finally { writer.close() } } \ No newline at end of file diff --git a/idea/testData/intentions/convertTryFinallyToUseCall/wrongCaret.kt b/idea/testData/intentions/convertTryFinallyToUseCall/wrongCaret.kt new file mode 100644 index 00000000000..e4e05a3f6da --- /dev/null +++ b/idea/testData/intentions/convertTryFinallyToUseCall/wrongCaret.kt @@ -0,0 +1,13 @@ +// IS_APPLICABLE: false +// WITH_RUNTIME +import java.io.File + +fun main(args: Array) { + val reader = File("hello-world.txt").bufferedReader() + try { + reader.readLine() + } + finally { + reader.close() + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 485531ecc56..c965a775a2c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -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")