diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/AddNameToArgumentIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/AddNameToArgumentIntention.kt index 23fe3dd0561..a1e498c7b2e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/AddNameToArgumentIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/AddNameToArgumentIntention.kt @@ -20,6 +20,8 @@ import com.intellij.codeInsight.intention.LowPriorityAction import com.intellij.openapi.editor.Editor import com.intellij.psi.PsiElement import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.conversion.copy.end import org.jetbrains.kotlin.idea.conversion.copy.start @@ -27,11 +29,14 @@ import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch -import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus +import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE +import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus.SUCCESS +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument -class AddNameToArgumentIntention - : SelfTargetingIntention(KtValueArgument::class.java, "Add name to argument"), LowPriorityAction { +class AddNameToArgumentIntention : SelfTargetingIntention( + KtValueArgument::class.java, "Add name to argument" +), LowPriorityAction { override fun isApplicableTo(element: KtValueArgument, caretOffset: Int): Boolean { val expression = element.getArgumentExpression() ?: return false @@ -47,8 +52,8 @@ class AddNameToArgumentIntention return true } - override fun allowCaretInsideElement(element: PsiElement) - = element !is KtValueArgumentList && element !is KtContainerNode && super.allowCaretInsideElement(element) + override fun allowCaretInsideElement(element: PsiElement) = + element !is KtValueArgumentList && element !is KtContainerNode && super.allowCaretInsideElement(element) override fun applyTo(element: KtValueArgument, editor: Editor?) { val name = detectNameToAdd(element)!! @@ -65,20 +70,30 @@ class AddNameToArgumentIntention val callExpr = argumentList.parent as? KtCallElement ?: return null val resolvedCall = callExpr.resolveToCall() ?: return null - val argumentMatch = resolvedCall.getArgumentMapping(argument) as? ArgumentMatch ?: return null - if (argumentMatch.status != ArgumentMatchStatus.SUCCESS) return null - if (!resolvedCall.resultingDescriptor.hasStableParameterNames()) return null - if (argumentMatch.valueParameter.varargElementType != null) { - val varargArgument = resolvedCall.valueArguments[argumentMatch.valueParameter] as? VarargValueArgument ?: return null - if (varargArgument.arguments.size != 1) return null - val versionSettings = callExpr.languageVersionSettings - if (versionSettings.supportsFeature(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm)) { - if (argument.getSpreadElement() == null) return null - } - } + if (!argumentMatchedAndCouldBeNamedInCall(argument, resolvedCall, callExpr.languageVersionSettings)) return null - return argumentMatch.valueParameter.name + return (resolvedCall.getArgumentMapping(argument) as? ArgumentMatch)?.valueParameter?.name + } + + companion object { + fun argumentMatchedAndCouldBeNamedInCall( + argument: ValueArgument, + resolvedCall: ResolvedCall, + versionSettings: LanguageVersionSettings + ): Boolean { + val argumentMatch = resolvedCall.getArgumentMapping(argument) as? ArgumentMatch ?: return false + if (argumentMatch.status != SUCCESS && argumentMatch.status != ARGUMENT_HAS_NO_TYPE) return false + + if (argumentMatch.valueParameter.varargElementType != null) { + val varargArgument = resolvedCall.valueArguments[argumentMatch.valueParameter] as? VarargValueArgument ?: return false + if (varargArgument.arguments.size != 1) return false + if (versionSettings.supportsFeature(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm)) { + if (argument.getSpreadElement() == null) return false + } + } + return true + } } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/AddNamesToCallArgumentsIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/AddNamesToCallArgumentsIntention.kt index 46c43026f24..828a516ae89 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/AddNamesToCallArgumentsIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/AddNamesToCallArgumentsIntention.kt @@ -18,17 +18,14 @@ package org.jetbrains.kotlin.idea.intentions import com.intellij.openapi.editor.Editor import com.intellij.openapi.util.TextRange -import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch -import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus -import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument class AddNamesToCallArgumentsIntention : SelfTargetingRangeIntention( - KtCallElement::class.java, - "Add names to call arguments" + KtCallElement::class.java, + "Add names to call arguments" ) { override fun applicabilityRange(element: KtCallElement): TextRange? { val arguments = element.valueArguments @@ -37,21 +34,14 @@ class AddNamesToCallArgumentsIntention : SelfTargetingRangeIntention generic() = null as T + +fun main() { + foo(generic()) +} \ No newline at end of file diff --git a/idea/testData/intentions/addNameToArgument/genericCall.kt.after b/idea/testData/intentions/addNameToArgument/genericCall.kt.after new file mode 100644 index 00000000000..5f99cf404d7 --- /dev/null +++ b/idea/testData/intentions/addNameToArgument/genericCall.kt.after @@ -0,0 +1,6 @@ +fun foo(a: String) {} +inline fun generic() = null as T + +fun main() { + foo(a = generic()) +} \ No newline at end of file diff --git a/idea/testData/intentions/addNamesToCallArguments/genericCall.kt b/idea/testData/intentions/addNamesToCallArguments/genericCall.kt new file mode 100644 index 00000000000..f3e5266cf00 --- /dev/null +++ b/idea/testData/intentions/addNamesToCallArguments/genericCall.kt @@ -0,0 +1,6 @@ +fun foo(a: String) {} +inline fun generic() = null as T + +fun main() { + foo(generic()) +} \ No newline at end of file diff --git a/idea/testData/intentions/addNamesToCallArguments/genericCall.kt.after b/idea/testData/intentions/addNamesToCallArguments/genericCall.kt.after new file mode 100644 index 00000000000..5f99cf404d7 --- /dev/null +++ b/idea/testData/intentions/addNamesToCallArguments/genericCall.kt.after @@ -0,0 +1,6 @@ +fun foo(a: String) {} +inline fun generic() = null as T + +fun main() { + foo(a = generic()) +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.after.kt b/idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.after.kt index 05cd0f6bd93..725e32904de 100644 --- a/idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.after.kt +++ b/idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.after.kt @@ -2,6 +2,7 @@ // ERROR: Unresolved reference: Some // ACTION: Create function 'Some' // ACTION: Rename reference +// ACTION: Add 'ctor =' to argument package p1 diff --git a/idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.before.Main.kt b/idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.before.Main.kt index 05cd0f6bd93..725e32904de 100644 --- a/idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.before.Main.kt +++ b/idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.before.Main.kt @@ -2,6 +2,7 @@ // ERROR: Unresolved reference: Some // ACTION: Create function 'Some' // ACTION: Rename reference +// ACTION: Add 'ctor =' to argument package p1 diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/notAbstractClass.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/notAbstractClass.kt index 85d41825b89..6b01936f41e 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/notAbstractClass.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/notAbstractClass.kt @@ -1,6 +1,7 @@ // "Create abstract function 'foo'" "false" // ACTION: Create function 'foo' // ACTION: Rename reference +// ACTION: Add 'b =' to argument // ERROR: Unresolved reference: foo class A { fun bar(b: Boolean) {} diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/otherExplicitReceiver.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/otherExplicitReceiver.kt index 029ce3c8edf..009bf228daa 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/otherExplicitReceiver.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/otherExplicitReceiver.kt @@ -2,6 +2,7 @@ // ACTION: Create extension function 'B.foo' // ACTION: Create member function 'B.foo' // ACTION: Rename reference +// ACTION: Add 'b =' to argument // ERROR: Unresolved reference: foo abstract class A { fun bar(b: Boolean) {} diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/notExtensionCallable.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/notExtensionCallable.kt index 76e6a3d5405..36eb7f3e8ef 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/notExtensionCallable.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/notExtensionCallable.kt @@ -1,6 +1,7 @@ // "Create extension function 'foo'" "false" // ACTION: Create function 'foo' // ACTION: Rename reference +// ACTION: Add 'b =' to argument // ERROR: Unresolved reference: foo fun bar(b: Boolean) { diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/propertyOnUserType.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/propertyOnUserType.kt index 9f6d59d7e62..0c1f71f7b56 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/propertyOnUserType.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/propertyOnUserType.kt @@ -1,4 +1,5 @@ // "Create member function 'foo'" "false" +// ACTION: Add names to call arguments // ERROR: Unresolved reference: x class A(val n: T) { diff --git a/idea/testData/quickfix/createFromUsage/createFunction/callableReferences/noFunctionalType.kt b/idea/testData/quickfix/createFromUsage/createFunction/callableReferences/noFunctionalType.kt index cb4649d8edd..095eceea2c4 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/callableReferences/noFunctionalType.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/callableReferences/noFunctionalType.kt @@ -1,5 +1,6 @@ // "Create function 'foo'" "false" // ACTION: Rename reference +// ACTION: Add 'n =' to argument // ERROR: Unresolved reference: foo fun bar(n: Int) = "$n" diff --git a/idea/testData/quickfix/createFromUsage/createVariable/localVariable/callableRef.kt b/idea/testData/quickfix/createFromUsage/createVariable/localVariable/callableRef.kt index 7e1bb019349..f98ade8945d 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/localVariable/callableRef.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/localVariable/callableRef.kt @@ -1,6 +1,7 @@ // "Create local variable 'foo'" "false" // ACTION: Rename reference // ACTION: Create function 'foo' +// ACTION: Add 'f =' to argument // ERROR: Unresolved reference: foo fun test(f: (Int) -> Int) {} diff --git a/idea/testData/quickfix/createFromUsage/createVariable/parameter/callableRef.kt b/idea/testData/quickfix/createFromUsage/createVariable/parameter/callableRef.kt index 7b2174d7a02..494d1a6ecce 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/parameter/callableRef.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/parameter/callableRef.kt @@ -1,6 +1,7 @@ // "Create parameter 'foo'" "false" // ACTION: Rename reference // ACTION: Create function 'foo' +// ACTION: Add 'f =' to argument // ERROR: Unresolved reference: foo fun test(f: (Int) -> Int) {} diff --git a/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromEnumEntryDelegationSpecifier.kt b/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromEnumEntryDelegationSpecifier.kt index 4b92beafa7d..ae37ef0d7c7 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromEnumEntryDelegationSpecifier.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromEnumEntryDelegationSpecifier.kt @@ -2,6 +2,7 @@ // ERROR: Unresolved reference: x // ACTION: Create property 'x' // ACTION: Rename reference +// ACTION: Add 'n =' to argument enum class E(n: Int) { X(x) diff --git a/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromObjectDelegationSpecifier.kt b/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromObjectDelegationSpecifier.kt index a461eac5cb7..6a0746a53ee 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromObjectDelegationSpecifier.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromObjectDelegationSpecifier.kt @@ -2,6 +2,7 @@ // ERROR: Unresolved reference: b // ACTION: Create property 'b' // ACTION: Rename reference +// ACTION: Add 'a =' to argument open class A(val a: Int) { diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/notAbstractClass.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/notAbstractClass.kt index 089864bee1c..520cadb8b7e 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/notAbstractClass.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/notAbstractClass.kt @@ -4,6 +4,7 @@ // ACTION: Create property 'foo' // ACTION: Create property 'foo' as constructor parameter // ACTION: Rename reference +// ACTION: Add 'b =' to argument // ERROR: Unresolved reference: foo class A { fun bar(b: Boolean) {} diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/otherExplicitReceiver.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/otherExplicitReceiver.kt index 3169cac00ec..0279fb09266 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/otherExplicitReceiver.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/otherExplicitReceiver.kt @@ -3,6 +3,7 @@ // ACTION: Create member property 'B.foo' // ACTION: Create property 'foo' as constructor parameter // ACTION: Rename reference +// ACTION: Add 'b =' to argument // ERROR: Unresolved reference: foo abstract class A { fun bar(b: Boolean) {} diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/callableRef.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/callableRef.kt index 5a7ddad8e02..93fcc1d4db4 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/callableRef.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/callableRef.kt @@ -1,6 +1,7 @@ // "Create property 'foo'" "false" // ACTION: Rename reference // ACTION: Create function 'foo' +// ACTION: Add 'f =' to argument // ERROR: Unresolved reference: foo fun test(f: (Int) -> Int) {} diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/memberWithTypeParameterAsReceiver.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/memberWithTypeParameterAsReceiver.kt index e64d4b2439c..5f0e7836b85 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/memberWithTypeParameterAsReceiver.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/memberWithTypeParameterAsReceiver.kt @@ -1,6 +1,7 @@ // "Create member property 'bar'" "false" // ACTION: Create extension property 'T.bar' // ACTION: Rename reference +// ACTION: Add 'n =' to argument // ERROR: Unresolved reference: bar fun consume(n: Int) {} diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index fdcd18fe0c3..887f22721bc 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -1151,6 +1151,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest { runTest("idea/testData/intentions/addNameToArgument/functionLiteralArgument.kt"); } + @TestMetadata("genericCall.kt") + public void testGenericCall() throws Exception { + runTest("idea/testData/intentions/addNameToArgument/genericCall.kt"); + } + @TestMetadata("incompleteCall.kt") public void testIncompleteCall() throws Exception { runTest("idea/testData/intentions/addNameToArgument/incompleteCall.kt"); @@ -1254,6 +1259,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest { runTest("idea/testData/intentions/addNamesToCallArguments/ambiguousCall.kt"); } + @TestMetadata("genericCall.kt") + public void testGenericCall() throws Exception { + runTest("idea/testData/intentions/addNamesToCallArguments/genericCall.kt"); + } + @TestMetadata("incompleteCall.kt") public void testIncompleteCall() throws Exception { runTest("idea/testData/intentions/addNamesToCallArguments/incompleteCall.kt");