Parameter info whole signature is built by information from resolve (+ changed policy for currentParameterIndex == 0)
This commit is contained in:
+64
-86
@@ -41,7 +41,6 @@ import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
|||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallResolver
|
import org.jetbrains.kotlin.resolve.calls.CallResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.allArgumentsMapped
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||||
@@ -138,84 +137,52 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
|
|||||||
val valueParameters = itemToShow.valueParameters
|
val valueParameters = itemToShow.valueParameters
|
||||||
val valueArguments = argumentList.arguments
|
val valueArguments = argumentList.arguments
|
||||||
|
|
||||||
val currentParameterIndex = context.currentParameterIndex
|
|
||||||
var boldStartOffset = -1
|
|
||||||
var boldEndOffset = -1
|
|
||||||
|
|
||||||
val usedIndexes = BooleanArray(valueParameters.size())
|
|
||||||
Arrays.fill(usedIndexes, false)
|
|
||||||
|
|
||||||
var namedMode = false
|
|
||||||
|
|
||||||
val bindingContext = argumentList.analyze(BodyResolveMode.PARTIAL)
|
val bindingContext = argumentList.analyze(BodyResolveMode.PARTIAL)
|
||||||
val callElement = argumentList.parent as? JetCallElement ?: return false
|
val callElement = argumentList.parent as? JetCallElement ?: return false
|
||||||
val call = callElement.getCall(bindingContext) ?: return false
|
val call = callElement.getCall(bindingContext) ?: return false
|
||||||
|
|
||||||
val (highlightParameterIndex, isGrey) = detectSignatureHighlighting(call, itemToShow, currentParameterIndex, bindingContext, argumentList.getResolutionFacade())
|
val (argumentToParameter, highlightParameterIndex, isGrey) = matchCallWithSignature(
|
||||||
|
call, itemToShow, context.currentParameterIndex, bindingContext, argumentList.getResolutionFacade())
|
||||||
|
|
||||||
|
val usedParameterIndices = HashSet<Int>()
|
||||||
|
var namedMode = false
|
||||||
|
var boldStartOffset = -1
|
||||||
|
var boldEndOffset = -1
|
||||||
val text = StringBuilder {
|
val text = StringBuilder {
|
||||||
for (i in valueParameters.indices) {
|
fun appendParameter(parameter: ValueParameterDescriptor) {
|
||||||
if (i != 0) {
|
if (length() > 0) {
|
||||||
append(", ")
|
append(", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
val highlightParameter = i == highlightParameterIndex
|
val highlightParameter = parameter.index == highlightParameterIndex
|
||||||
|
|
||||||
if (highlightParameter) {
|
if (highlightParameter) {
|
||||||
boldStartOffset = length()
|
boldStartOffset = length()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!namedMode) {
|
append(renderParameter(parameter, namedMode))
|
||||||
if (valueArguments.size() > i) {
|
|
||||||
val argument = valueArguments[i]
|
|
||||||
if (argument.isNamed()) {
|
|
||||||
namedMode = true
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val param = valueParameters[i]
|
|
||||||
append(renderParameter(param, false))
|
|
||||||
usedIndexes[i] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val param = valueParameters[i]
|
|
||||||
append(renderParameter(param, false))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (namedMode) {
|
|
||||||
var takeAnyArgument = true
|
|
||||||
if (valueArguments.size() > i) {
|
|
||||||
val argument = valueArguments[i]
|
|
||||||
if (argument.isNamed()) {
|
|
||||||
for ((j, param) in valueParameters.withIndex()) {
|
|
||||||
val referenceExpression = argument.getArgumentName()!!.getReferenceExpression()
|
|
||||||
if (!usedIndexes[j] && param.name == referenceExpression.getReferencedNameAsName()) {
|
|
||||||
takeAnyArgument = false
|
|
||||||
usedIndexes[j] = true
|
|
||||||
append(renderParameter(param, true))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (takeAnyArgument) {
|
|
||||||
for ((j, param) in valueParameters.withIndex()) {
|
|
||||||
if (!usedIndexes[j]) {
|
|
||||||
usedIndexes[j] = true
|
|
||||||
append(renderParameter(param, true))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (highlightParameter) {
|
if (highlightParameter) {
|
||||||
boldEndOffset = length()
|
boldEndOffset = length()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (argument in valueArguments) {
|
||||||
|
val parameter = argumentToParameter(argument) ?: continue
|
||||||
|
if (!usedParameterIndices.add(parameter.index)) continue
|
||||||
|
|
||||||
|
if (argument.isNamed()) {
|
||||||
|
namedMode = true
|
||||||
|
}
|
||||||
|
|
||||||
|
appendParameter(parameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (parameter in valueParameters) {
|
||||||
|
if (parameter.index !in usedParameterIndices) {
|
||||||
|
appendParameter(parameter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (valueParameters.size() == 0) {
|
if (valueParameters.size() == 0) {
|
||||||
append(CodeInsightBundle.message("parameter.info.no.parameters"))
|
append(CodeInsightBundle.message("parameter.info.no.parameters"))
|
||||||
}
|
}
|
||||||
@@ -324,58 +291,69 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
|
|||||||
return argumentList
|
return argumentList
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class SignatureHighlighting(
|
private data class SignatureInfo(
|
||||||
|
val argumentToParameter: (ValueArgument) -> ValueParameterDescriptor?,
|
||||||
val highlightParameterIndex: Int?,
|
val highlightParameterIndex: Int?,
|
||||||
val isGrey: Boolean
|
val isGrey: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun detectSignatureHighlighting(call: Call, overload: FunctionDescriptor, currentArgumentIndex: Int, bindingContext: BindingContext, resolutionFacade: ResolutionFacade): SignatureHighlighting {
|
private fun matchCallWithSignature(
|
||||||
if (currentArgumentIndex == 0) {
|
call: Call,
|
||||||
val highlightParameterIndex = if (overload.valueParameters.isEmpty()) null else 0
|
overload: FunctionDescriptor,
|
||||||
return SignatureHighlighting(highlightParameterIndex, isGrey = false)
|
currentArgumentIndex: Int,
|
||||||
|
bindingContext: BindingContext,
|
||||||
|
resolutionFacade: ResolutionFacade
|
||||||
|
): SignatureInfo {
|
||||||
|
if (currentArgumentIndex == 0 && call.valueArguments.isEmpty() && overload.valueParameters.isEmpty()) {
|
||||||
|
return SignatureInfo({ null }, null, isGrey = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(call.valueArguments.size() >= currentArgumentIndex)
|
assert(call.valueArguments.size() >= currentArgumentIndex)
|
||||||
|
|
||||||
val truncatedArguments = if (call.valueArguments.size() > currentArgumentIndex) {
|
val argumentsBeforeCurrent = call.valueArguments.subList(0, currentArgumentIndex)
|
||||||
call.valueArguments.subList(0, currentArgumentIndex + 1)
|
|
||||||
|
val callToUse: Call
|
||||||
|
val currentArgument: ValueArgument
|
||||||
|
if (call.valueArguments.size() > currentArgumentIndex) {
|
||||||
|
currentArgument = call.valueArguments[currentArgumentIndex]
|
||||||
|
callToUse = call
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val dummyArgument = object : ValueArgument {
|
// add dummy current argument if we don't have one
|
||||||
|
currentArgument = object : ValueArgument {
|
||||||
override fun getArgumentExpression(): JetExpression? = null
|
override fun getArgumentExpression(): JetExpression? = null
|
||||||
override fun getArgumentName(): ValueArgumentName? = null
|
override fun getArgumentName(): ValueArgumentName? = null
|
||||||
override fun isNamed(): Boolean = false
|
override fun isNamed(): Boolean = false
|
||||||
override fun asElement(): JetElement = throw UnsupportedOperationException()
|
override fun asElement(): JetElement = call.callElement // is a hack but what to do?
|
||||||
override fun getSpreadElement(): LeafPsiElement? = null
|
override fun getSpreadElement(): LeafPsiElement? = null
|
||||||
override fun isExternal() = false
|
override fun isExternal() = false
|
||||||
}
|
}
|
||||||
call.valueArguments + dummyArgument
|
callToUse = object : DelegatingCall(call) {
|
||||||
|
val arguments = call.valueArguments + currentArgument
|
||||||
|
|
||||||
|
override fun getValueArguments() = arguments
|
||||||
|
override fun getFunctionLiteralArguments() = emptyList<FunctionLiteralArgument>()
|
||||||
|
override fun getValueArgumentList() = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: do we really need truncated call?
|
val candidates = detectCandidates(callToUse, bindingContext, resolutionFacade)
|
||||||
// leave only arguments before the current one
|
|
||||||
val truncatedCall = object : DelegatingCall(call) {
|
|
||||||
override fun getValueArguments() = truncatedArguments
|
|
||||||
override fun getFunctionLiteralArguments() = emptyList<FunctionLiteralArgument>()
|
|
||||||
override fun getValueArgumentList() = null
|
|
||||||
}
|
|
||||||
|
|
||||||
val candidates = detectCandidates(truncatedCall, bindingContext, resolutionFacade)
|
|
||||||
val resolvedCall = candidates.singleOrNull { it.resultingDescriptor.original == overload.original }
|
val resolvedCall = candidates.singleOrNull { it.resultingDescriptor.original == overload.original }
|
||||||
?: return SignatureHighlighting(null, isGrey = true)
|
?: return SignatureInfo({ null }, null, isGrey = true)
|
||||||
|
|
||||||
val currentParameter = (resolvedCall.getArgumentMapping(truncatedArguments.last()) as? ArgumentMatch)?.valueParameter
|
val argumentToParameter = { argument: ValueArgument -> (resolvedCall.getArgumentMapping(argument) as? ArgumentMatch)?.valueParameter }
|
||||||
|
|
||||||
|
val currentParameter = (resolvedCall.getArgumentMapping(currentArgument) as? ArgumentMatch)?.valueParameter
|
||||||
val highlightParameterIndex = currentParameter?.index
|
val highlightParameterIndex = currentParameter?.index
|
||||||
|
|
||||||
if (!resolvedCall.allArgumentsMapped()) { // some of arguments before the current one are not mapped to any of the parameters
|
if (!(argumentsBeforeCurrent + currentArgument).all { argument -> resolvedCall.getArgumentMapping(argument) is ArgumentMatch }) { // some of arguments before the current one are not mapped to any of the parameters
|
||||||
return SignatureHighlighting(highlightParameterIndex, isGrey = true)
|
return SignatureInfo(argumentToParameter, highlightParameterIndex, isGrey = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// grey out if not all arguments before the current are matched
|
// grey out if not all arguments before the current are matched
|
||||||
val isGrey = truncatedCall.valueArguments
|
val isGrey = argumentsBeforeCurrent
|
||||||
.take(currentArgumentIndex)
|
|
||||||
.any { argument -> resolvedCall.getArgumentMapping(argument).isError() && !argument.hasError(bindingContext) /* ignore arguments that has error type */ }
|
.any { argument -> resolvedCall.getArgumentMapping(argument).isError() && !argument.hasError(bindingContext) /* ignore arguments that has error type */ }
|
||||||
return SignatureHighlighting(highlightParameterIndex, isGrey)
|
return SignatureInfo(argumentToParameter, highlightParameterIndex, isGrey)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ValueArgument.hasError(bindingContext: BindingContext)
|
private fun ValueArgument.hasError(bindingContext: BindingContext)
|
||||||
|
|||||||
+1
-1
@@ -7,6 +7,6 @@ open class A(x: Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Text: (<highlight>[x: Int]</highlight>), Disabled: false, Strikeout: false, Green: false
|
|
||||||
Text: (<highlight>[y: Boolean = true]</highlight>, [x: Int], [z: Long = 12345678901234], [u: String = "abc\n"], [u0: String = "" + "123"], [uu: String = "$u"], [v: Char = '\u0000'], [vv: String = "..."]), Disabled: false, Strikeout: false, Green: true
|
Text: (<highlight>[y: Boolean = true]</highlight>, [x: Int], [z: Long = 12345678901234], [u: String = "abc\n"], [u0: String = "" + "123"], [uu: String = "$u"], [v: Char = '\u0000'], [vv: String = "..."]), Disabled: false, Strikeout: false, Green: true
|
||||||
|
Text: ([x: Int]), Disabled: true, Strikeout: false, Green: false
|
||||||
*/
|
*/
|
||||||
@@ -7,6 +7,6 @@ open class A(x: Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Text: (<highlight>[x: Int]</highlight>), Disabled: false, Strikeout: false, Green: false
|
|
||||||
Text: (<highlight>[y: Boolean]</highlight>, [x: Int]), Disabled: false, Strikeout: false, Green: true
|
Text: (<highlight>[y: Boolean]</highlight>, [x: Int]), Disabled: false, Strikeout: false, Green: true
|
||||||
|
Text: ([x: Int]), Disabled: true, Strikeout: false, Green: false
|
||||||
*/
|
*/
|
||||||
@@ -7,5 +7,5 @@ fun f(c: C) {
|
|||||||
c.foo(<caret>1)
|
c.foo(<caret>1)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Text: (<no parameters>), Disabled: false, Strikeout: false, Green: true
|
Text: (<no parameters>), Disabled: true, Strikeout: false, Green: true
|
||||||
*/
|
*/
|
||||||
+1
-1
@@ -5,5 +5,5 @@ fun test() {
|
|||||||
/*
|
/*
|
||||||
Text: (<highlight>keyValuePair: Pair<Int, String></highlight>), Disabled: false, Strikeout: false, Green: true
|
Text: (<highlight>keyValuePair: Pair<Int, String></highlight>), Disabled: false, Strikeout: false, Green: true
|
||||||
Text: (<highlight>vararg values: Pair<Int, String></highlight>), Disabled: false, Strikeout: false, Green: false
|
Text: (<highlight>vararg values: Pair<Int, String></highlight>), Disabled: false, Strikeout: false, Green: false
|
||||||
Text: (<no parameters>), Disabled: false, Strikeout: false, Green: false
|
Text: (<no parameters>), Disabled: true, Strikeout: false, Green: false
|
||||||
*/
|
*/
|
||||||
Reference in New Issue
Block a user