From 76c9bbc06dc7703841c9736307310f62aea36b38 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 7 Jan 2016 15:54:33 +0100 Subject: [PATCH] handle setter calls used as expression bodies in "Use property access syntax" intention #KT-10587 Fixed --- .../UsePropertyAccessSyntaxIntention.kt | 24 ++++++++++++++----- .../setAsExpressionBody.kt | 2 ++ .../setAsExpressionBody.kt.after | 4 ++++ .../setAsExpressionBodyProperty.kt | 4 ++++ .../setAsExpressionBodyProperty.kt.after | 6 +++++ .../setAsExpressionBodyUnqualified.kt | 4 ++++ .../setAsExpressionBodyUnqualified.kt.after | 6 +++++ .../intentions/IntentionTestGenerated.java | 18 ++++++++++++++ 8 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBody.kt create mode 100644 idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBody.kt.after create mode 100644 idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyProperty.kt create mode 100644 idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyProperty.kt.after create mode 100644 idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyUnqualified.kt create mode 100644 idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyUnqualified.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/UsePropertyAccessSyntaxIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/UsePropertyAccessSyntaxIntention.kt index e3836f48b49..f3bec35c3da 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/UsePropertyAccessSyntaxIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/UsePropertyAccessSyntaxIntention.kt @@ -69,7 +69,7 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention val arguments = element.valueArguments return when (arguments.size) { 0 -> replaceWithPropertyGet(element, propertyName) - 1 -> replaceWithPropertySet(element, propertyName, arguments.single()) + 1 -> replaceWithPropertySet(element, propertyName) else -> error("More than one argument in call to accessor") } } @@ -158,15 +158,27 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention } //TODO: what if it was used as expression (of type Unit)? - private fun replaceWithPropertySet(callExpression: KtCallExpression, propertyName: Name, argument: KtValueArgument): KtExpression { - val qualifiedExpression = callExpression.getQualifiedExpressionForSelector() + private fun replaceWithPropertySet(callExpression: KtCallExpression, propertyName: Name): KtExpression { + val call = callExpression.getQualifiedExpressionForSelector() ?: callExpression + val callParent = call.parent + var callToConvert = callExpression + if (callParent is KtDeclarationWithBody && call == callParent.bodyExpression) { + ConvertToBlockBodyIntention.convert(callParent) + val firstStatement = (callParent.bodyExpression as? KtBlockExpression)?.statements?.first() + callToConvert = (firstStatement as? KtQualifiedExpression)?.selectorExpression as? KtCallExpression + ?: firstStatement as? KtCallExpression + ?: throw IllegalStateException("Unexpected contents of function after conversion: ${callParent.text}") + } + + val qualifiedExpression = callToConvert.getQualifiedExpressionForSelector() + val argument = callToConvert.valueArguments.single() if (qualifiedExpression != null) { val pattern = when (qualifiedExpression) { is KtDotQualifiedExpression -> "$0.$1=$2" is KtSafeQualifiedExpression -> "$0?.$1=$2" else -> error(qualifiedExpression) //TODO: make it sealed? } - val newExpression = KtPsiFactory(callExpression).createExpressionByPattern( + val newExpression = KtPsiFactory(callToConvert).createExpressionByPattern( pattern, qualifiedExpression.receiverExpression, propertyName, @@ -175,8 +187,8 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention return qualifiedExpression.replaced(newExpression) } else { - val newExpression = KtPsiFactory(callExpression).createExpressionByPattern("$0=$1", propertyName, argument.getArgumentExpression()!!) - return callExpression.replaced(newExpression) + val newExpression = KtPsiFactory(callToConvert).createExpressionByPattern("$0=$1", propertyName, argument.getArgumentExpression()!!) + return callToConvert.replaced(newExpression) } } } \ No newline at end of file diff --git a/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBody.kt b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBody.kt new file mode 100644 index 00000000000..bee3f527a25 --- /dev/null +++ b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBody.kt @@ -0,0 +1,2 @@ +// WITH_RUNTIME +fun foo(thread: Thread) = thread.setName("") \ No newline at end of file diff --git a/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBody.kt.after b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBody.kt.after new file mode 100644 index 00000000000..67d46b4b8d3 --- /dev/null +++ b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBody.kt.after @@ -0,0 +1,4 @@ +// WITH_RUNTIME +fun foo(thread: Thread) { + thread.name = "" +} diff --git a/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyProperty.kt b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyProperty.kt new file mode 100644 index 00000000000..9f952bc994c --- /dev/null +++ b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyProperty.kt @@ -0,0 +1,4 @@ +// WITH_RUNTIME +var Thread.otherName: String + get() = getName() + set(value) = setName(value) diff --git a/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyProperty.kt.after b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyProperty.kt.after new file mode 100644 index 00000000000..3874e441979 --- /dev/null +++ b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyProperty.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME +var Thread.otherName: String + get() = getName() + set(value) { + name = value + } diff --git a/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyUnqualified.kt b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyUnqualified.kt new file mode 100644 index 00000000000..ddab36e2fa9 --- /dev/null +++ b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyUnqualified.kt @@ -0,0 +1,4 @@ +// WITH_RUNTIME +class C: Thread() { + fun foo(n: String) = setName(n) +} diff --git a/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyUnqualified.kt.after b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyUnqualified.kt.after new file mode 100644 index 00000000000..a8077363832 --- /dev/null +++ b/idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyUnqualified.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME +class C: Thread() { + fun foo(n: String) { + name = n + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index c7046face96..88c5080457c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -8740,6 +8740,24 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("setAsExpressionBody.kt") + public void testSetAsExpressionBody() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBody.kt"); + doTest(fileName); + } + + @TestMetadata("setAsExpressionBodyProperty.kt") + public void testSetAsExpressionBodyProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyProperty.kt"); + doTest(fileName); + } + + @TestMetadata("setAsExpressionBodyUnqualified.kt") + public void testSetAsExpressionBodyUnqualified() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/usePropertyAccessSyntax/setAsExpressionBodyUnqualified.kt"); + doTest(fileName); + } + @TestMetadata("setImplicitReceiver.kt") public void testSetImplicitReceiver() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/usePropertyAccessSyntax/setImplicitReceiver.kt");