diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java index bc9c2867835..3c10591bb9e 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java @@ -222,6 +222,10 @@ public class QuickFixRegistrar { QuickFixes.factories.put(EXPECTED_TYPE_MISMATCH, changeFunctionLiteralReturnTypeFix); QuickFixes.factories.put(ASSIGNMENT_TYPE_MISMATCH, changeFunctionLiteralReturnTypeFix); + QuickFixes.factories.put(UNRESOLVED_REFERENCE, CreateUnaryOperationActionFactory.INSTANCE$); + QuickFixes.factories.put(UNRESOLVED_REFERENCE_WRONG_RECEIVER, CreateUnaryOperationActionFactory.INSTANCE$); + QuickFixes.factories.put(NO_VALUE_FOR_PARAMETER, CreateUnaryOperationActionFactory.INSTANCE$); + QuickFixes.factories.put(UNRESOLVED_REFERENCE_WRONG_RECEIVER, CreateBinaryOperationActionFactory.INSTANCE$); QuickFixes.factories.put(UNRESOLVED_REFERENCE, CreateBinaryOperationActionFactory.INSTANCE$); QuickFixes.factories.put(NONE_APPLICABLE, CreateBinaryOperationActionFactory.INSTANCE$); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateUnaryOperationActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateUnaryOperationActionFactory.kt new file mode 100644 index 00000000000..e2271566df4 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateUnaryOperationActionFactory.kt @@ -0,0 +1,27 @@ +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.lang.psi.JetSimpleNameExpression +import org.jetbrains.jet.lang.types.expressions.OperatorConventions +import org.jetbrains.jet.lexer.JetToken +import org.jetbrains.jet.lang.psi.JetBinaryExpression +import org.jetbrains.jet.lang.types.Variance +import java.util.Collections +import org.jetbrains.jet.lang.psi.JetUnaryExpression + +public object CreateUnaryOperationActionFactory: JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val callExpr = diagnostic.getPsiElement().getParent() as? JetUnaryExpression ?: return null + val token = callExpr.getOperationToken() as JetToken + val operationName = OperatorConventions.getNameForOperationSymbol(token) ?: return null + val incDec = token in OperatorConventions.INCREMENT_OPERATIONS + + val receiverExpr = callExpr.getBaseExpression() ?: return null + + val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE) + val returnType = if (incDec) TypeInfo.ByReceiverType(Variance.OUT_VARIANCE) else TypeInfo(callExpr, Variance.OUT_VARIANCE) + return CreateFunctionFromUsageFix(callExpr, FunctionInfo(operationName.asString(), receiverType, returnType)) + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/FunctionInfo.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/FunctionInfo.kt index 7b8621486c0..940ed44d1cc 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/FunctionInfo.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/FunctionInfo.kt @@ -20,20 +20,22 @@ abstract class TypeInfo(val variance: Variance) { JetNameSuggester.suggestNamesForExpression(expression, EmptyValidator) } - override fun getPossibleTypes(context: BindingContext): List = - expression.guessTypes(context).flatMap { it.getPossibleSupertypes(variance) } + override fun getPossibleTypes(builder: FunctionBuilder): List = + expression.guessTypes(builder.currentFileContext).flatMap { it.getPossibleSupertypes(variance) } } class ByType(val theType: JetType, variance: Variance, val keepUnsubstituted: Boolean = false): TypeInfo(variance) { - override val possibleNamesFromExpression: Array = - ArrayUtil.EMPTY_STRING_ARRAY - - override fun getPossibleTypes(context: BindingContext): List = + override fun getPossibleTypes(builder: FunctionBuilder): List = theType.getPossibleSupertypes(variance) } - abstract val possibleNamesFromExpression: Array - abstract fun getPossibleTypes(context: BindingContext): List + class ByReceiverType(variance: Variance): TypeInfo(variance) { + override fun getPossibleTypes(builder: FunctionBuilder): List = + builder.receiverTypeCandidate.theType.getPossibleSupertypes(variance) + } + + open val possibleNamesFromExpression: Array get() = ArrayUtil.EMPTY_STRING_ARRAY + abstract fun getPossibleTypes(builder: FunctionBuilder): List protected fun JetType.getPossibleSupertypes(variance: Variance): List { val single = Collections.singletonList(this) diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/functionBuilder.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/functionBuilder.kt index 52dbd92243b..208bb17a38b 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/functionBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/functionBuilder.kt @@ -107,7 +107,7 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) { } fun computeTypeCandidates(typeInfo: TypeInfo): List = - typeCandidates.getOrPut(typeInfo) { typeInfo.getPossibleTypes(currentFileContext).map { TypeCandidate(it) } } + typeCandidates.getOrPut(typeInfo) { typeInfo.getPossibleTypes(this).map { TypeCandidate(it) } } fun computeTypeCandidates( typeInfo: TypeInfo, @@ -115,7 +115,7 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) { scope: JetScope): List { if (typeInfo is TypeInfo.ByType && typeInfo.keepUnsubstituted) return computeTypeCandidates(typeInfo) return typeCandidates.getOrPut(typeInfo) { - val types = typeInfo.getPossibleTypes(currentFileContext).reverse() + val types = typeInfo.getPossibleTypes(this).reverse() val newTypes = LinkedHashSet(types) for (substitution in substitutions) { diff --git a/idea/testData/quickfix/createFromUsage/unaryOperations/afterIncOnUserType.kt b/idea/testData/quickfix/createFromUsage/unaryOperations/afterIncOnUserType.kt new file mode 100644 index 00000000000..d9918130348 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/unaryOperations/afterIncOnUserType.kt @@ -0,0 +1,12 @@ +// "Create function 'inc' from usage" "true" + +class A(val n: T) { + fun inc(): A { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} + +fun test() { + var a = A(1) + a++ +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/unaryOperations/afterMinusMissingArgs.kt b/idea/testData/quickfix/createFromUsage/unaryOperations/afterMinusMissingArgs.kt new file mode 100644 index 00000000000..76e4c41ee85 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/unaryOperations/afterMinusMissingArgs.kt @@ -0,0 +1,12 @@ +// "Create function 'minus' from usage" "true" + +class A(val n: T) { + fun minus(n: Int): A = throw Exception() + fun minus(): A { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} + +fun test() { + val a: A = -A(1) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/unaryOperations/afterMinusOnLibType.kt b/idea/testData/quickfix/createFromUsage/unaryOperations/afterMinusOnLibType.kt new file mode 100644 index 00000000000..75ff700ca2a --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/unaryOperations/afterMinusOnLibType.kt @@ -0,0 +1,8 @@ +// "Create function 'minus' from usage" "true" + +fun test() { + val a = -false +} +fun Boolean.minus(): Any { + 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/unaryOperations/afterMinusOnUserType.kt b/idea/testData/quickfix/createFromUsage/unaryOperations/afterMinusOnUserType.kt new file mode 100644 index 00000000000..707ecbb908f --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/unaryOperations/afterMinusOnUserType.kt @@ -0,0 +1,11 @@ +// "Create function 'minus' from usage" "true" + +class A(val n: T) { + fun minus(): Any { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} + +fun test() { + val a = -A(1) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/unaryOperations/afterMinusOnUserTypeWithTypeParams.kt b/idea/testData/quickfix/createFromUsage/unaryOperations/afterMinusOnUserTypeWithTypeParams.kt new file mode 100644 index 00000000000..3915e723814 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/unaryOperations/afterMinusOnUserTypeWithTypeParams.kt @@ -0,0 +1,11 @@ +// "Create function 'minus' from usage" "true" + +class A(val n: T) { + fun minus(): A { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} + +fun test(u: U) { + val a: A = -A(u) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/unaryOperations/beforeIncOnUserType.kt b/idea/testData/quickfix/createFromUsage/unaryOperations/beforeIncOnUserType.kt new file mode 100644 index 00000000000..b3140ca8f31 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/unaryOperations/beforeIncOnUserType.kt @@ -0,0 +1,8 @@ +// "Create function 'inc' from usage" "true" + +class A(val n: T) + +fun test() { + var a = A(1) + a++ +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusMissingArgs.kt b/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusMissingArgs.kt new file mode 100644 index 00000000000..30f8e53210a --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusMissingArgs.kt @@ -0,0 +1,9 @@ +// "Create function 'minus' from usage" "true" + +class A(val n: T) { + fun minus(n: Int): A = throw Exception() +} + +fun test() { + val a: A = -A(1) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnLibType.kt b/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnLibType.kt new file mode 100644 index 00000000000..7fb5e9603c3 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnLibType.kt @@ -0,0 +1,5 @@ +// "Create function 'minus' from usage" "true" + +fun test() { + val a = -false +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnUserType.kt b/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnUserType.kt new file mode 100644 index 00000000000..ec2cfd0b309 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnUserType.kt @@ -0,0 +1,7 @@ +// "Create function 'minus' from usage" "true" + +class A(val n: T) + +fun test() { + val a = -A(1) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnUserTypeWithTypeParams.kt b/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnUserTypeWithTypeParams.kt new file mode 100644 index 00000000000..ce35990ed11 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnUserTypeWithTypeParams.kt @@ -0,0 +1,7 @@ +// "Create function 'minus' from usage" "true" + +class A(val n: T) + +fun test(u: U) { + val a: A = -A(u) +} \ 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 ed805b5cf0e..d2bc429eb5a 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}) + @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}) @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) public static class CreateFromUsage extends AbstractQuickFixTest { public void testAllFilesPresentInCreateFromUsage() throws Exception { @@ -923,6 +923,46 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } + @TestMetadata("idea/testData/quickfix/createFromUsage/unaryOperations") + @TestDataPath("$PROJECT_ROOT") + @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) + public static class UnaryOperations extends AbstractQuickFixTest { + public void testAllFilesPresentInUnaryOperations() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/unaryOperations"), Pattern.compile("^before(\\w+)\\.kt$"), true); + } + + @TestMetadata("beforeIncOnUserType.kt") + public void testIncOnUserType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/unaryOperations/beforeIncOnUserType.kt"); + doTest(fileName); + } + + @TestMetadata("beforeMinusMissingArgs.kt") + public void testMinusMissingArgs() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusMissingArgs.kt"); + doTest(fileName); + } + + @TestMetadata("beforeMinusOnLibType.kt") + public void testMinusOnLibType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnLibType.kt"); + doTest(fileName); + } + + @TestMetadata("beforeMinusOnUserType.kt") + public void testMinusOnUserType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnUserType.kt"); + doTest(fileName); + } + + @TestMetadata("beforeMinusOnUserTypeWithTypeParams.kt") + public void testMinusOnUserTypeWithTypeParams() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/unaryOperations/beforeMinusOnUserTypeWithTypeParams.kt"); + doTest(fileName); + } + + } + } @TestMetadata("idea/testData/quickfix/expressions")