From aeee8bafe60904315b0ba0fe410f3cc056cc2880 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Tue, 10 Nov 2015 15:07:22 +0300 Subject: [PATCH] Name Suggester: Suggest parameter name for the corresponding argument expression #KT-8111 Fixed --- .../jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt | 14 ++++- .../kotlin/idea/core/KotlinNameSuggester.kt | 63 ++++++++++++++----- .../intentions/IterateExpressionIntention.kt | 4 +- .../callableBuilder/CallableBuilder.kt | 2 +- .../callableBuilder/CallableInfo.kt | 8 +-- .../CallableUsageReplacementStrategy.kt | 2 +- .../createFunction/call/funExtraArgs.kt.after | 2 +- .../call/funMissingArgs.kt.after | 2 +- .../substituteExplicitThisInMember.kt.after | 12 ++-- .../substituteImplicitThisInMember.kt.after | 12 ++-- .../DelegatorToSuperCallInArgument.kt.after | 4 +- .../FunctionLiteral.kt.after | 4 +- .../FunctionLiteralFromExpected.kt.after | 4 +- .../FunctionLiteralWithExtraArgs.kt.after | 4 +- .../IntroduceLambdaAndCreateBlock.kt.after | 4 +- .../NoExplicitReceivers.kt.after | 6 +- .../ReplaceOccurence.kt.after | 4 +- .../ParameterNameByArgumentExpression.kt | 11 ++++ ...erNameByParenthesizedArgumentExpression.kt | 11 ++++ .../nameSuggester/KotlinNameSuggesterTest.kt | 15 +++++ 20 files changed, 137 insertions(+), 51 deletions(-) create mode 100644 idea/testData/refactoring/nameSuggester/ParameterNameByArgumentExpression.kt create mode 100644 idea/testData/refactoring/nameSuggester/ParameterNameByParenthesizedArgumentExpression.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt index 8ce8c2e38b8..efdcca81732 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt @@ -406,4 +406,16 @@ public fun KtDeclaration.visibilityModifier(): PsiElement? { public fun KtDeclaration.visibilityModifierType(): KtModifierKeywordToken? = visibilityModifier()?.node?.elementType as KtModifierKeywordToken? -public fun KtStringTemplateExpression.isPlain() = entries.all { it is KtLiteralStringTemplateEntry } \ No newline at end of file +public fun KtStringTemplateExpression.isPlain() = entries.all { it is KtLiteralStringTemplateEntry } + +public fun KtExpression.getOutermostParenthesizerOrThis(): KtExpression { + return (parentsWithSelf zip parents).firstOrNull { + val (element, parent) = it + when (parent) { + is KtParenthesizedExpression -> false + is KtAnnotatedExpression -> parent.baseExpression != element + is KtLabeledExpression -> parent.baseExpression != element + else -> true + } + }?.first as KtExpression? ?: this +} \ No newline at end of file diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinNameSuggester.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinNameSuggester.kt index da6055efd3e..03ccedda647 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinNameSuggester.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinNameSuggester.kt @@ -18,10 +18,15 @@ package org.jetbrains.kotlin.idea.core import com.intellij.openapi.util.text.StringUtil import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.lexer.KotlinLexer import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getOutermostParenthesizerOrThis import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils @@ -36,7 +41,7 @@ public object KotlinNameSuggester { public fun suggestNamesByExpressionAndType(expression: KtExpression, bindingContext: BindingContext, validator: (String) -> Boolean, defaultName: String?): Collection { val result = LinkedHashSet() - result.addNamesByExpression(expression, validator) + result.addNamesByExpression(expression, bindingContext, validator) val type = bindingContext.getType(expression) if (type != null) { @@ -62,10 +67,13 @@ public object KotlinNameSuggester { return result } - public fun suggestNamesByExpressionOnly(expression: KtExpression, validator: (String) -> Boolean, defaultName: String? = null): List { + public fun suggestNamesByExpressionOnly( + expression: KtExpression, + bindingContext: BindingContext?, + validator: (String) -> Boolean, defaultName: String? = null): List { val result = ArrayList() - result.addNamesByExpression(expression, validator) + result.addNamesByExpression(expression, bindingContext, validator) if (result.isEmpty()) { result.addName(defaultName, validator) @@ -74,10 +82,14 @@ public object KotlinNameSuggester { return result } - public fun suggestIterationVariableNames(collection: KtExpression, elementType: KotlinType, validator: (String) -> Boolean, defaultName: String?): Collection { + public fun suggestIterationVariableNames( + collection: KtExpression, + elementType: KotlinType, + bindingContext: BindingContext?, + validator: (String) -> Boolean, defaultName: String?): Collection { val result = LinkedHashSet() - suggestNamesByExpressionOnly(collection, { true }) + suggestNamesByExpressionOnly(collection, bindingContext, { true }) .map { StringUtil.unpluralize(it) } .filterNotNull() .mapTo(result) { suggestNameByName(it, validator) } @@ -261,18 +273,41 @@ public object KotlinNameSuggester { return matcher.replaceAll("") } - private fun MutableCollection.addNamesByExpression(expression: KtExpression?, validator: (String) -> Boolean) { + private fun MutableCollection.addNamesByExpressionPSI(expression: KtExpression?, validator: (String) -> Boolean) { + if (expression == null) return + val deparenthesized = KtPsiUtil.safeDeparenthesize(expression) + when (deparenthesized) { + is KtSimpleNameExpression -> addCamelNames(deparenthesized.getReferencedName(), validator) + is KtQualifiedExpression -> addNamesByExpressionPSI(deparenthesized.selectorExpression, validator) + is KtCallExpression -> addNamesByExpressionPSI(deparenthesized.calleeExpression, validator) + is KtPostfixExpression -> addNamesByExpressionPSI(deparenthesized.baseExpression, validator) + } + } + + private fun MutableCollection.addNamesByExpression( + expression: KtExpression?, + bindingContext: BindingContext?, + validator: (String) -> Boolean + ) { if (expression == null) return - val expression = KtPsiUtil.safeDeparenthesize(expression) - when (expression) { - is KtSimpleNameExpression -> addCamelNames(expression.getReferencedName(), validator) + addNamesByValueArgument(expression, bindingContext, validator) + addNamesByExpressionPSI(expression, validator) + } - is KtQualifiedExpression -> addNamesByExpression(expression.getSelectorExpression(), validator) - - is KtCallExpression -> addNamesByExpression(expression.getCalleeExpression(), validator) - - is KtPostfixExpression -> addNamesByExpression(expression.getBaseExpression(), validator) + private fun MutableCollection.addNamesByValueArgument( + expression: KtExpression, + bindingContext: BindingContext?, + validator: (String) -> Boolean + ) { + if (bindingContext == null) return + val argumentExpression = expression.getOutermostParenthesizerOrThis() + val valueArgument = argumentExpression.parent as? KtValueArgument ?: return + val resolvedCall = argumentExpression.getParentResolvedCall(bindingContext) ?: return + val argumentMatch = resolvedCall.getArgumentMapping(valueArgument) as? ArgumentMatch ?: return + val parameter = argumentMatch.valueParameter + if (parameter.containingDeclaration.hasStableParameterNames()) { + addName(parameter.name.asString(), validator) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/IterateExpressionIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/IterateExpressionIntention.kt index 5dc3506b022..80bedc352ac 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/IterateExpressionIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/IterateExpressionIntention.kt @@ -21,6 +21,7 @@ import com.intellij.codeInsight.template.TemplateBuilderImpl import com.intellij.codeInsight.template.impl.ConstantNode import com.intellij.openapi.editor.Editor import com.intellij.psi.PsiDocumentManager +import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.core.* import org.jetbrains.kotlin.idea.resolve.ideService @@ -58,7 +59,8 @@ public class IterateExpressionIntention : SelfTargetingIntention(j val elementType = data(element)!!.elementType val nameValidator = NewDeclarationNameValidator(element, element.siblings(), NewDeclarationNameValidator.Target.VARIABLES) - val names = KotlinNameSuggester.suggestIterationVariableNames(element, elementType, nameValidator, "e") + val bindingContext = element.analyze(BodyResolveMode.PARTIAL) + val names = KotlinNameSuggester.suggestIterationVariableNames(element, elementType, bindingContext, nameValidator, "e") var forExpression = KtPsiFactory(element).createExpressionByPattern("for($0 in $1) {\nx\n}", names.first(), element) as KtForExpression forExpression = element.replaced(forExpression) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt index 415287dd5e5..b26fa5e0a9f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt @@ -801,7 +801,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { builder.replaceElement(parameterTypeRef, parameterTypeExpression) // add parameter name to the template - val possibleNamesFromExpression = parameter.typeInfo.possibleNamesFromExpression + val possibleNamesFromExpression = parameter.typeInfo.getPossibleNamesFromExpression(currentFileContext) val preferredName = parameter.preferredName val possibleNames = if (preferredName != null) { arrayOf(preferredName, *possibleNamesFromExpression) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt index 2955c296326..c3e1bc1851d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt @@ -41,8 +41,8 @@ abstract class TypeInfo(val variance: Variance) { } class ByExpression(val expression: KtExpression, variance: Variance): TypeInfo(variance) { - override val possibleNamesFromExpression: Array by lazy { - KotlinNameSuggester.suggestNamesByExpressionOnly(expression, { true }).toTypedArray() + override fun getPossibleNamesFromExpression(bindingContext: BindingContext): Array { + return KotlinNameSuggester.suggestNamesByExpressionOnly(expression, bindingContext, { true }).toTypedArray() } override fun getPossibleTypes(builder: CallableBuilder): List = @@ -70,7 +70,7 @@ abstract class TypeInfo(val variance: Variance) { abstract class DelegatingTypeInfo(val delegate: TypeInfo): TypeInfo(delegate.variance) { override val substitutionsAllowed: Boolean = delegate.substitutionsAllowed - override val possibleNamesFromExpression: Array get() = delegate.possibleNamesFromExpression + override fun getPossibleNamesFromExpression(bindingContext: BindingContext) = delegate.getPossibleNamesFromExpression(bindingContext) override fun getPossibleTypes(builder: CallableBuilder): List = delegate.getPossibleTypes(builder) } @@ -84,7 +84,7 @@ abstract class TypeInfo(val variance: Variance) { open val substitutionsAllowed: Boolean = true open val staticContextRequired: Boolean = false - open val possibleNamesFromExpression: Array get() = ArrayUtil.EMPTY_STRING_ARRAY + open fun getPossibleNamesFromExpression(bindingContext: BindingContext): Array = ArrayUtil.EMPTY_STRING_ARRAY abstract fun getPossibleTypes(builder: CallableBuilder): List protected fun KotlinType?.getPossibleSupertypes(variance: Variance, callableBuilder: CallableBuilder): List { diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt index 72b27ee0149..8a759128e62 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt @@ -652,7 +652,7 @@ private class ConstructedExpressionWrapperWithIntroduceFeature( val name = if (nameSuggestion != null) KotlinNameSuggester.suggestNameByName(nameSuggestion, validator) else - KotlinNameSuggester.suggestNamesByExpressionOnly(value, validator, "t").first() + KotlinNameSuggester.suggestNamesByExpressionOnly(value, bindingContext, validator, "t").first() return Name.identifier(name) } diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/funExtraArgs.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/call/funExtraArgs.kt.after index 2333eeaadc0..f5ab2455eae 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/funExtraArgs.kt.after +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/funExtraArgs.kt.after @@ -3,7 +3,7 @@ class A(val n: T) { fun foo(a: Int): A = throw Exception() - fun foo(t: T, s: String): A { + fun foo(a: T, s: String): A { throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. } } diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/funMissingArgs.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/call/funMissingArgs.kt.after index d58faa396e5..2193368c40d 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/funMissingArgs.kt.after +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/funMissingArgs.kt.after @@ -3,7 +3,7 @@ class A(val n: T) { fun foo(i: Int, s: String): A = throw Exception() - fun foo(t: T): A { + fun foo(i: T): A { throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. } } diff --git a/idea/testData/refactoring/introduceParameter/substituteExplicitThisInMember.kt.after b/idea/testData/refactoring/introduceParameter/substituteExplicitThisInMember.kt.after index bf50a11d376..700715ee035 100644 --- a/idea/testData/refactoring/introduceParameter/substituteExplicitThisInMember.kt.after +++ b/idea/testData/refactoring/introduceParameter/substituteExplicitThisInMember.kt.after @@ -9,12 +9,12 @@ class A(val a: Int) { fun test() { val a = A(1) - val a3 = A(2) - a.foo(a.a + a3.a) + val i2 = A(2) + a.foo(a.a + i2.a) with(A(1)) { - val a2 = A(2) - foo(this.a + a2.a) - val a1 = A(2) - this.foo(this.a + a1.a) + val i1 = A(2) + foo(this.a + i1.a) + val i = A(2) + this.foo(this.a + i.a) } } \ No newline at end of file diff --git a/idea/testData/refactoring/introduceParameter/substituteImplicitThisInMember.kt.after b/idea/testData/refactoring/introduceParameter/substituteImplicitThisInMember.kt.after index bf50a11d376..700715ee035 100644 --- a/idea/testData/refactoring/introduceParameter/substituteImplicitThisInMember.kt.after +++ b/idea/testData/refactoring/introduceParameter/substituteImplicitThisInMember.kt.after @@ -9,12 +9,12 @@ class A(val a: Int) { fun test() { val a = A(1) - val a3 = A(2) - a.foo(a.a + a3.a) + val i2 = A(2) + a.foo(a.a + i2.a) with(A(1)) { - val a2 = A(2) - foo(this.a + a2.a) - val a1 = A(2) - this.foo(this.a + a1.a) + val i1 = A(2) + foo(this.a + i1.a) + val i = A(2) + this.foo(this.a + i.a) } } \ No newline at end of file diff --git a/idea/testData/refactoring/introduceVariable/DelegatorToSuperCallInArgument.kt.after b/idea/testData/refactoring/introduceVariable/DelegatorToSuperCallInArgument.kt.after index 1f40cbc1b5a..e6885677bf5 100644 --- a/idea/testData/refactoring/introduceVariable/DelegatorToSuperCallInArgument.kt.after +++ b/idea/testData/refactoring/introduceVariable/DelegatorToSuperCallInArgument.kt.after @@ -1,6 +1,6 @@ open class A(n: Int) fun foo() { - val i = 1 - val x = object : A(i) {} + val n = 1 + val x = object : A(n) {} } \ No newline at end of file diff --git a/idea/testData/refactoring/introduceVariable/FunctionLiteral.kt.after b/idea/testData/refactoring/introduceVariable/FunctionLiteral.kt.after index 81fd82b8f6b..f56fa8ffcf2 100644 --- a/idea/testData/refactoring/introduceVariable/FunctionLiteral.kt.after +++ b/idea/testData/refactoring/introduceVariable/FunctionLiteral.kt.after @@ -1,5 +1,5 @@ // WITH_RUNTIME fun foo(c : Collection){ - val function: (String) -> Boolean = { it; false } - c.filter(function) + val predicate: (String) -> Boolean = { it; false } + c.filter(predicate) } \ No newline at end of file diff --git a/idea/testData/refactoring/introduceVariable/FunctionLiteralFromExpected.kt.after b/idea/testData/refactoring/introduceVariable/FunctionLiteralFromExpected.kt.after index e3a8b9f69b8..0764c2033a8 100644 --- a/idea/testData/refactoring/introduceVariable/FunctionLiteralFromExpected.kt.after +++ b/idea/testData/refactoring/introduceVariable/FunctionLiteralFromExpected.kt.after @@ -3,6 +3,6 @@ class A { } fun apply(x: (A) -> Int) = 2 fun test() { - val function: (A) -> Int = { it.foo() } - apply(function) + val x: (A) -> Int = { it.foo() } + apply(x) } \ No newline at end of file diff --git a/idea/testData/refactoring/introduceVariable/FunctionLiteralWithExtraArgs.kt.after b/idea/testData/refactoring/introduceVariable/FunctionLiteralWithExtraArgs.kt.after index 2978314b7bd..50cb059c6a6 100644 --- a/idea/testData/refactoring/introduceVariable/FunctionLiteralWithExtraArgs.kt.after +++ b/idea/testData/refactoring/introduceVariable/FunctionLiteralWithExtraArgs.kt.after @@ -1,5 +1,5 @@ // WITH_RUNTIME fun foo(c : Collection){ - val function: (String) -> Boolean = { it.length() > 1 } - c.filterTo(ArrayList(), function) + val predicate: (String) -> Boolean = { it.length() > 1 } + c.filterTo(ArrayList(), predicate) } \ No newline at end of file diff --git a/idea/testData/refactoring/introduceVariable/IntroduceLambdaAndCreateBlock.kt.after b/idea/testData/refactoring/introduceVariable/IntroduceLambdaAndCreateBlock.kt.after index 5b233f0b012..8397c3dde4a 100644 --- a/idea/testData/refactoring/introduceVariable/IntroduceLambdaAndCreateBlock.kt.after +++ b/idea/testData/refactoring/introduceVariable/IntroduceLambdaAndCreateBlock.kt.after @@ -2,7 +2,7 @@ fun foo(p: Int, list: List) { if (p > 0) { - val function: (Int) -> Boolean = { it > 0 } - list.filter(function) + val predicate: (Int) -> Boolean = { it > 0 } + list.filter(predicate) } } \ No newline at end of file diff --git a/idea/testData/refactoring/introduceVariable/NoExplicitReceivers.kt.after b/idea/testData/refactoring/introduceVariable/NoExplicitReceivers.kt.after index ae48ca57401..5fafc9f70ba 100644 --- a/idea/testData/refactoring/introduceVariable/NoExplicitReceivers.kt.after +++ b/idea/testData/refactoring/introduceVariable/NoExplicitReceivers.kt.after @@ -1,9 +1,9 @@ // WITH_RUNTIME fun main(args: Array) { with(A()) { - val prop1 = prop - println(prop1) - println(prop1) + val message = prop + println(message) + println(message) } } diff --git a/idea/testData/refactoring/introduceVariable/ReplaceOccurence.kt.after b/idea/testData/refactoring/introduceVariable/ReplaceOccurence.kt.after index 18fffc66edf..c2d61f8c3f1 100644 --- a/idea/testData/refactoring/introduceVariable/ReplaceOccurence.kt.after +++ b/idea/testData/refactoring/introduceVariable/ReplaceOccurence.kt.after @@ -1,5 +1,5 @@ fun a(x: Int) {} fun b() { - val i = 1 - a(i) + val x = 1 + a(x) } \ No newline at end of file diff --git a/idea/testData/refactoring/nameSuggester/ParameterNameByArgumentExpression.kt b/idea/testData/refactoring/nameSuggester/ParameterNameByArgumentExpression.kt new file mode 100644 index 00000000000..d0035476165 --- /dev/null +++ b/idea/testData/refactoring/nameSuggester/ParameterNameByArgumentExpression.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME +fun x(items : Sequence) {} +fun y() { + x(sequenceOf("")) +} +/* +items +of +sequence +sequenceOf +*/ \ No newline at end of file diff --git a/idea/testData/refactoring/nameSuggester/ParameterNameByParenthesizedArgumentExpression.kt b/idea/testData/refactoring/nameSuggester/ParameterNameByParenthesizedArgumentExpression.kt new file mode 100644 index 00000000000..30fbad141ba --- /dev/null +++ b/idea/testData/refactoring/nameSuggester/ParameterNameByParenthesizedArgumentExpression.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME +fun x(items : Sequence) {} +fun y() { + x(foo@ (sequenceOf(""))) +} +/* +items +of +sequence +sequenceOf +*/ \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/nameSuggester/KotlinNameSuggesterTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/nameSuggester/KotlinNameSuggesterTest.kt index 22f5f93c972..61041c45875 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/nameSuggester/KotlinNameSuggesterTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/nameSuggester/KotlinNameSuggesterTest.kt @@ -21,10 +21,12 @@ import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.core.KotlinNameSuggester import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringUtil +import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.KotlinTestUtils public class KotlinNameSuggesterTest : LightCodeInsightFixtureTestCase() { @@ -56,6 +58,10 @@ public class KotlinNameSuggesterTest : LightCodeInsightFixtureTestCase() { public fun testURL() { doTest() } + public fun testParameterNameByArgumentExpression() { doTest() } + + public fun testParameterNameByParenthesizedArgumentExpression() { doTest() } + override fun setUp() { super.setUp() myFixture.setTestDataPath(PluginTestCaseBase.getTestDataPathBase() + "/refactoring/nameSuggester") @@ -65,7 +71,11 @@ public class KotlinNameSuggesterTest : LightCodeInsightFixtureTestCase() { myFixture.configureByFile(getTestName(false) + ".kt") val file = myFixture.getFile() as KtFile val expectedResultText = KotlinTestUtils.getLastCommentInFile(file) + val withRuntime = InTextDirectivesUtils.isDirectiveDefined(file.text, "//WITH_RUNTIME") try { + if (withRuntime) { + ConfigLibraryUtil.configureKotlinRuntimeAndSdk(myModule, PluginTestCaseBase.mockJdk()) + } KotlinRefactoringUtil.selectExpression(myFixture.getEditor(), file, object : KotlinRefactoringUtil.SelectExpressionCallback { override fun run(expression: KtExpression?) { val names = KotlinNameSuggester.suggestNamesByExpressionAndType(expression!!, expression.analyze(BodyResolveMode.PARTIAL), { true }, "value").sorted() @@ -77,5 +87,10 @@ public class KotlinNameSuggesterTest : LightCodeInsightFixtureTestCase() { catch (e: KotlinRefactoringUtil.IntroduceRefactoringException) { throw AssertionError("Failed to find expression: " + e.getMessage()) } + finally { + if (withRuntime) { + ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(myModule, PluginTestCaseBase.mockJdk()) + } + } } }