From a923e9e9c8d5accadc415896318cf51b87a66eb5 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 5 Oct 2015 21:50:43 +0300 Subject: [PATCH] Parameter info fetches default parameter values from library sources --- .../idea/core/OptionalParametersHelper.kt | 17 +++++--- .../KotlinFunctionParameterInfoHandler.kt | 43 ++++++++++--------- .../DefaultValuesFromLib.kt | 5 +++ .../AbstractFunctionParameterInfoTest.kt | 4 +- .../FunctionParameterInfoTestGenerated.java | 6 +++ 5 files changed, 47 insertions(+), 28 deletions(-) create mode 100644 idea/testData/parameterInfo/functionParameterInfo/DefaultValuesFromLib.kt diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/OptionalParametersHelper.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/OptionalParametersHelper.kt index 1f2d8ade4bd..99d8054625b 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/OptionalParametersHelper.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/OptionalParametersHelper.kt @@ -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.isReallySuccess import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import java.util.* public object OptionalParametersHelper { @@ -114,26 +115,30 @@ public object OptionalParametersHelper { public val parameterUsages: Map> ) - //TODO: handle imports - //TODO: handle implicit receivers - public fun defaultParameterValue(parameter: ValueParameterDescriptor, project: Project): DefaultValue? { + public fun defaultParameterValueExpression(parameter: ValueParameterDescriptor, project: Project): JetExpression? { if (!parameter.hasDefaultValue()) return null if (!parameter.declaresDefaultValue()) { val overridden = parameter.getOverriddenDescriptors().firstOrNull { it.hasDefaultValue() } ?: return null - return defaultParameterValue(overridden, project) + return defaultParameterValueExpression(overridden, project) } //TODO: parameter in overriding method! //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 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 parameterUsages = HashMap>() - val bindingContext = expression.analyze() + val bindingContext = expression.analyze(BodyResolveMode.PARTIAL) expression.forEachDescendantOfType { val target = bindingContext[BindingContext.REFERENCE_TARGET, it] if (target is ValueParameterDescriptor && target in allParameters) { diff --git a/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinFunctionParameterInfoHandler.kt b/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinFunctionParameterInfoHandler.kt index 67121ae884c..05e73a495ca 100644 --- a/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinFunctionParameterInfoHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinFunctionParameterInfoHandler.kt @@ -19,7 +19,7 @@ package org.jetbrains.kotlin.idea.parameterInfo import com.intellij.codeInsight.CodeInsightBundle import com.intellij.codeInsight.lookup.LookupElement 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.ui.Gray 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.idea.caches.resolve.analyze 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.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.frontendService @@ -146,6 +147,8 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp val callElement = argumentList.parent as? JetCallElement ?: return false val call = callElement.getCall(bindingContext) ?: return false + val project = callElement.project + val currentParameterIndex = context.currentParameterIndex 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() } - append(renderParameter(parameter, namedMode)) + append(renderParameter(parameter, namedMode, project)) if (highlightParameter) { boldEndOffset = length() @@ -214,40 +217,40 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp companion object { 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 { if (named) append("[") + if (parameter.varargElementType != null) { append("vararg ") } append(parameter.name) append(": ") append(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(parameterTypeToRender(parameter))) + if (parameter.hasDefaultValue()) { - val parameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(parameter) append(" = ") - append(getDefaultExpressionString(parameterDeclaration)) + append(parameter.renderDefaultValue(project)) } + if (named) append("]") }.toString() } - private fun getDefaultExpressionString(parameterDeclaration: PsiElement?): String { - if (parameterDeclaration is JetParameter) { - val defaultValue = parameterDeclaration.defaultValue - if (defaultValue != null) { - val defaultExpression = defaultValue.text - if (defaultExpression.length() <= 32) { - return defaultExpression - } + private fun ValueParameterDescriptor.renderDefaultValue(project: Project): String { + val expression = OptionalParametersHelper.defaultParameterValueExpression(this, project) + if (expression != null) { + val text = expression.text + if (text.length() <= 32) { + return text + } - if (defaultValue is JetConstantExpression || defaultValue is JetStringTemplateExpression) { - if (defaultExpression.startsWith("\"")) { - return "\"...\"" - } - else if (defaultExpression.startsWith("\'")) { - return "\'...\'" - } + if (expression is JetConstantExpression || expression is JetStringTemplateExpression) { + if (text.startsWith("\"")) { + return "\"...\"" + } + else if (text.startsWith("\'")) { + return "\'...\'" } } } diff --git a/idea/testData/parameterInfo/functionParameterInfo/DefaultValuesFromLib.kt b/idea/testData/parameterInfo/functionParameterInfo/DefaultValuesFromLib.kt new file mode 100644 index 00000000000..174434c280d --- /dev/null +++ b/idea/testData/parameterInfo/functionParameterInfo/DefaultValuesFromLib.kt @@ -0,0 +1,5 @@ +fun f() { + listOf(1).joinToString() +} + +//Text: (separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "...", transform: ((Int) -> String)? = null), Disabled: false, Strikeout: false, Green: true \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/AbstractFunctionParameterInfoTest.kt b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/AbstractFunctionParameterInfoTest.kt index ee9b745108b..97ad6f5aef5 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/AbstractFunctionParameterInfoTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/AbstractFunctionParameterInfoTest.kt @@ -20,8 +20,8 @@ import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiWhiteSpace import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase 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.ProjectDescriptorWithStdlibSources import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.psi.JetFile @@ -30,7 +30,7 @@ import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.junit.Assert abstract class AbstractFunctionParameterInfoTest : LightCodeInsightFixtureTestCase() { - override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE + override fun getProjectDescriptor() = ProjectDescriptorWithStdlibSources.INSTANCE override fun setUp() { super.setUp() diff --git a/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/FunctionParameterInfoTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/FunctionParameterInfoTestGenerated.java index f61f0fee789..6da9c7896f6 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/FunctionParameterInfoTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/FunctionParameterInfoTestGenerated.java @@ -35,6 +35,12 @@ public class FunctionParameterInfoTestGenerated extends AbstractFunctionParamete 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") public void testDeprecated() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/parameterInfo/functionParameterInfo/Deprecated.kt");