Add support for mixed named arguments to parameter info popup
Don't display parameter info in square brackets if the caller doesn't have to use a named argument. This makes the parameter info popup reflect the new capability introduced with MixedNamedArgumentsInTheirOwnPosition. ^KT-41645 Fixed
This commit is contained in:
committed by
Vladimir Dolzhenko
parent
af6e744b65
commit
91c021c699
+22
-5
@@ -25,14 +25,17 @@ import com.intellij.psi.impl.source.tree.LeafPsiElement
|
|||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.ui.Gray
|
import com.intellij.ui.Gray
|
||||||
import com.intellij.ui.JBColor
|
import com.intellij.ui.JBColor
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.idea.FrontendInternals
|
import org.jetbrains.kotlin.idea.FrontendInternals
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.idea.completion.canBeUsedWithoutNameInCall
|
||||||
import org.jetbrains.kotlin.idea.core.OptionalParametersHelper
|
import org.jetbrains.kotlin.idea.core.OptionalParametersHelper
|
||||||
import org.jetbrains.kotlin.idea.core.resolveCandidates
|
import org.jetbrains.kotlin.idea.core.resolveCandidates
|
||||||
|
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||||
import org.jetbrains.kotlin.idea.util.ShadowedDeclarationsFilter
|
import org.jetbrains.kotlin.idea.util.ShadowedDeclarationsFilter
|
||||||
@@ -213,6 +216,9 @@ abstract class KotlinParameterInfoWithCallHandlerBase<TArgumentList : KtElement,
|
|||||||
if (!argumentListClass.java.isInstance(context.parameterOwner)) return false
|
if (!argumentListClass.java.isInstance(context.parameterOwner)) return false
|
||||||
val call = itemToShow.call ?: return false
|
val call = itemToShow.call ?: return false
|
||||||
|
|
||||||
|
val supportsMixedNamedArgumentsInTheirOwnPosition =
|
||||||
|
call.callElement.languageVersionSettings.supportsFeature(LanguageFeature.MixedNamedArgumentsInTheirOwnPosition)
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val argumentList = context.parameterOwner as TArgumentList
|
val argumentList = context.parameterOwner as TArgumentList
|
||||||
|
|
||||||
@@ -230,6 +236,7 @@ abstract class KotlinParameterInfoWithCallHandlerBase<TArgumentList : KtElement,
|
|||||||
val text = buildString {
|
val text = buildString {
|
||||||
val usedParameterIndices = HashSet<Int>()
|
val usedParameterIndices = HashSet<Int>()
|
||||||
var namedMode = false
|
var namedMode = false
|
||||||
|
var argumentIndex = 0
|
||||||
|
|
||||||
if (call.callType == Call.CallType.ARRAY_SET_METHOD) {
|
if (call.callType == Call.CallType.ARRAY_SET_METHOD) {
|
||||||
// for set-operator the last parameter is used for the value assigned
|
// for set-operator the last parameter is used for the value assigned
|
||||||
@@ -238,7 +245,9 @@ abstract class KotlinParameterInfoWithCallHandlerBase<TArgumentList : KtElement,
|
|||||||
|
|
||||||
val includeParameterNames = !substitutedDescriptor.hasSynthesizedParameterNames()
|
val includeParameterNames = !substitutedDescriptor.hasSynthesizedParameterNames()
|
||||||
|
|
||||||
fun appendParameter(parameter: ValueParameterDescriptor) {
|
fun appendParameter(parameter: ValueParameterDescriptor, named: Boolean = false) {
|
||||||
|
argumentIndex++
|
||||||
|
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
append(", ")
|
append(", ")
|
||||||
}
|
}
|
||||||
@@ -248,7 +257,7 @@ abstract class KotlinParameterInfoWithCallHandlerBase<TArgumentList : KtElement,
|
|||||||
boldStartOffset = length
|
boldStartOffset = length
|
||||||
}
|
}
|
||||||
|
|
||||||
append(renderParameter(parameter, includeParameterNames, namedMode, project))
|
append(renderParameter(parameter, includeParameterNames, named || namedMode, project))
|
||||||
|
|
||||||
if (highlightParameter) {
|
if (highlightParameter) {
|
||||||
boldEndOffset = length
|
boldEndOffset = length
|
||||||
@@ -260,15 +269,20 @@ abstract class KotlinParameterInfoWithCallHandlerBase<TArgumentList : KtElement,
|
|||||||
val parameter = argumentToParameter(argument) ?: continue
|
val parameter = argumentToParameter(argument) ?: continue
|
||||||
if (!usedParameterIndices.add(parameter.index)) continue
|
if (!usedParameterIndices.add(parameter.index)) continue
|
||||||
|
|
||||||
if (argument.isNamed()) {
|
if (argument.isNamed() &&
|
||||||
|
!(supportsMixedNamedArgumentsInTheirOwnPosition && argument.canBeUsedWithoutNameInCall(itemToShow))
|
||||||
|
) {
|
||||||
namedMode = true
|
namedMode = true
|
||||||
}
|
}
|
||||||
|
|
||||||
appendParameter(parameter)
|
appendParameter(parameter, argument.isNamed())
|
||||||
}
|
}
|
||||||
|
|
||||||
for (parameter in substitutedDescriptor.valueParameters) {
|
for (parameter in substitutedDescriptor.valueParameters) {
|
||||||
if (parameter.index !in usedParameterIndices) {
|
if (parameter.index !in usedParameterIndices) {
|
||||||
|
if (argumentIndex != parameter.index) {
|
||||||
|
namedMode = true
|
||||||
|
}
|
||||||
appendParameter(parameter)
|
appendParameter(parameter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -521,6 +535,9 @@ abstract class KotlinParameterInfoWithCallHandlerBase<TArgumentList : KtElement,
|
|||||||
private fun ValueArgument.hasError(bindingContext: BindingContext) =
|
private fun ValueArgument.hasError(bindingContext: BindingContext) =
|
||||||
getArgumentExpression()?.let { bindingContext.getType(it) }?.isError ?: true
|
getArgumentExpression()?.let { bindingContext.getType(it) }?.isError ?: true
|
||||||
|
|
||||||
|
private fun ValueArgument.canBeUsedWithoutNameInCall(callInfo: CallInfo) =
|
||||||
|
this is KtValueArgument && this.canBeUsedWithoutNameInCall(callInfo.resolvedCall as ResolvedCall<out CallableDescriptor>)
|
||||||
|
|
||||||
// we should not compare descriptors directly because partial resolve is involved
|
// we should not compare descriptors directly because partial resolve is involved
|
||||||
private fun descriptorsEqual(descriptor1: FunctionDescriptor, descriptor2: FunctionDescriptor): Boolean {
|
private fun descriptorsEqual(descriptor1: FunctionDescriptor, descriptor2: FunctionDescriptor): Boolean {
|
||||||
if (descriptor1.original == descriptor2.original) return true
|
if (descriptor1.original == descriptor2.original) return true
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
open class A(x: Int) {
|
||||||
|
fun m(x: Boolean, y: Int) = 1
|
||||||
|
fun m(x: Boolean, y: Int, z: Int) = 2
|
||||||
|
|
||||||
|
fun d(x: Int) {
|
||||||
|
m(false, y = 23<caret>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Text: (x: Boolean, <highlight>[y: Int]</highlight>), Disabled: false, Strikeout: false, Green: true
|
||||||
|
Text: (x: Boolean, <highlight>[y: Int]</highlight>, z: Int), Disabled: false, Strikeout: false, Green: false
|
||||||
|
*/
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// COMPILER_ARGUMENTS: -XXLanguage:-MixedNamedArgumentsInTheirOwnPosition
|
||||||
|
|
||||||
|
open class A(x: Int) {
|
||||||
|
fun m(x: Boolean, y: Int) = 1
|
||||||
|
fun m(x: Boolean, y: Int, z: Int) = 2
|
||||||
|
|
||||||
|
fun d(x: Int) {
|
||||||
|
m(false, y = 23<caret>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Text: (x: Boolean, <highlight>[y: Int]</highlight>), Disabled: false, Strikeout: false, Green: true
|
||||||
|
Text: (x: Boolean, <highlight>[y: Int]</highlight>, [z: Int]), Disabled: false, Strikeout: false, Green: false
|
||||||
|
*/
|
||||||
+10
@@ -196,6 +196,16 @@ public class ParameterInfoTestGenerated extends AbstractParameterInfoTest {
|
|||||||
runTest("idea/testData/parameterInfo/functionCall/LocalFunctionBug.kt");
|
runTest("idea/testData/parameterInfo/functionCall/LocalFunctionBug.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("MixedNamedArguments.kt")
|
||||||
|
public void testMixedNamedArguments() throws Exception {
|
||||||
|
runTest("idea/testData/parameterInfo/functionCall/MixedNamedArguments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("MixedNamedArguments2.kt")
|
||||||
|
public void testMixedNamedArguments2() throws Exception {
|
||||||
|
runTest("idea/testData/parameterInfo/functionCall/MixedNamedArguments2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("NamedAndDefaultParameter.kt")
|
@TestMetadata("NamedAndDefaultParameter.kt")
|
||||||
public void testNamedAndDefaultParameter() throws Exception {
|
public void testNamedAndDefaultParameter() throws Exception {
|
||||||
runTest("idea/testData/parameterInfo/functionCall/NamedAndDefaultParameter.kt");
|
runTest("idea/testData/parameterInfo/functionCall/NamedAndDefaultParameter.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user