Intentions: Convert extension receiver to parameter and vice versa

This commit is contained in:
Alexey Sedunov
2015-01-20 13:42:53 +03:00
parent 7b6160b92f
commit cef9996ba7
31 changed files with 408 additions and 3 deletions
@@ -344,6 +344,10 @@ convert.function.to.property.intention=Convert function to property
convert.function.to.property.intention.family=Convert Function to Property
convert.property.to.function.intention=Convert property to function
convert.property.to.function.intention.family=Convert Property to Function
convert.receiver.to.parameter.intention=Convert receiver to parameter
convert.receiver.to.parameter.intention.family=Convert Receiver to Parameter
convert.parameter.to.receiver.intention=Convert parameter to receiver
convert.parameter.to.receiver.intention.family=Convert Parameter to Receiver
property.is.implemented.too.many=Has implementations
property.is.overridden.too.many=Is overridden in subclasses
@@ -0,0 +1,7 @@
fun <spot>String</spot>.foo(n: Int): Int {
return length() - n
}
fun test() {
"1".foo(2)
}
@@ -0,0 +1,7 @@
fun foo(<spot>s: String</spot>, n: Int): Int {
return s.length() - n
}
fun test() {
foo("1", 2)
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts function parameter to extension receiver.
</body>
</html>
@@ -0,0 +1,7 @@
fun foo(<spot>s: String</spot>, n: Int): Int {
return s.length() - n
}
fun test() {
foo("1", 2)
}
@@ -0,0 +1,7 @@
fun <spot>String</spot>.foo(n: Int): Int {
return length() - n
}
fun test() {
"1".foo(2)
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts extension function receiver to its parameter.
</body>
</html>
+12 -2
View File
@@ -795,12 +795,22 @@
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertFunctionToPropertyIntention</className>
<className>org.jetbrains.kotlin.idea.intentions.ConvertFunctionToPropertyIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertPropertyToFunctionIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertReceiverToParameterIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertPropertyToFunctionIntention</className>
<className>org.jetbrains.kotlin.idea.intentions.ConvertParameterToReceiverIntention</className>
<category>Kotlin</category>
</intentionAction>
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.intentions
import org.jetbrains.kotlin.psi.JetNamedFunction
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.refactoring.changeSignature.runChangeSignature
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeSignatureConfiguration
import org.jetbrains.kotlin.psi.JetParameter
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetMethodDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
public class ConvertParameterToReceiverIntention: JetSelfTargetingIntention<JetParameter>("convert.parameter.to.receiver.intention", javaClass()) {
override fun isApplicableTo(element: JetParameter): Boolean {
val function = element.getStrictParentOfType<JetNamedFunction>() ?: return false
return function.getValueParameterList() == element.getParent() && function.getReceiverTypeReference() == null
}
private fun configureChangeSignature(parameterIndex: Int): JetChangeSignatureConfiguration {
return object: JetChangeSignatureConfiguration {
override fun configure(originalDescriptor: JetMethodDescriptor, bindingContext: BindingContext): JetMethodDescriptor {
return originalDescriptor.modify { receiver = originalDescriptor.getParameters()[parameterIndex] }
}
}
}
override fun applyTo(element: JetParameter, editor: Editor) {
val function = element.getStrictParentOfType<JetNamedFunction>() ?: return
val parameterIndex = function.getValueParameters().indexOf(element)
val context = function.analyze()
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, function] as? FunctionDescriptor ?: return
runChangeSignature(element.getProject(), descriptor, configureChangeSignature(parameterIndex), context, element, getText())
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.intentions
import org.jetbrains.kotlin.psi.JetNamedFunction
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.psi.JetTypeReference
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.refactoring.changeSignature.runChangeSignature
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeSignatureConfiguration
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetMethodDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify
public class ConvertReceiverToParameterIntention: JetSelfTargetingIntention<JetTypeReference>("convert.receiver.to.parameter.intention", javaClass()) {
override fun isApplicableTo(element: JetTypeReference): Boolean {
return (element.getParent() as? JetNamedFunction)?.getReceiverTypeReference() == element
}
private fun configureChangeSignature(): JetChangeSignatureConfiguration {
return object: JetChangeSignatureConfiguration {
override fun configure(originalDescriptor: JetMethodDescriptor, bindingContext: BindingContext): JetMethodDescriptor {
return originalDescriptor.modify { receiver = null }
}
}
}
override fun applyTo(element: JetTypeReference, editor: Editor) {
val function = element.getParent() as? JetNamedFunction ?: return
val context = function.analyze()
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, function] as? FunctionDescriptor ?: return
runChangeSignature(element.getProject(), descriptor, configureChangeSignature(), context, element, getText())
}
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.ConvertParameterToReceiverIntention
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
class Foo(<caret>s: String, n: Int) {
}
fun test() {
Foo("1", 2)
}
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
val foo = {(<caret>s: String, n: Int) -> s.length() - n/2 > 1 }
fun test() {
foo("1", 2)
}
@@ -0,0 +1,7 @@
fun test() {
fun foo(<caret>s: String, n: Int): Boolean {
return s.length() - n/2 > 1
}
foo("1", 2)
}
@@ -0,0 +1,7 @@
fun test() {
fun String.foo(n: Int): Boolean {
return length() - n/2 > 1
}
"1".foo(2)
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
class A {
fun foo(<caret>s: String, n: Int): Boolean {
return s.length() - n/2 > 1
}
fun test() {
foo("1", 2)
}
}
fun test() {
with(A()) {
foo("1", 2)
}
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
class A {
fun String.foo(n: Int): Boolean {
return length() - n/2 > 1
}
fun test() {
"1".foo(2)
}
}
fun test() {
with(A()) {
"1".foo(2)
}
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
fun <caret>foo(s: String, n: Int): Boolean {
return s.length() - n/2 > 1
}
fun test() {
foo("1", 2)
}
@@ -0,0 +1,7 @@
fun foo(<caret>s: String, n: Int): Boolean {
return s.length() - n/2 > 1
}
fun test() {
foo("1", 2)
}
@@ -0,0 +1,7 @@
fun String.foo(n: Int): Boolean {
return length() - n/2 > 1
}
fun test() {
"1".foo(2)
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
fun Any.foo(<caret>s: String, n: Int): Boolean {
return s.length() - n/2 > 1
}
fun test() {
"0".foo("1", 2)
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.ConvertReceiverToParameterIntention
@@ -0,0 +1,7 @@
fun test() {
fun <caret>String.foo(n: Int): Boolean {
return length() - n/2 > 1
}
"1".foo(2)
}
@@ -0,0 +1,7 @@
fun test() {
fun foo(s: String, n: Int): Boolean {
return s.length() - n/2 > 1
}
foo("1", 2)
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
class A {
fun <caret>String.foo(n: Int): Boolean {
return length() - n/2 > 1
}
fun test() {
"1".foo(2)
}
}
fun test() {
with(A()) {
"1".foo(2)
}
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
class A {
fun foo(s: String, n: Int): Boolean {
return s.length() - n/2 > 1
}
fun test() {
foo("1", 2)
}
}
fun test() {
with(A()) {
foo("1", 2)
}
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
fun String.foo<caret>(n: Int): Boolean {
return length() - n/2 > 1
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
fun <caret>foo(s: String, n: Int): Boolean {
return s.length() - n/2 > 1
}
@@ -0,0 +1,7 @@
fun <caret>String.foo(n: Int): Boolean {
return length() - n/2 > 1
}
fun test() {
"1".foo(2)
}
@@ -0,0 +1,7 @@
fun foo(s: String, n: Int): Boolean {
return s.length() - n/2 > 1
}
fun test() {
foo("1", 2)
}
@@ -30,7 +30,7 @@ import java.util.regex.Pattern;
@SuppressWarnings("all")
@TestMetadata("idea/testData/intentions")
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({IntentionTestGenerated.AddBraces.class, IntentionTestGenerated.AttributeCallReplacements.class, IntentionTestGenerated.Branched.class, IntentionTestGenerated.ConvertAssertToIf.class, IntentionTestGenerated.ConvertFunctionToProperty.class, IntentionTestGenerated.ConvertIfToAssert.class, IntentionTestGenerated.ConvertNegatedBooleanSequence.class, IntentionTestGenerated.ConvertNegatedExpressionWithDemorgansLaw.class, IntentionTestGenerated.ConvertPropertyToFunction.class, IntentionTestGenerated.ConvertToBlockBody.class, IntentionTestGenerated.ConvertToConcatenatedStringIntention.class, IntentionTestGenerated.ConvertToExpressionBody.class, IntentionTestGenerated.ConvertToForEachFunctionCall.class, IntentionTestGenerated.ConvertToForEachLoop.class, IntentionTestGenerated.ConvertToStringTemplateIntention.class, IntentionTestGenerated.Declarations.class, IntentionTestGenerated.InsertCurlyBracesToTemplate.class, IntentionTestGenerated.InsertExplicitTypeArguments.class, IntentionTestGenerated.InvertIfCondition.class, IntentionTestGenerated.MakeTypeExplicitInLambda.class, IntentionTestGenerated.MakeTypeImplicitInLambda.class, IntentionTestGenerated.MoveLambdaInsideParentheses.class, IntentionTestGenerated.MoveLambdaOutsideParentheses.class, IntentionTestGenerated.OperatorToFunction.class, IntentionTestGenerated.ReconstructedType.class, IntentionTestGenerated.RemoveBraces.class, IntentionTestGenerated.RemoveCurlyBracesFromTemplate.class, IntentionTestGenerated.RemoveExplicitTypeArguments.class, IntentionTestGenerated.RemoveUnnecessaryParentheses.class, IntentionTestGenerated.ReplaceExplicitFunctionLiteralParamWithIt.class, IntentionTestGenerated.ReplaceItWithExplicitFunctionLiteralParam.class, IntentionTestGenerated.ReplaceWithDotQualifiedMethodCall.class, IntentionTestGenerated.ReplaceWithInfixFunctionCall.class, IntentionTestGenerated.ReplaceWithOperatorAssign.class, IntentionTestGenerated.ReplaceWithTraditionalAssignment.class, IntentionTestGenerated.SimplifyBooleanWithConstants.class, IntentionTestGenerated.SimplifyNegatedBinaryExpressionIntention.class, IntentionTestGenerated.SpecifyType.class, IntentionTestGenerated.SplitIf.class, IntentionTestGenerated.SwapBinaryExpression.class})
@InnerTestClasses({IntentionTestGenerated.AddBraces.class, IntentionTestGenerated.AttributeCallReplacements.class, IntentionTestGenerated.Branched.class, IntentionTestGenerated.ConvertAssertToIf.class, IntentionTestGenerated.ConvertFunctionToProperty.class, IntentionTestGenerated.ConvertIfToAssert.class, IntentionTestGenerated.ConvertNegatedBooleanSequence.class, IntentionTestGenerated.ConvertNegatedExpressionWithDemorgansLaw.class, IntentionTestGenerated.ConvertParameterToReceiver.class, IntentionTestGenerated.ConvertPropertyToFunction.class, IntentionTestGenerated.ConvertReceiverToParameter.class, IntentionTestGenerated.ConvertToBlockBody.class, IntentionTestGenerated.ConvertToConcatenatedStringIntention.class, IntentionTestGenerated.ConvertToExpressionBody.class, IntentionTestGenerated.ConvertToForEachFunctionCall.class, IntentionTestGenerated.ConvertToForEachLoop.class, IntentionTestGenerated.ConvertToStringTemplateIntention.class, IntentionTestGenerated.Declarations.class, IntentionTestGenerated.InsertCurlyBracesToTemplate.class, IntentionTestGenerated.InsertExplicitTypeArguments.class, IntentionTestGenerated.InvertIfCondition.class, IntentionTestGenerated.MakeTypeExplicitInLambda.class, IntentionTestGenerated.MakeTypeImplicitInLambda.class, IntentionTestGenerated.MoveLambdaInsideParentheses.class, IntentionTestGenerated.MoveLambdaOutsideParentheses.class, IntentionTestGenerated.OperatorToFunction.class, IntentionTestGenerated.ReconstructedType.class, IntentionTestGenerated.RemoveBraces.class, IntentionTestGenerated.RemoveCurlyBracesFromTemplate.class, IntentionTestGenerated.RemoveExplicitTypeArguments.class, IntentionTestGenerated.RemoveUnnecessaryParentheses.class, IntentionTestGenerated.ReplaceExplicitFunctionLiteralParamWithIt.class, IntentionTestGenerated.ReplaceItWithExplicitFunctionLiteralParam.class, IntentionTestGenerated.ReplaceWithDotQualifiedMethodCall.class, IntentionTestGenerated.ReplaceWithInfixFunctionCall.class, IntentionTestGenerated.ReplaceWithOperatorAssign.class, IntentionTestGenerated.ReplaceWithTraditionalAssignment.class, IntentionTestGenerated.SimplifyBooleanWithConstants.class, IntentionTestGenerated.SimplifyNegatedBinaryExpressionIntention.class, IntentionTestGenerated.SpecifyType.class, IntentionTestGenerated.SplitIf.class, IntentionTestGenerated.SwapBinaryExpression.class})
@RunWith(JUnit3RunnerWithInners.class)
public class IntentionTestGenerated extends AbstractIntentionTest {
public void testAllFilesPresentInIntentions() throws Exception {
@@ -2929,6 +2929,57 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
@TestMetadata("idea/testData/intentions/convertParameterToReceiver")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ConvertParameterToReceiver extends AbstractIntentionTest {
public void testAllFilesPresentInConvertParameterToReceiver() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertParameterToReceiver"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("classParameter.kt")
public void testClassParameter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertParameterToReceiver/classParameter.kt");
doTest(fileName);
}
@TestMetadata("lambdaParameter.kt")
public void testLambdaParameter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertParameterToReceiver/lambdaParameter.kt");
doTest(fileName);
}
@TestMetadata("localFun.kt")
public void testLocalFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertParameterToReceiver/localFun.kt");
doTest(fileName);
}
@TestMetadata("memberFun.kt")
public void testMemberFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertParameterToReceiver/memberFun.kt");
doTest(fileName);
}
@TestMetadata("noParameterUnderCaret.kt")
public void testNoParameterUnderCaret() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertParameterToReceiver/noParameterUnderCaret.kt");
doTest(fileName);
}
@TestMetadata("topLevelFun.kt")
public void testTopLevelFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertParameterToReceiver/topLevelFun.kt");
doTest(fileName);
}
@TestMetadata("withExtensionReceiver.kt")
public void testWithExtensionReceiver() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertParameterToReceiver/withExtensionReceiver.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/intentions/convertPropertyToFunction")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -3022,6 +3073,45 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
@TestMetadata("idea/testData/intentions/convertReceiverToParameter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ConvertReceiverToParameter extends AbstractIntentionTest {
public void testAllFilesPresentInConvertReceiverToParameter() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertReceiverToParameter"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("localFun.kt")
public void testLocalFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertReceiverToParameter/localFun.kt");
doTest(fileName);
}
@TestMetadata("memberFun.kt")
public void testMemberFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertReceiverToParameter/memberFun.kt");
doTest(fileName);
}
@TestMetadata("noReceiverUnderCaret.kt")
public void testNoReceiverUnderCaret() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertReceiverToParameter/noReceiverUnderCaret.kt");
doTest(fileName);
}
@TestMetadata("notExtension.kt")
public void testNotExtension() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertReceiverToParameter/notExtension.kt");
doTest(fileName);
}
@TestMetadata("topLevelFun.kt")
public void testTopLevelFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertReceiverToParameter/topLevelFun.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/intentions/convertToBlockBody")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)