From 865c7935613f08c11e8186d5ead0bd0b2032d198 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 3 Oct 2014 16:38:38 +0400 Subject: [PATCH] Create From Usage: Do not suggest "val" for references used as assignment left-hand side --- .../jet/lang/psi/psiUtil/jetPsiUtil.kt | 5 +++ .../callableBuilder/CallableBuilder.kt | 15 ++++++-- .../callableBuilder/CallableInfo.kt | 37 ++++++++++--------- .../callableBuilder/typeUtils.kt | 5 ++- .../CreateBinaryOperationActionFactory.kt | 2 +- .../CreateComponentFunctionActionFactory.kt | 2 +- ...FunctionOrPropertyFromCallActionFactory.kt | 15 ++++++-- .../CreateGetFunctionActionFactory.kt | 2 +- .../CreateHasNextFunctionActionFactory.kt | 2 +- .../CreateInvokeFunctionActionFactory.kt | 2 +- .../CreateIteratorFunctionActionFactory.kt | 2 +- .../CreateNextFunctionActionFactory.kt | 2 +- .../CreateSetFunctionActionFactory.kt | 2 +- .../CreateUnaryOperationActionFactory.kt | 2 +- .../CreateLocalVariableActionFactory.kt | 14 ++++--- .../CreateParameterActionFactory.kt | 19 ++++++---- .../localVariable/afterAssignedInFun.kt | 7 ++++ .../localVariable/beforeAssignedInFun.kt | 5 +++ .../parameter/afterAssignedInFunInClass.kt | 7 ++++ .../parameter/beforeAssignedInFun.kt | 8 ++++ .../parameter/beforeAssignedInFunInClass.kt | 7 ++++ .../property/afterVarOnLibType.kt | 10 +++++ .../property/afterVarOnUserType.kt | 11 ++++++ .../property/beforeVarOnLibType.kt | 8 ++++ .../property/beforeVarOnUserType.kt | 8 ++++ .../quickfix/QuickFixTestGenerated.java | 30 +++++++++++++++ 26 files changed, 180 insertions(+), 49 deletions(-) create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/localVariable/afterAssignedInFun.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeAssignedInFun.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/parameter/afterAssignedInFunInClass.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeAssignedInFun.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeAssignedInFunInClass.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnLibType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnUserType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/property/beforeVarOnLibType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/property/beforeVarOnUserType.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt index e5f359b8c34..57c7de5a844 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt @@ -345,4 +345,9 @@ public fun PsiElement.siblings(forward: Boolean = true, withItself: Boolean = tr public fun PsiElement.parents(withItself: Boolean = true): Stream { val stream = stream(this) { if (it is PsiFile) null else it.getParent() } return if (withItself) stream else stream.drop(1) +} + +public fun JetExpression.getAssignmentByLHS(): JetBinaryExpression? { + val parent = getParent() as? JetBinaryExpression ?: return null + return if (JetPsiUtil.isAssignment(parent) && parent.getLeft() == this) parent else null } \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt index aa1b0194193..fdbc5efd8dc 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt @@ -243,8 +243,10 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { with (config) { val ownerTypeString = if (isExtension) "${receiverTypeCandidate!!.renderedType!!}." else "" val paramList = when (callableInfo.kind) { - CallableKind.FUNCTION -> "(${callableInfo.parameterInfos.indices.map { i -> "p$i: Any" }.joinToString(", ")})" - CallableKind.PROPERTY -> "" + CallableKind.FUNCTION -> + "(${(callableInfo as FunctionInfo).parameterInfos.indices.map { i -> "p$i: Any" }.joinToString(", ")})" + CallableKind.PROPERTY -> + "" } val returnTypeString = if (isUnit) "" else ": Any" val header = "$ownerTypeString${callableInfo.name}$paramList$returnTypeString" @@ -253,7 +255,10 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { val declaration = when (callableInfo.kind) { CallableKind.FUNCTION -> psiFactory.createFunction("fun $header {}") - CallableKind.PROPERTY -> psiFactory.createProperty("val $header") + CallableKind.PROPERTY -> { + val valVar = if ((callableInfo as PropertyInfo).writable) "var" else "val" + psiFactory.createProperty("$valVar $header") + } } val newLine = psiFactory.createNewLine() @@ -433,7 +438,9 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { } private fun setupValVarTemplate(builder: TemplateBuilder, property: JetProperty) { - builder.replaceElement(property.getValOrVarNode().getPsi()!!, ValVarExpression) + if (!(config.callableInfo as PropertyInfo).writable) { + builder.replaceElement(property.getValOrVarNode().getPsi()!!, ValVarExpression) + } } private fun setupTypeParameterListTemplate(builder: TemplateBuilderImpl, declaration: JetCallableDeclaration): TypeParameterListExpression { diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableInfo.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableInfo.kt index 5a9d7035e76..f8ea38c0dcc 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableInfo.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableInfo.kt @@ -71,30 +71,31 @@ enum class CallableKind { PROPERTY } -class CallableInfo ( +abstract class CallableInfo ( val name: String, - val kind: CallableKind, val receiverTypeInfo: TypeInfo, val returnTypeInfo: TypeInfo, - val possibleContainers: List, - val parameterInfos: List = Collections.emptyList() + val possibleContainers: List ) { - { - if (kind == CallableKind.PROPERTY) assert (parameterInfos.isEmpty(), "$kind: Parameters are not allowed") - } + abstract val kind: CallableKind + abstract val parameterInfos: List } -fun createFunctionInfo(name: String, - receiverTypeInfo: TypeInfo, - returnTypeInfo: TypeInfo, - possibleContainers: List = Collections.emptyList(), - parameterInfos: List = Collections.emptyList()): CallableInfo { - return CallableInfo(name, CallableKind.FUNCTION, receiverTypeInfo, returnTypeInfo, possibleContainers, parameterInfos) +class FunctionInfo(name: String, + receiverTypeInfo: TypeInfo, + returnTypeInfo: TypeInfo, + possibleContainers: List = Collections.emptyList(), + override val parameterInfos: List = Collections.emptyList() +) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers) { + override val kind: CallableKind get() = CallableKind.FUNCTION } -fun createPropertyInfo(name: String, - receiverTypeInfo: TypeInfo, - returnTypeInfo: TypeInfo, - possibleContainers: List): CallableInfo { - return CallableInfo(name, CallableKind.PROPERTY, receiverTypeInfo, returnTypeInfo, possibleContainers) +class PropertyInfo(name: String, + receiverTypeInfo: TypeInfo, + returnTypeInfo: TypeInfo, + val writable: Boolean, + possibleContainers: List = Collections.emptyList() +) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers) { + override val kind: CallableKind get() = CallableKind.PROPERTY + override val parameterInfos: List get() = Collections.emptyList() } \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/typeUtils.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/typeUtils.kt index 5a180e481f2..941240aaa3a 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/typeUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/typeUtils.kt @@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker import org.jetbrains.jet.lang.types.Variance import org.jetbrains.jet.lang.types.TypeProjectionImpl import org.jetbrains.jet.lang.types.JetTypeImpl +import org.jetbrains.jet.lang.psi.psiUtil.getAssignmentByLHS private fun JetType.contains(inner: JetType): Boolean { return this == inner || getArguments().any { inner in it.getType() } @@ -179,4 +180,6 @@ private fun JetType.substitute(substitution: JetTypeSubstitution, variance: Vari } return JetTypeImpl(getAnnotations(), getConstructor(), isNullable(), newArguments, getMemberScope()) } -} \ No newline at end of file +} + +fun JetExpression.getExpressionForTypeGuess() = getAssignmentByLHS()?.getRight() ?: this \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateBinaryOperationActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateBinaryOperationActionFactory.kt index cbfbdf85b27..74b85afea7b 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateBinaryOperationActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateBinaryOperationActionFactory.kt @@ -38,6 +38,6 @@ public object CreateBinaryOperationActionFactory: JetSingleIntentionActionFactor else -> TypeInfo(callExpr, Variance.OUT_VARIANCE) } val parameters = Collections.singletonList(ParameterInfo(TypeInfo(argumentExpr, Variance.IN_VARIANCE))) - return CreateFunctionFromUsageFix(callExpr, createFunctionInfo(operationName, receiverType, returnType, Collections.emptyList(), parameters)) + return CreateFunctionFromUsageFix(callExpr, FunctionInfo(operationName, receiverType, returnType, Collections.emptyList(), parameters)) } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateComponentFunctionActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateComponentFunctionActionFactory.kt index 73bf54915ed..f8db7ffcaf6 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateComponentFunctionActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateComponentFunctionActionFactory.kt @@ -34,6 +34,6 @@ object CreateComponentFunctionActionFactory : JetSingleIntentionActionFactory() val entry = entries[componentNumber] val returnType = TypeInfo(entry, Variance.OUT_VARIANCE) - return CreateFunctionFromUsageFix(multiDeclaration!!, createFunctionInfo(name.getIdentifier(), ownerType, returnType)) + return CreateFunctionFromUsageFix(multiDeclaration!!, FunctionInfo(name.getIdentifier(), ownerType, returnType)) } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateFunctionOrPropertyFromCallActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateFunctionOrPropertyFromCallActionFactory.kt index 80cba609b2e..7eb05faa945 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateFunctionOrPropertyFromCallActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateFunctionOrPropertyFromCallActionFactory.kt @@ -21,6 +21,7 @@ import java.util.Collections import org.jetbrains.jet.plugin.refactoring.getExtractionContainers import org.jetbrains.jet.lang.psi.JetClassBody import org.jetbrains.jet.lang.psi.JetFile +import org.jetbrains.jet.lang.psi.psiUtil.getAssignmentByLHS object CreateFunctionOrPropertyFromCallActionFactory : JetSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): IntentionAction? { @@ -70,8 +71,6 @@ object CreateFunctionOrPropertyFromCallActionFactory : JetSingleIntentionActionF } else Collections.emptyList() - val returnType = TypeInfo(fullCallExpr, Variance.OUT_VARIANCE) - val callableInfo = when (callExpr) { is JetCallExpression -> { val anyType = KotlinBuiltIns.getInstance().getNullableAnyType() @@ -81,10 +80,18 @@ object CreateFunctionOrPropertyFromCallActionFactory : JetSingleIntentionActionF it.getArgumentName()?.getReferenceExpression()?.getReferencedName() ) } - createFunctionInfo(calleeExpr.getReferencedName(), receiverType, returnType, possibleContainers, parameters) + val returnType = TypeInfo(fullCallExpr, Variance.OUT_VARIANCE) + FunctionInfo(calleeExpr.getReferencedName(), receiverType, returnType, possibleContainers, parameters) } - is JetSimpleNameExpression -> createPropertyInfo(calleeExpr.getReferencedName(), receiverType, returnType, possibleContainers) + is JetSimpleNameExpression -> { + val varExpected = fullCallExpr.getAssignmentByLHS() != null + val returnType = TypeInfo( + fullCallExpr.getExpressionForTypeGuess(), + if (varExpected) Variance.INVARIANT else Variance.OUT_VARIANCE + ) + PropertyInfo(calleeExpr.getReferencedName(), receiverType, returnType, varExpected, possibleContainers) + } else -> return null } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateGetFunctionActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateGetFunctionActionFactory.kt index b1c995439a4..7bf6cd5ad47 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateGetFunctionActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateGetFunctionActionFactory.kt @@ -20,6 +20,6 @@ object CreateGetFunctionActionFactory : JetSingleIntentionActionFactory() { } val returnType = TypeInfo(accessExpr, Variance.OUT_VARIANCE) - return CreateFunctionFromUsageFix(accessExpr, createFunctionInfo("get", arrayType, returnType, Collections.emptyList(), parameters)) + return CreateFunctionFromUsageFix(accessExpr, FunctionInfo("get", arrayType, returnType, Collections.emptyList(), parameters)) } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateHasNextFunctionActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateHasNextFunctionActionFactory.kt index a1ead783cd6..5eb2e6b9d0f 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateHasNextFunctionActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateHasNextFunctionActionFactory.kt @@ -18,6 +18,6 @@ object CreateHasNextFunctionActionFactory : JetSingleIntentionActionFactory() { val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null val returnType = TypeInfo(KotlinBuiltIns.getInstance().getBooleanType(), Variance.OUT_VARIANCE) - return CreateFunctionFromUsageFix(forExpr, createFunctionInfo("hasNext", ownerType, returnType)) + return CreateFunctionFromUsageFix(forExpr, FunctionInfo("hasNext", ownerType, returnType)) } } \ No newline at end of file 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 index 73361d6164e..0d4253ae1ae 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateInvokeFunctionActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateInvokeFunctionActionFactory.kt @@ -30,6 +30,6 @@ object CreateInvokeFunctionActionFactory : JetSingleIntentionActionFactory() { } val returnType = TypeInfo(callExpr, Variance.OUT_VARIANCE) - return CreateFunctionFromUsageFix(callExpr, createFunctionInfo("invoke", receiverType, returnType, Collections.emptyList(), parameters)) + return CreateFunctionFromUsageFix(callExpr, FunctionInfo("invoke", receiverType, returnType, Collections.emptyList(), parameters)) } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateIteratorFunctionActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateIteratorFunctionActionFactory.kt index fe0918c8f74..b9e764b8810 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateIteratorFunctionActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateIteratorFunctionActionFactory.kt @@ -32,6 +32,6 @@ object CreateIteratorFunctionActionFactory : JetSingleIntentionActionFactory() { val returnJetTypeArguments = Collections.singletonList(returnJetTypeParameterType) val newReturnJetType = JetTypeImpl(returnJetType.getAnnotations(), returnJetType.getConstructor(), returnJetType.isNullable(), returnJetTypeArguments, returnJetType.getMemberScope()) val returnType = TypeInfo(newReturnJetType, Variance.OUT_VARIANCE) - return CreateFunctionFromUsageFix(forExpr, createFunctionInfo("iterator", iterableType, returnType)) + return CreateFunctionFromUsageFix(forExpr, FunctionInfo("iterator", iterableType, returnType)) } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateNextFunctionActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateNextFunctionActionFactory.kt index 7bb9ce6be0f..e07505f45b1 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateNextFunctionActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateNextFunctionActionFactory.kt @@ -19,6 +19,6 @@ object CreateNextFunctionActionFactory : JetSingleIntentionActionFactory() { val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null val variableExpr: JetExpression = ((forExpr.getLoopParameter() ?: forExpr.getMultiParameter()) ?: return null) as JetExpression val returnType = TypeInfo(variableExpr, Variance.OUT_VARIANCE) - return CreateFunctionFromUsageFix(forExpr, createFunctionInfo("next", ownerType, returnType)) + return CreateFunctionFromUsageFix(forExpr, FunctionInfo("next", ownerType, returnType)) } } \ No newline at end of file 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 5c4353455a6..a1d997fba4d 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 @@ -28,6 +28,6 @@ object CreateSetFunctionActionFactory : JetSingleIntentionActionFactory() { parameters.add(ParameterInfo(valType, "value")) val returnType = TypeInfo(KotlinBuiltIns.getInstance().getUnitType(), Variance.OUT_VARIANCE) - return CreateFunctionFromUsageFix(accessExpr, createFunctionInfo("set", arrayType, returnType, Collections.emptyList(), parameters)) + return CreateFunctionFromUsageFix(accessExpr, FunctionInfo("set", arrayType, returnType, Collections.emptyList(), parameters)) } } \ No newline at end of file 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 index 63a95dcc595..3bf66dbb844 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateUnaryOperationActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createFunction/CreateUnaryOperationActionFactory.kt @@ -23,6 +23,6 @@ public object CreateUnaryOperationActionFactory: JetSingleIntentionActionFactory 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, createFunctionInfo(operationName.asString(), receiverType, returnType)) + return CreateFunctionFromUsageFix(callExpr, FunctionInfo(operationName.asString(), receiverType, returnType)) } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createVariable/CreateLocalVariableActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createVariable/CreateLocalVariableActionFactory.kt index a905a835320..213dd38303a 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createVariable/CreateLocalVariableActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createVariable/CreateLocalVariableActionFactory.kt @@ -12,7 +12,6 @@ import org.jetbrains.jet.plugin.quickfix.QuickFixUtil import org.jetbrains.jet.lang.psi.JetSimpleNameExpression import org.jetbrains.jet.lang.psi.psiUtil.getQualifiedElement import org.jetbrains.jet.lang.psi.JetBlockExpression -import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.createPropertyInfo import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.TypeInfo import org.jetbrains.jet.lang.types.Variance import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.CallableBuilderConfiguration @@ -20,13 +19,14 @@ import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.createB import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.CallablePlacement import com.intellij.openapi.command.CommandProcessor import org.jetbrains.jet.lang.psi.psiUtil.parents -import org.jetbrains.jet.lang.psi.JetFunction -import org.jetbrains.jet.lang.psi.JetPropertyAccessor import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.plugin.intentions.ConvertToBlockBodyAction import org.jetbrains.jet.lang.psi.JetDeclarationWithBody import org.jetbrains.jet.plugin.refactoring.getExtractionContainers import org.jetbrains.jet.lang.psi.JetClassBody +import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.PropertyInfo +import org.jetbrains.jet.lang.psi.psiUtil.getAssignmentByLHS +import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.getExpressionForTypeGuess object CreateLocalVariableActionFactory: JetSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): IntentionAction? { @@ -37,9 +37,13 @@ object CreateLocalVariableActionFactory: JetSingleIntentionActionFactory() { .filter { it is JetBlockExpression || it is JetDeclarationWithBody } .firstOrNull() as? JetElement ?: return null + val varExpected = refExpr.getAssignmentByLHS() != null + val typeInfo = TypeInfo( + refExpr.getExpressionForTypeGuess(), + if (varExpected) Variance.INVARIANT else Variance.OUT_VARIANCE + ) val containers = refExpr.getExtractionContainers().filterNot { it is JetClassBody || it is JetFile } - val propertyInfo = - createPropertyInfo(refExpr.getReferencedName(), TypeInfo.Empty, TypeInfo(refExpr, Variance.OUT_VARIANCE), containers) + val propertyInfo = PropertyInfo(refExpr.getReferencedName(), TypeInfo.Empty, typeInfo, varExpected, containers) return object: CreateFromUsageFixBase(refExpr) { override fun getText(): String = JetBundle.message("create.local.variable.from.usage", propertyInfo.name) diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createVariable/CreateParameterActionFactory.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createVariable/CreateParameterActionFactory.kt index 2c29ef4d92d..2c486ddcc8d 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createVariable/CreateParameterActionFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/createVariable/CreateParameterActionFactory.kt @@ -37,8 +37,9 @@ import org.jetbrains.jet.plugin.refactoring.changeSignature.JetValVar import org.jetbrains.jet.lang.psi.JetEnumEntry import org.jetbrains.jet.lang.psi.JetClassOrObject import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils -import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.jet.lang.psi.JetNamedFunction +import org.jetbrains.jet.lang.psi.psiUtil.getAssignmentByLHS +import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.getExpressionForTypeGuess object CreateParameterActionFactory: JetSingleIntentionActionFactory() { private fun JetType.hasTypeParametersToAdd(functionDescriptor: FunctionDescriptor, context: BindingContext): Boolean { @@ -69,7 +70,9 @@ object CreateParameterActionFactory: JetSingleIntentionActionFactory() { val refExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null if (refExpr.getQualifiedElement() != refExpr) return null - val paramType = refExpr.guessTypes(context).let { + val varExpected = refExpr.getAssignmentByLHS() != null + + val paramType = refExpr.getExpressionForTypeGuess().guessTypes(context).let { when (it.size) { 0 -> KotlinBuiltIns.getInstance().getAnyType() 1 -> it.first() @@ -80,7 +83,7 @@ object CreateParameterActionFactory: JetSingleIntentionActionFactory() { val parameterInfo = JetParameterInfo(refExpr.getReferencedName(), paramType) fun chooseContainingClass(it: PsiElement): JetClass? { - parameterInfo.setValOrVar(JetValVar.Val) + parameterInfo.setValOrVar(if (varExpected) JetValVar.Var else JetValVar.Val) return it.parents(false).filterIsInstance(javaClass()).firstOrNull() as? JetClass } @@ -89,11 +92,11 @@ object CreateParameterActionFactory: JetSingleIntentionActionFactory() { .filter { it is JetNamedFunction || it is JetPropertyAccessor || it is JetClassBody || it is JetClassInitializer } .firstOrNull() ?.let { - when (it) { - is JetPropertyAccessor -> chooseContainingClass(it) - is JetClassInitializer -> - it.getParent()?.getParent() as? JetClass - is JetClassBody -> { + when { + it is JetNamedFunction && varExpected, + it is JetPropertyAccessor -> chooseContainingClass(it) + it is JetClassInitializer -> it.getParent()?.getParent() as? JetClass + it is JetClassBody -> { val klass = it.getParent() as? JetClass when { klass is JetEnumEntry -> chooseContainingClass(klass) diff --git a/idea/testData/quickfix/createFromUsage/createVariable/localVariable/afterAssignedInFun.kt b/idea/testData/quickfix/createFromUsage/createVariable/localVariable/afterAssignedInFun.kt new file mode 100644 index 00000000000..280fbfa48ce --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/localVariable/afterAssignedInFun.kt @@ -0,0 +1,7 @@ +// "Create local variable 'foo'" "true" + +fun test(n: Int) { + var foo: Int + + foo = n + 1 +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeAssignedInFun.kt b/idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeAssignedInFun.kt new file mode 100644 index 00000000000..6b5bf1f875e --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeAssignedInFun.kt @@ -0,0 +1,5 @@ +// "Create local variable 'foo'" "true" + +fun test(n: Int) { + foo = n + 1 +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/parameter/afterAssignedInFunInClass.kt b/idea/testData/quickfix/createFromUsage/createVariable/parameter/afterAssignedInFunInClass.kt new file mode 100644 index 00000000000..3508164c774 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/parameter/afterAssignedInFunInClass.kt @@ -0,0 +1,7 @@ +// "Create parameter 'foo'" "true" + +class A(var foo: Int) { + fun test(n: Int) { + foo = n + 1 + } +} diff --git a/idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeAssignedInFun.kt b/idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeAssignedInFun.kt new file mode 100644 index 00000000000..982a62312fd --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeAssignedInFun.kt @@ -0,0 +1,8 @@ +// "Create parameter 'foo'" "false" +// ACTION: Create local variable 'foo' +// ACTION: Create property 'foo' from usage +// ERROR: Unresolved reference: foo + +fun test(n: Int) { + foo = n + 1 +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeAssignedInFunInClass.kt b/idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeAssignedInFunInClass.kt new file mode 100644 index 00000000000..867e7d0620a --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeAssignedInFunInClass.kt @@ -0,0 +1,7 @@ +// "Create parameter 'foo'" "true" + +class A { + fun test(n: Int) { + foo = n + 1 + } +} diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnLibType.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnLibType.kt new file mode 100644 index 00000000000..e37bcc2237b --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnLibType.kt @@ -0,0 +1,10 @@ +// "Create property 'foo' from usage" "true" +// ERROR: Property must be initialized + +class A(val n: T) + +fun test() { + 2.foo = A("2") +} + +var Int.foo: A diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnUserType.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnUserType.kt new file mode 100644 index 00000000000..cfe39a83b01 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnUserType.kt @@ -0,0 +1,11 @@ +// "Create property 'foo' from usage" "true" +// ERROR: Property must be initialized or be abstract + +class A(val n: T) { + var foo: String + +} + +fun test() { + A(1).foo = "1" +} diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/beforeVarOnLibType.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/beforeVarOnLibType.kt new file mode 100644 index 00000000000..2fbac99d6d8 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/beforeVarOnLibType.kt @@ -0,0 +1,8 @@ +// "Create property 'foo' from usage" "true" +// ERROR: Property must be initialized + +class A(val n: T) + +fun test() { + 2.foo = A("2") +} diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/beforeVarOnUserType.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/beforeVarOnUserType.kt new file mode 100644 index 00000000000..836c630799b --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/beforeVarOnUserType.kt @@ -0,0 +1,8 @@ +// "Create property 'foo' from usage" "true" +// ERROR: Property must be initialized or be abstract + +class A(val n: T) + +fun test() { + A(1).foo = "1" +} diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index 5eca104a315..608717363b4 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -1179,6 +1179,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createVariable/localVariable"), Pattern.compile("^before(\\w+)\\.kt$"), true); } + @TestMetadata("beforeAssignedInFun.kt") + public void testAssignedInFun() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeAssignedInFun.kt"); + doTest(fileName); + } + @TestMetadata("beforeInAccessor.kt") public void testInAccessor() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeInAccessor.kt"); @@ -1261,6 +1267,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createVariable/parameter"), Pattern.compile("^before(\\w+)\\.kt$"), true); } + @TestMetadata("beforeAssignedInFun.kt") + public void testAssignedInFun() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeAssignedInFun.kt"); + doTest(fileName); + } + + @TestMetadata("beforeAssignedInFunInClass.kt") + public void testAssignedInFunInClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeAssignedInFunInClass.kt"); + doTest(fileName); + } + @TestMetadata("beforeInAccessorInClass.kt") public void testInAccessorInClass() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeInAccessorInClass.kt"); @@ -1559,6 +1577,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("beforeVarOnLibType.kt") + public void testVarOnLibType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/beforeVarOnLibType.kt"); + doTest(fileName); + } + + @TestMetadata("beforeVarOnUserType.kt") + public void testVarOnUserType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/beforeVarOnUserType.kt"); + doTest(fileName); + } + } }