From 0120085443a4b95dfdcd0bcab083c8852697084c Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 30 Sep 2016 12:22:42 +0300 Subject: [PATCH] Refine expression kind definition in postfix templates - Do not treat if without else as values - Some statements aren't contained in block (see tests) #KT-14107 Fixed #KT-14110 Fixed --- .../postfix/KtPostfixTemplateProvider.kt | 14 +++++++++++--- .../codeInsight/postfix/returnFromLoop.kt | 4 ++++ .../postfix/returnFromLoop.kt.after | 4 ++++ idea/testData/codeInsight/postfix/soutInIf.kt | 4 ++++ .../codeInsight/postfix/soutInIf.kt.after | 4 ++++ .../testData/codeInsight/postfix/soutInLoop.kt | 4 ++++ .../codeInsight/postfix/soutInLoop.kt.after | 4 ++++ .../PostfixTemplateProviderTestGenerated.java | 18 ++++++++++++++++++ 8 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 idea/testData/codeInsight/postfix/returnFromLoop.kt create mode 100644 idea/testData/codeInsight/postfix/returnFromLoop.kt.after create mode 100644 idea/testData/codeInsight/postfix/soutInIf.kt create mode 100644 idea/testData/codeInsight/postfix/soutInIf.kt.after create mode 100644 idea/testData/codeInsight/postfix/soutInLoop.kt create mode 100644 idea/testData/codeInsight/postfix/soutInLoop.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt index 903efbfca33..f9b867e22ff 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.intentions.negate import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf +import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement import org.jetbrains.kotlin.resolve.calls.callUtil.getType import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.KotlinType @@ -128,16 +129,23 @@ private class KtExpressionPostfixTemplateSelector( // Both KtLambdaExpression and KtFunctionLiteral have the same offset, so we add only one of them -> KtLambdaExpression if (it is KtFunctionLiteral) return@Condition false - if (statementsOnly && it.parent !is KtBlockExpression) return@Condition false + val context by lazy { it.analyze(BodyResolveMode.PARTIAL_FOR_COMPLETION) } + + if (statementsOnly && it.parent !is KtBlockExpression && !it.isUsedAsStatement(context)) return@Condition false if (checkCanBeUsedAsValue && !it.canBeUsedAsValue()) return@Condition false - typePredicate == null || it.getType(it.analyze(BodyResolveMode.PARTIAL_FOR_COMPLETION))?.let { typePredicate(it) } ?: false + typePredicate == null || it.getType(context)?.let { typePredicate(it) } ?: false } private fun KtExpression.canBeUsedAsValue() = !KtPsiUtil.isAssignment(this) && !this.isNamedDeclaration && - this !is KtLoopExpression + this !is KtLoopExpression && + // if's only with else may be treated as expressions + !isIfWithoutElse + + private val KtExpression.isIfWithoutElse: Boolean + get() = (this is KtIfExpression && this.elseKeyword == null) } override fun getExpressions(context: PsiElement, document: Document, offset: Int): List { diff --git a/idea/testData/codeInsight/postfix/returnFromLoop.kt b/idea/testData/codeInsight/postfix/returnFromLoop.kt new file mode 100644 index 00000000000..1e1280ea364 --- /dev/null +++ b/idea/testData/codeInsight/postfix/returnFromLoop.kt @@ -0,0 +1,4 @@ +fun foo() { + for (i in 1..9) + i.return +} diff --git a/idea/testData/codeInsight/postfix/returnFromLoop.kt.after b/idea/testData/codeInsight/postfix/returnFromLoop.kt.after new file mode 100644 index 00000000000..9e374380798 --- /dev/null +++ b/idea/testData/codeInsight/postfix/returnFromLoop.kt.after @@ -0,0 +1,4 @@ +fun foo() { + for (i in 1..9) + return i +} diff --git a/idea/testData/codeInsight/postfix/soutInIf.kt b/idea/testData/codeInsight/postfix/soutInIf.kt new file mode 100644 index 00000000000..fad6a7b4190 --- /dev/null +++ b/idea/testData/codeInsight/postfix/soutInIf.kt @@ -0,0 +1,4 @@ +fun foo(x: Int, y: Int) { + if (x > y) + x.sout +} diff --git a/idea/testData/codeInsight/postfix/soutInIf.kt.after b/idea/testData/codeInsight/postfix/soutInIf.kt.after new file mode 100644 index 00000000000..b4abb3b67e1 --- /dev/null +++ b/idea/testData/codeInsight/postfix/soutInIf.kt.after @@ -0,0 +1,4 @@ +fun foo(x: Int, y: Int) { + if (x > y) + println(x) +} diff --git a/idea/testData/codeInsight/postfix/soutInLoop.kt b/idea/testData/codeInsight/postfix/soutInLoop.kt new file mode 100644 index 00000000000..908bb4163ea --- /dev/null +++ b/idea/testData/codeInsight/postfix/soutInLoop.kt @@ -0,0 +1,4 @@ +fun foo() { + for (i in 1..9) + i.sout +} diff --git a/idea/testData/codeInsight/postfix/soutInLoop.kt.after b/idea/testData/codeInsight/postfix/soutInLoop.kt.after new file mode 100644 index 00000000000..a040dc10012 --- /dev/null +++ b/idea/testData/codeInsight/postfix/soutInLoop.kt.after @@ -0,0 +1,4 @@ +fun foo() { + for (i in 1..9) + println(i) +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/postfix/PostfixTemplateProviderTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/postfix/PostfixTemplateProviderTestGenerated.java index b7a109de023..eec2aead476 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/postfix/PostfixTemplateProviderTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/postfix/PostfixTemplateProviderTestGenerated.java @@ -137,12 +137,30 @@ public class PostfixTemplateProviderTestGenerated extends AbstractPostfixTemplat doTest(fileName); } + @TestMetadata("returnFromLoop.kt") + public void testReturnFromLoop() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/postfix/returnFromLoop.kt"); + doTest(fileName); + } + @TestMetadata("sout.kt") public void testSout() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/postfix/sout.kt"); doTest(fileName); } + @TestMetadata("soutInIf.kt") + public void testSoutInIf() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/postfix/soutInIf.kt"); + doTest(fileName); + } + + @TestMetadata("soutInLoop.kt") + public void testSoutInLoop() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/postfix/soutInLoop.kt"); + doTest(fileName); + } + @TestMetadata("try.kt") public void testTry() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/postfix/try.kt");