Parameter info fetches default parameter values from library sources
This commit is contained in:
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
|
|||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
public object OptionalParametersHelper {
|
public object OptionalParametersHelper {
|
||||||
@@ -114,26 +115,30 @@ public object OptionalParametersHelper {
|
|||||||
public val parameterUsages: Map<ValueParameterDescriptor, Collection<JetExpression>>
|
public val parameterUsages: Map<ValueParameterDescriptor, Collection<JetExpression>>
|
||||||
)
|
)
|
||||||
|
|
||||||
//TODO: handle imports
|
public fun defaultParameterValueExpression(parameter: ValueParameterDescriptor, project: Project): JetExpression? {
|
||||||
//TODO: handle implicit receivers
|
|
||||||
public fun defaultParameterValue(parameter: ValueParameterDescriptor, project: Project): DefaultValue? {
|
|
||||||
if (!parameter.hasDefaultValue()) return null
|
if (!parameter.hasDefaultValue()) return null
|
||||||
|
|
||||||
if (!parameter.declaresDefaultValue()) {
|
if (!parameter.declaresDefaultValue()) {
|
||||||
val overridden = parameter.getOverriddenDescriptors().firstOrNull { it.hasDefaultValue() } ?: return null
|
val overridden = parameter.getOverriddenDescriptors().firstOrNull { it.hasDefaultValue() } ?: return null
|
||||||
return defaultParameterValue(overridden, project)
|
return defaultParameterValueExpression(overridden, project)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: parameter in overriding method!
|
//TODO: parameter in overriding method!
|
||||||
//TODO: it's a temporary code while we don't have default values accessible from descriptors
|
//TODO: it's a temporary code while we don't have default values accessible from descriptors
|
||||||
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, parameter)?.getNavigationElement() as? JetParameter
|
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, parameter)?.getNavigationElement() as? JetParameter
|
||||||
val expression = declaration?.getDefaultValue() ?: return null
|
return declaration?.defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: handle imports
|
||||||
|
//TODO: handle implicit receivers
|
||||||
|
public fun defaultParameterValue(parameter: ValueParameterDescriptor, project: Project): DefaultValue? {
|
||||||
|
val expression = defaultParameterValueExpression(parameter, project) ?: return null
|
||||||
|
|
||||||
val allParameters = parameter.getContainingDeclaration().getValueParameters().toSet()
|
val allParameters = parameter.getContainingDeclaration().getValueParameters().toSet()
|
||||||
|
|
||||||
val parameterUsages = HashMap<ValueParameterDescriptor, MutableCollection<JetExpression>>()
|
val parameterUsages = HashMap<ValueParameterDescriptor, MutableCollection<JetExpression>>()
|
||||||
|
|
||||||
val bindingContext = expression.analyze()
|
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL)
|
||||||
expression.forEachDescendantOfType<JetSimpleNameExpression> {
|
expression.forEachDescendantOfType<JetSimpleNameExpression> {
|
||||||
val target = bindingContext[BindingContext.REFERENCE_TARGET, it]
|
val target = bindingContext[BindingContext.REFERENCE_TARGET, it]
|
||||||
if (target is ValueParameterDescriptor && target in allParameters) {
|
if (target is ValueParameterDescriptor && target in allParameters) {
|
||||||
|
|||||||
+23
-20
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.idea.parameterInfo
|
|||||||
import com.intellij.codeInsight.CodeInsightBundle
|
import com.intellij.codeInsight.CodeInsightBundle
|
||||||
import com.intellij.codeInsight.lookup.LookupElement
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
import com.intellij.lang.parameterInfo.*
|
import com.intellij.lang.parameterInfo.*
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||||
import com.intellij.ui.Gray
|
import com.intellij.ui.Gray
|
||||||
import com.intellij.ui.JBColor
|
import com.intellij.ui.JBColor
|
||||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
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.core.OptionalParametersHelper
|
||||||
import org.jetbrains.kotlin.idea.core.getResolutionScope
|
import org.jetbrains.kotlin.idea.core.getResolutionScope
|
||||||
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
|
||||||
@@ -146,6 +147,8 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
|
|||||||
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 project = callElement.project
|
||||||
|
|
||||||
val currentParameterIndex = context.currentParameterIndex
|
val currentParameterIndex = context.currentParameterIndex
|
||||||
if (currentParameterIndex < 0) return false // by some strange reason we are invoked with currentParameterIndex == -1 during initialization
|
if (currentParameterIndex < 0) return false // by some strange reason we are invoked with currentParameterIndex == -1 during initialization
|
||||||
|
|
||||||
@@ -169,7 +172,7 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
|
|||||||
boldStartOffset = length()
|
boldStartOffset = length()
|
||||||
}
|
}
|
||||||
|
|
||||||
append(renderParameter(parameter, namedMode))
|
append(renderParameter(parameter, namedMode, project))
|
||||||
|
|
||||||
if (highlightParameter) {
|
if (highlightParameter) {
|
||||||
boldEndOffset = length()
|
boldEndOffset = length()
|
||||||
@@ -214,40 +217,40 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
|
|||||||
companion object {
|
companion object {
|
||||||
val GREEN_BACKGROUND: Color = JBColor(Color(231, 254, 234), Gray._100)
|
val GREEN_BACKGROUND: Color = JBColor(Color(231, 254, 234), Gray._100)
|
||||||
|
|
||||||
private fun renderParameter(parameter: ValueParameterDescriptor, named: Boolean): String {
|
private fun renderParameter(parameter: ValueParameterDescriptor, named: Boolean, project: Project): String {
|
||||||
return StringBuilder {
|
return StringBuilder {
|
||||||
if (named) append("[")
|
if (named) append("[")
|
||||||
|
|
||||||
if (parameter.varargElementType != null) {
|
if (parameter.varargElementType != null) {
|
||||||
append("vararg ")
|
append("vararg ")
|
||||||
}
|
}
|
||||||
append(parameter.name)
|
append(parameter.name)
|
||||||
append(": ")
|
append(": ")
|
||||||
append(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(parameterTypeToRender(parameter)))
|
append(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(parameterTypeToRender(parameter)))
|
||||||
|
|
||||||
if (parameter.hasDefaultValue()) {
|
if (parameter.hasDefaultValue()) {
|
||||||
val parameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(parameter)
|
|
||||||
append(" = ")
|
append(" = ")
|
||||||
append(getDefaultExpressionString(parameterDeclaration))
|
append(parameter.renderDefaultValue(project))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (named) append("]")
|
if (named) append("]")
|
||||||
}.toString()
|
}.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDefaultExpressionString(parameterDeclaration: PsiElement?): String {
|
private fun ValueParameterDescriptor.renderDefaultValue(project: Project): String {
|
||||||
if (parameterDeclaration is JetParameter) {
|
val expression = OptionalParametersHelper.defaultParameterValueExpression(this, project)
|
||||||
val defaultValue = parameterDeclaration.defaultValue
|
if (expression != null) {
|
||||||
if (defaultValue != null) {
|
val text = expression.text
|
||||||
val defaultExpression = defaultValue.text
|
if (text.length() <= 32) {
|
||||||
if (defaultExpression.length() <= 32) {
|
return text
|
||||||
return defaultExpression
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultValue is JetConstantExpression || defaultValue is JetStringTemplateExpression) {
|
if (expression is JetConstantExpression || expression is JetStringTemplateExpression) {
|
||||||
if (defaultExpression.startsWith("\"")) {
|
if (text.startsWith("\"")) {
|
||||||
return "\"...\""
|
return "\"...\""
|
||||||
}
|
}
|
||||||
else if (defaultExpression.startsWith("\'")) {
|
else if (text.startsWith("\'")) {
|
||||||
return "\'...\'"
|
return "\'...\'"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun f() {
|
||||||
|
listOf(1).joinToString(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Text: (<highlight>separator: String = ", "</highlight>, prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "...", transform: ((Int) -> String)? = null), Disabled: false, Strikeout: false, Green: true
|
||||||
+2
-2
@@ -20,8 +20,8 @@ import com.intellij.psi.PsiDocumentManager
|
|||||||
import com.intellij.psi.PsiWhiteSpace
|
import com.intellij.psi.PsiWhiteSpace
|
||||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.test.JetWithJdkAndRuntimeLightProjectDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||||
|
import org.jetbrains.kotlin.idea.test.ProjectDescriptorWithStdlibSources
|
||||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
|||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
|
|
||||||
abstract class AbstractFunctionParameterInfoTest : LightCodeInsightFixtureTestCase() {
|
abstract class AbstractFunctionParameterInfoTest : LightCodeInsightFixtureTestCase() {
|
||||||
override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
override fun getProjectDescriptor() = ProjectDescriptorWithStdlibSources.INSTANCE
|
||||||
|
|
||||||
override fun setUp() {
|
override fun setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
|
|||||||
+6
@@ -35,6 +35,12 @@ public class FunctionParameterInfoTestGenerated extends AbstractFunctionParamete
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/parameterInfo/functionParameterInfo"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/parameterInfo/functionParameterInfo"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("DefaultValuesFromLib.kt")
|
||||||
|
public void testDefaultValuesFromLib() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/parameterInfo/functionParameterInfo/DefaultValuesFromLib.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Deprecated.kt")
|
@TestMetadata("Deprecated.kt")
|
||||||
public void testDeprecated() throws Exception {
|
public void testDeprecated() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/parameterInfo/functionParameterInfo/Deprecated.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/parameterInfo/functionParameterInfo/Deprecated.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user