From 67df2b448fcb44d77aad0f85ef5fd062b174965c Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Wed, 24 Sep 2014 16:00:39 +0400 Subject: [PATCH] Create Function From Usage: Quick-fix for invoke convention --- .../plugin/quickfix/QuickFixRegistrar.java | 2 ++ .../CreateInvokeFunctionActionFactory.kt | 33 +++++++++++++++++ .../invoke/afterInvokeOnLibType.kt | 10 ++++++ .../invoke/afterInvokeOnUserType.kt | 12 +++++++ .../afterInvokeOnUserTypeWithTypeParams.kt | 12 +++++++ ...rInvokeWithExplicitParamNamesOnUserType.kt | 11 ++++++ .../invoke/beforeInvokeOnLibType.kt | 7 ++++ .../invoke/beforeInvokeOnUserType.kt | 8 +++++ .../beforeInvokeOnUserTypeWithTypeParams.kt | 8 +++++ ...eInvokeWithExplicitParamNamesOnUserType.kt | 7 ++++ .../quickfix/QuickFixTestGenerated.java | 36 ++++++++++++++++++- 11 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateInvokeFunctionActionFactory.kt create mode 100644 idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnLibType.kt create mode 100644 idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnUserType.kt create mode 100644 idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnUserTypeWithTypeParams.kt create mode 100644 idea/testData/quickfix/createFromUsage/invoke/afterInvokeWithExplicitParamNamesOnUserType.kt create mode 100644 idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnLibType.kt create mode 100644 idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnUserType.kt create mode 100644 idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnUserTypeWithTypeParams.kt create mode 100644 idea/testData/quickfix/createFromUsage/invoke/beforeInvokeWithExplicitParamNamesOnUserType.kt diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java index 3c10591bb9e..23dcaeb929d 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java @@ -232,6 +232,8 @@ public class QuickFixRegistrar { QuickFixes.factories.put(NO_VALUE_FOR_PARAMETER, CreateBinaryOperationActionFactory.INSTANCE$); QuickFixes.factories.put(TOO_MANY_ARGUMENTS, CreateBinaryOperationActionFactory.INSTANCE$); + QuickFixes.factories.put(FUNCTION_EXPECTED, CreateInvokeFunctionActionFactory.INSTANCE$); + QuickFixes.factories.put(TYPE_MISMATCH, new QuickFixFactoryForTypeMismatchError()); QuickFixes.factories.put(AUTOCAST_IMPOSSIBLE, CastExpressionFix.createFactoryForAutoCastImpossible()); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateInvokeFunctionActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateInvokeFunctionActionFactory.kt new file mode 100644 index 00000000000..eac93b648ea --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateInvokeFunctionActionFactory.kt @@ -0,0 +1,33 @@ +package org.jetbrains.jet.plugin.quickfix.createFromUsage.createFunction + +import org.jetbrains.jet.plugin.quickfix.JetSingleIntentionActionFactory +import org.jetbrains.jet.lang.diagnostics.Diagnostic +import com.intellij.codeInsight.intention.IntentionAction +import org.jetbrains.jet.plugin.quickfix.QuickFixUtil +import org.jetbrains.jet.lang.psi.JetArrayAccessExpression +import org.jetbrains.jet.lang.types.Variance +import org.jetbrains.jet.lang.psi.JetCallExpression +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.jet.lang.diagnostics.Errors + +object CreateInvokeFunctionActionFactory : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val callExpr = diagnostic.getPsiElement().getParent() as? JetCallExpression ?: return null + + val expectedType = Errors.FUNCTION_EXPECTED.cast(diagnostic).getB() + if (expectedType.isError()) return null + + val receiverType = TypeInfo(expectedType, Variance.IN_VARIANCE) + + val anyType = KotlinBuiltIns.getInstance().getNullableAnyType() + val parameters = callExpr.getValueArguments().map { + ParameterInfo( + it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE), + it.getArgumentName()?.getReferenceExpression()?.getReferencedName() + ) + } + + val returnType = TypeInfo(callExpr, Variance.OUT_VARIANCE) + return CreateFunctionFromUsageFix(callExpr, FunctionInfo("invoke", receiverType, returnType, parameters)) + } +} diff --git a/idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnLibType.kt b/idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnLibType.kt new file mode 100644 index 00000000000..c57a8a55272 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnLibType.kt @@ -0,0 +1,10 @@ +// "Create function 'invoke' from usage" "true" + +class A(val n: T) + +fun test(): A { + return 1(2, "2") +} +fun Int.invoke(i: Int, s: String): A { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnUserType.kt b/idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnUserType.kt new file mode 100644 index 00000000000..03ba9c58357 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnUserType.kt @@ -0,0 +1,12 @@ +// "Create function 'invoke' from usage" "true" + +class A(val n: T) { + fun invoke(arg: T, s: String): B { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} +class B(val m: T) + +fun test(): B { + return A(1)(2, "2") +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnUserTypeWithTypeParams.kt b/idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnUserTypeWithTypeParams.kt new file mode 100644 index 00000000000..d2a17ee832a --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/invoke/afterInvokeOnUserTypeWithTypeParams.kt @@ -0,0 +1,12 @@ +// "Create function 'invoke' from usage" "true" + +class A(val n: T) { + fun invoke(u: T, s: String): B { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} +class B(val m: T) + +fun test(u: U): B { + return A(u)(u, "u") +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/invoke/afterInvokeWithExplicitParamNamesOnUserType.kt b/idea/testData/quickfix/createFromUsage/invoke/afterInvokeWithExplicitParamNamesOnUserType.kt new file mode 100644 index 00000000000..983fd27687f --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/invoke/afterInvokeWithExplicitParamNamesOnUserType.kt @@ -0,0 +1,11 @@ +// "Create function 'invoke' from usage" "true" + +class A(val n: T) { + fun invoke(abc: T, ghi: A, def: String): A { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} + +fun test() { + val a: A = A(1)(abc = 1, ghi = A(2), def = "s") +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnLibType.kt b/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnLibType.kt new file mode 100644 index 00000000000..b2139dec2d8 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnLibType.kt @@ -0,0 +1,7 @@ +// "Create function 'invoke' from usage" "true" + +class A(val n: T) + +fun test(): A { + return 1(2, "2") +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnUserType.kt b/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnUserType.kt new file mode 100644 index 00000000000..d3fc680cc9f --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnUserType.kt @@ -0,0 +1,8 @@ +// "Create function 'invoke' from usage" "true" + +class A(val n: T) +class B(val m: T) + +fun test(): B { + return A(1)(2, "2") +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnUserTypeWithTypeParams.kt b/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnUserTypeWithTypeParams.kt new file mode 100644 index 00000000000..fcd0527044e --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnUserTypeWithTypeParams.kt @@ -0,0 +1,8 @@ +// "Create function 'invoke' from usage" "true" + +class A(val n: T) +class B(val m: T) + +fun test(u: U): B { + return A(u)(u, "u") +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeWithExplicitParamNamesOnUserType.kt b/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeWithExplicitParamNamesOnUserType.kt new file mode 100644 index 00000000000..ee48b367a22 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/invoke/beforeInvokeWithExplicitParamNamesOnUserType.kt @@ -0,0 +1,7 @@ +// "Create function 'invoke' from usage" "true" + +class A(val n: T) + +fun test() { + val a: A = A(1)(abc = 1, ghi = A(2), def = "s") +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index d2bc429eb5a..2ecbb640dae 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -618,7 +618,7 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { @TestMetadata("idea/testData/quickfix/createFromUsage") @TestDataPath("$PROJECT_ROOT") - @InnerTestClasses({CreateFromUsage.BinaryOperations.class, CreateFromUsage.Component.class, CreateFromUsage.Get.class, CreateFromUsage.HasNext.class, CreateFromUsage.Iterator.class, CreateFromUsage.Next.class, CreateFromUsage.Set.class, CreateFromUsage.UnaryOperations.class}) + @InnerTestClasses({CreateFromUsage.BinaryOperations.class, CreateFromUsage.Component.class, CreateFromUsage.Get.class, CreateFromUsage.HasNext.class, CreateFromUsage.Invoke.class, CreateFromUsage.Iterator.class, CreateFromUsage.Next.class, CreateFromUsage.Set.class, CreateFromUsage.UnaryOperations.class}) @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) public static class CreateFromUsage extends AbstractQuickFixTest { public void testAllFilesPresentInCreateFromUsage() throws Exception { @@ -851,6 +851,40 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } + @TestMetadata("idea/testData/quickfix/createFromUsage/invoke") + @TestDataPath("$PROJECT_ROOT") + @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) + public static class Invoke extends AbstractQuickFixTest { + public void testAllFilesPresentInInvoke() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/invoke"), Pattern.compile("^before(\\w+)\\.kt$"), true); + } + + @TestMetadata("beforeInvokeOnLibType.kt") + public void testInvokeOnLibType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnLibType.kt"); + doTest(fileName); + } + + @TestMetadata("beforeInvokeOnUserType.kt") + public void testInvokeOnUserType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnUserType.kt"); + doTest(fileName); + } + + @TestMetadata("beforeInvokeOnUserTypeWithTypeParams.kt") + public void testInvokeOnUserTypeWithTypeParams() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/invoke/beforeInvokeOnUserTypeWithTypeParams.kt"); + doTest(fileName); + } + + @TestMetadata("beforeInvokeWithExplicitParamNamesOnUserType.kt") + public void testInvokeWithExplicitParamNamesOnUserType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/invoke/beforeInvokeWithExplicitParamNamesOnUserType.kt"); + doTest(fileName); + } + + } + @TestMetadata("idea/testData/quickfix/createFromUsage/iterator") @TestDataPath("$PROJECT_ROOT") @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)