From 108e97b70e66c30d90db8328917c2eaac8d8cc4c Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Sat, 22 Apr 2017 12:43:35 +0200 Subject: [PATCH] Show parameter hints for ambiguous calls --- .../KotlinInlayParameterHintsProvider.kt | 38 ++++++++++++------ .../parameterInfo/InlayParameterHintsTest.kt | 39 +++++++++++++++++++ 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinInlayParameterHintsProvider.kt b/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinInlayParameterHintsProvider.kt index 1346be715ad..63680889c60 100644 --- a/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinInlayParameterHintsProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinInlayParameterHintsProvider.kt @@ -24,11 +24,14 @@ import com.intellij.lang.Language import com.intellij.lang.java.JavaLanguage import com.intellij.psi.PsiElement import com.intellij.psi.codeStyle.CodeStyleSettingsManager +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings +import org.jetbrains.kotlin.idea.core.resolveCandidates import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getReturnTypeReference import org.jetbrains.kotlin.lexer.KtTokens @@ -38,8 +41,10 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.RenderingFormat +import org.jetbrains.kotlin.resolve.calls.callUtil.getCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode @@ -121,21 +126,32 @@ private enum class HintType(desc: String, enabled: Boolean) { private fun provideParameterInfo(element: KtCallExpression): List { val ctx = element.analyze(BodyResolveMode.PARTIAL) - element.getResolvedCall(ctx)?.let { resolvedCall -> - return resolvedCall.valueArguments.mapNotNull { (valueParam: ValueParameterDescriptor, resolvedArg) -> - resolvedArg.arguments.firstOrNull()?.let { arg -> - arg.getArgumentExpression()?.let { argExp -> - if (!arg.isNamed() && !valueParam.name.isSpecial && argExp.isUnclearExpression()) { - val prefix = if (valueParam.varargElementType != null) "..." else "" - return@mapNotNull InlayInfo(prefix + valueParam.name.identifier, argExp.startOffset) - } + val call = element.getCall(ctx) ?: return emptyList() + val candidates = call.resolveCandidates(ctx, element.getResolutionFacade()) + if (candidates.isEmpty()) return emptyList() + candidates.singleOrNull()?.let { return getParameterInfoForCallCandidate(it) } + return candidates.map { getParameterInfoForCallCandidate(it) }.reduce { infos1, infos2 -> + for (index in infos1.indices) { + if (index >= infos2.size || infos1[index] != infos2[index]) { + return@reduce infos1.subList(0, index) + } + } + infos1 + } + } + + private fun getParameterInfoForCallCandidate(resolvedCall: ResolvedCall): List { + return resolvedCall.valueArguments.mapNotNull { (valueParam: ValueParameterDescriptor, resolvedArg) -> + resolvedArg.arguments.firstOrNull()?.let { arg -> + arg.getArgumentExpression()?.let { argExp -> + if (!arg.isNamed() && !valueParam.name.isSpecial && argExp.isUnclearExpression()) { + val prefix = if (valueParam.varargElementType != null) "..." else "" + return@mapNotNull InlayInfo(prefix + valueParam.name.identifier, argExp.startOffset) } } - null } + null } - - return emptyList() } private fun KtExpression.isUnclearExpression() = when(this) { diff --git a/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/InlayParameterHintsTest.kt b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/InlayParameterHintsTest.kt index 5735cb27e2b..dd9deb3de5f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/InlayParameterHintsTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/InlayParameterHintsTest.kt @@ -91,5 +91,44 @@ class InlayParameterHintsTest : KotlinLightCodeInsightFixtureTestCase() { """) } + fun `test inline positive and negative numbers`() { + check(""" + fun main() { + val obj = Any() + count(-1, obj); + count(+1, obj); + } + + fun count(test: Int, obj: Any) { + } +} +""") + } + + fun `test show ambiguous`() { + check(""" + fun main() { + test(10, x); + } + fun test(a: Int, bS: String) {} + fun test(a: Int, bI: Int) {} +""") + } + + fun `test show ambiguous constructor`() { + check(""" + fun main() { + X(10, x); + } +} + +class X { + constructor(a: Int, bI: Int) {} + constructor(a: Int, bS: String) {} +} +""") + } + + }