From b2588f610ab63d7c5079d036ece9a88ca011bd33 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 20 Oct 2014 21:10:33 +0400 Subject: [PATCH] Create From Usage ("set" operation): Support expressions of the form a[i]++ --- .../jet/lang/psi/JetOperationExpression.java | 3 ++- ...implifyNegatedBinaryExpressionIntention.kt | 3 ++- .../ConvertToForEachFunctionCallIntention.kt | 3 ++- .../CreateSetFunctionActionFactory.kt | 27 ++++++++++++++++--- .../set/afterSetterForIncrement.kt | 13 +++++++++ .../set/beforeSetterForIncrement.kt | 9 +++++++ .../quickfix/QuickFixTestGenerated.java | 7 +++++ 7 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/set/afterSetterForIncrement.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/set/beforeSetterForIncrement.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetOperationExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetOperationExpression.java index 54fc848aa40..0bdf9cf4d3a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetOperationExpression.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetOperationExpression.java @@ -16,9 +16,10 @@ package org.jetbrains.jet.lang.psi; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; -public interface JetOperationExpression { +public interface JetOperationExpression extends PsiElement { @NotNull JetSimpleNameExpression getOperationReference(); } diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/intentions/SimplifyNegatedBinaryExpressionIntention.kt b/idea/idea-analysis/src/org/jetbrains/jet/plugin/intentions/SimplifyNegatedBinaryExpressionIntention.kt index 47e39e97d98..9d5f792a65a 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/intentions/SimplifyNegatedBinaryExpressionIntention.kt +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/intentions/SimplifyNegatedBinaryExpressionIntention.kt @@ -29,6 +29,7 @@ import org.jetbrains.jet.lexer.JetTokens import org.jetbrains.jet.lang.psi.JetPsiUtil import org.jetbrains.jet.plugin.JetBundle import org.jetbrains.jet.lang.psi.JetPsiFactory +import com.intellij.psi.PsiElement public class SimplifyNegatedBinaryExpressionIntention : JetSelfTargetingIntention("simplify.negated.binary.expression", javaClass()) { @@ -87,7 +88,7 @@ public class SimplifyNegatedBinaryExpressionIntention : JetSelfTargetingIntentio expression.getRight() ) else -> throw IllegalStateException( - "Expression is neither a JetIsExpression or JetBinaryExpression (checked by isApplicableTo): ${expression.getText()}" + "Expression is neither a JetIsExpression or JetBinaryExpression (checked by isApplicableTo): ${(expression : PsiElement).getText()}" ) } ) diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/ConvertToForEachFunctionCallIntention.kt b/idea/src/org/jetbrains/jet/plugin/intentions/ConvertToForEachFunctionCallIntention.kt index 7a0bc8396c8..614ed1c5379 100644 --- a/idea/src/org/jetbrains/jet/plugin/intentions/ConvertToForEachFunctionCallIntention.kt +++ b/idea/src/org/jetbrains/jet/plugin/intentions/ConvertToForEachFunctionCallIntention.kt @@ -23,6 +23,7 @@ import org.jetbrains.jet.lang.psi.JetBlockExpression import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.lang.psi.JetParameter import org.jetbrains.jet.lang.psi.JetOperationExpression +import com.intellij.psi.PsiElement public class ConvertToForEachFunctionCallIntention : JetSelfTargetingIntention("convert.to.for.each.function.call.intention", javaClass()) { override fun isApplicableTo(element: JetForExpression): Boolean { @@ -49,7 +50,7 @@ public class ConvertToForEachFunctionCallIntention : JetSelfTargetingIntention "(${loopRange.getText()})" + is JetOperationExpression -> "(${(loopRange : PsiElement).getText()})" else -> loopRange.getText() ?: throw AssertionError("LoopRange in ForExpression shouldn't be empty: expressionText = ${element.getText()}") } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateSetFunctionActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateSetFunctionActionFactory.kt index 26646dc31d9..82d2af6e748 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateSetFunctionActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateSetFunctionActionFactory.kt @@ -11,6 +11,12 @@ import org.jetbrains.jet.lang.psi.JetBinaryExpression import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.* import java.util.Collections +import org.jetbrains.jet.lang.psi.JetOperationExpression +import org.jetbrains.jet.lang.psi.JetUnaryExpression +import org.jetbrains.jet.lang.types.expressions.OperatorConventions +import org.jetbrains.jet.lang.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache +import org.jetbrains.jet.lang.types.ErrorUtils object CreateSetFunctionActionFactory : JetSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): IntentionAction? { @@ -18,16 +24,29 @@ object CreateSetFunctionActionFactory : JetSingleIntentionActionFactory() { val arrayExpr = accessExpr.getArrayExpression() ?: return null val arrayType = TypeInfo(arrayExpr, Variance.IN_VARIANCE) + val builtIns = KotlinBuiltIns.getInstance() + val parameters = accessExpr.getIndexExpressions().mapTo(ArrayList()) { ParameterInfo(TypeInfo(it, Variance.IN_VARIANCE)) } - val assignmentExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null - val rhs = assignmentExpr.getRight() ?: return null - val valType = TypeInfo(rhs, Variance.IN_VARIANCE) + val assignmentExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null + val valType = when (assignmentExpr) { + is JetBinaryExpression -> { + TypeInfo(assignmentExpr.getRight() ?: return null, Variance.IN_VARIANCE) + } + is JetUnaryExpression -> { + if (assignmentExpr.getOperationToken() !in OperatorConventions.INCREMENT_OPERATIONS) return null + + val context = AnalyzerFacadeWithCache.getContextForElement(assignmentExpr) + val rhsType = assignmentExpr.getResolvedCall(context)?.getResultingDescriptor()?.getReturnType() + TypeInfo(if (rhsType == null || ErrorUtils.containsErrorType(rhsType)) builtIns.getAnyType() else rhsType, Variance.IN_VARIANCE) + } + else -> return null + } parameters.add(ParameterInfo(valType, "value")) - val returnType = TypeInfo(KotlinBuiltIns.getInstance().getUnitType(), Variance.OUT_VARIANCE) + val returnType = TypeInfo(builtIns.getUnitType(), Variance.OUT_VARIANCE) return CreateCallableFromUsageFix(accessExpr, FunctionInfo("set", arrayType, returnType, Collections.emptyList(), parameters)) } } \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/set/afterSetterForIncrement.kt b/idea/testData/quickfix/createFromUsage/createFunction/set/afterSetterForIncrement.kt new file mode 100644 index 00000000000..f803b745f3f --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/set/afterSetterForIncrement.kt @@ -0,0 +1,13 @@ +// "Create function 'set' from usage" "true" +class A { + fun get(s: String): Int = 1 + + fun set(s: String, value: Int) { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} + +fun foo() { + var a = A() + a["1"]++ +} diff --git a/idea/testData/quickfix/createFromUsage/createFunction/set/beforeSetterForIncrement.kt b/idea/testData/quickfix/createFromUsage/createFunction/set/beforeSetterForIncrement.kt new file mode 100644 index 00000000000..8606ddc0189 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/set/beforeSetterForIncrement.kt @@ -0,0 +1,9 @@ +// "Create function 'set' from usage" "true" +class A { + fun get(s: String): Int = 1 +} + +fun foo() { + var a = A() + a["1"]++ +} diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index e8e6a3711d5..bed9d60bc59 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -1197,6 +1197,13 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/set/beforeCreateSetFromUsage2.kt"); doTest(fileName); } + + @TestMetadata("beforeSetterForIncrement.kt") + public void testSetterForIncrement() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/set/beforeSetterForIncrement.kt"); + doTest(fileName); + } + } @TestMetadata("idea/testData/quickfix/createFromUsage/createFunction/unaryOperations")