Show parameter hints for ambiguous calls
This commit is contained in:
+27
-11
@@ -24,11 +24,14 @@ import com.intellij.lang.Language
|
|||||||
import com.intellij.lang.java.JavaLanguage
|
import com.intellij.lang.java.JavaLanguage
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||||
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.caches.resolve.analyze
|
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.formatter.KotlinCodeStyleSettings
|
||||||
|
import org.jetbrains.kotlin.idea.core.resolveCandidates
|
||||||
import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention
|
import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getReturnTypeReference
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getReturnTypeReference
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
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.psi.psiUtil.startOffset
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.renderer.RenderingFormat
|
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.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
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.fqNameOrNull
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
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<InlayInfo> {
|
private fun provideParameterInfo(element: KtCallExpression): List<InlayInfo> {
|
||||||
val ctx = element.analyze(BodyResolveMode.PARTIAL)
|
val ctx = element.analyze(BodyResolveMode.PARTIAL)
|
||||||
element.getResolvedCall(ctx)?.let { resolvedCall ->
|
val call = element.getCall(ctx) ?: return emptyList()
|
||||||
return resolvedCall.valueArguments.mapNotNull { (valueParam: ValueParameterDescriptor, resolvedArg) ->
|
val candidates = call.resolveCandidates(ctx, element.getResolutionFacade())
|
||||||
resolvedArg.arguments.firstOrNull()?.let { arg ->
|
if (candidates.isEmpty()) return emptyList()
|
||||||
arg.getArgumentExpression()?.let { argExp ->
|
candidates.singleOrNull()?.let { return getParameterInfoForCallCandidate(it) }
|
||||||
if (!arg.isNamed() && !valueParam.name.isSpecial && argExp.isUnclearExpression()) {
|
return candidates.map { getParameterInfoForCallCandidate(it) }.reduce { infos1, infos2 ->
|
||||||
val prefix = if (valueParam.varargElementType != null) "..." else ""
|
for (index in infos1.indices) {
|
||||||
return@mapNotNull InlayInfo(prefix + valueParam.name.identifier, argExp.startOffset)
|
if (index >= infos2.size || infos1[index] != infos2[index]) {
|
||||||
}
|
return@reduce infos1.subList(0, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
infos1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getParameterInfoForCallCandidate(resolvedCall: ResolvedCall<out CallableDescriptor>): List<InlayInfo> {
|
||||||
|
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) {
|
private fun KtExpression.isUnclearExpression() = when(this) {
|
||||||
|
|||||||
@@ -91,5 +91,44 @@ class InlayParameterHintsTest : KotlinLightCodeInsightFixtureTestCase() {
|
|||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun `test inline positive and negative numbers`() {
|
||||||
|
check("""
|
||||||
|
fun main() {
|
||||||
|
val obj = Any()
|
||||||
|
count(<hint text="test:"/>-1, obj);
|
||||||
|
count(<hint text="test:"/>+1, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun count(test: Int, obj: Any) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test show ambiguous`() {
|
||||||
|
check("""
|
||||||
|
fun main() {
|
||||||
|
test(<hint text="a:"/>10, x);
|
||||||
|
}
|
||||||
|
fun test(a: Int, bS: String) {}
|
||||||
|
fun test(a: Int, bI: Int) {}
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test show ambiguous constructor`() {
|
||||||
|
check("""
|
||||||
|
fun main() {
|
||||||
|
X(<hint text="a:"/>10, x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class X {
|
||||||
|
constructor(a: Int, bI: Int) {}
|
||||||
|
constructor(a: Int, bS: String) {}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user