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
This commit is contained in:
Denis Zharkov
2016-09-30 12:22:42 +03:00
parent 3c24996073
commit 0120085443
8 changed files with 53 additions and 3 deletions
@@ -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<PsiElement> {
+4
View File
@@ -0,0 +1,4 @@
fun foo() {
for (i in 1..9)
i.return<caret>
}
@@ -0,0 +1,4 @@
fun foo() {
for (i in 1..9)
return i
}
+4
View File
@@ -0,0 +1,4 @@
fun foo(x: Int, y: Int) {
if (x > y)
x.sout<caret>
}
+4
View File
@@ -0,0 +1,4 @@
fun foo(x: Int, y: Int) {
if (x > y)
println(x)
}
+4
View File
@@ -0,0 +1,4 @@
fun foo() {
for (i in 1..9)
i.sout<caret>
}
+4
View File
@@ -0,0 +1,4 @@
fun foo() {
for (i in 1..9)
println(i)
}
@@ -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");