diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt index 8ab1047458a..6072352a7ca 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt @@ -21,15 +21,13 @@ import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.openapi.module.ModuleUtilCore -import com.intellij.psi.PsiComment -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiErrorElement -import com.intellij.psi.PsiWhiteSpace +import com.intellij.psi.* import com.intellij.psi.filters.* import com.intellij.psi.filters.position.LeftNeighbour import com.intellij.psi.filters.position.PositionElementFilter import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.TokenSet +import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget @@ -206,18 +204,35 @@ object KeywordCompletion { is KtBlockExpression -> { var prefixText = "fun foo() { " if (prevParent is KtExpression) { - // check that we are right after a try-expression without finally-block + // check that we are right after a try-expression without finally-block or after if-expression without else val prevLeaf = prevParent.prevLeaf { it !is PsiWhiteSpace && it !is PsiComment && it !is PsiErrorElement } - if (prevLeaf?.node?.elementType == KtTokens.RBRACE) { - val blockParent = (prevLeaf?.parent as? KtBlockExpression)?.parent - when (blockParent) { - is KtTryExpression -> prefixText += "try {}\n" - is KtCatchClause -> prefixText += "try {} catch (e: E) {}\n" - } - } + if (prevLeaf != null) { + val isAfterThen = prevLeaf.goUpWhileIsLastChild().any { it.node.elementType == KtNodeTypes.THEN } - if (prevLeaf?.getParentOfType(strict = false) != null) { - prefixText += "if(true){}\n" + var isAfterTry = false + var isAfterCatch = false + if (prevLeaf.node.elementType == KtTokens.RBRACE) { + val blockParent = (prevLeaf.parent as? KtBlockExpression)?.parent + when (blockParent) { + is KtTryExpression -> isAfterTry = true + is KtCatchClause -> { isAfterTry = true; isAfterCatch = true } + } + } + + if (isAfterThen) { + if (isAfterTry) { + prefixText += "if (a)\n" + } + else { + prefixText += "if (a) {}\n" + } + } + if (isAfterTry) { + prefixText += "try {}\n" + } + if (isAfterCatch) { + prefixText += "catch (e: E) {}\n" + } } return buildFilterWithContext(prefixText, prevParent, position) @@ -460,4 +475,15 @@ object KeywordCompletion { if (ancestor == this) return 0 return parent!!.getStartOffsetInAncestor(ancestor) + startOffsetInParent } + + private fun PsiElement.goUpWhileIsLastChild(): Sequence { + return generateSequence(this) { + if (it is PsiFile) + null + else if (it != it.parent.lastChild) + null + else + it.parent + } + } } diff --git a/idea/idea-completion/testData/keywords/AfterIf.kt b/idea/idea-completion/testData/keywords/AfterIf.kt index 8f17259a759..6d414f05a40 100644 --- a/idea/idea-completion/testData/keywords/AfterIf.kt +++ b/idea/idea-completion/testData/keywords/AfterIf.kt @@ -11,9 +11,7 @@ fun some() { // EXIST: do -// EXIST: as // EXIST: class -// EXIST: else // EXIST: false // EXIST: for // EXIST: fun diff --git a/idea/idea-completion/testData/keywords/Else1.kt b/idea/idea-completion/testData/keywords/Else1.kt new file mode 100644 index 00000000000..8def8e967b6 --- /dev/null +++ b/idea/idea-completion/testData/keywords/Else1.kt @@ -0,0 +1,29 @@ +fun foo(p: Int) { + if (p > 0) { + + } + +} + +// EXIST: else +// EXIST: class +// EXIST: do +// EXIST: false +// EXIST: for +// EXIST: fun +// EXIST: if +// EXIST: null +// EXIST: object +// EXIST: return +// EXIST: super +// EXIST: throw +// EXIST: interface +// EXIST: true +// EXIST: try +// EXIST: val +// EXIST: var +// EXIST: when +// EXIST: while +// EXIST: typealias +// EXIST: as +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/Else2.kt b/idea/idea-completion/testData/keywords/Else2.kt new file mode 100644 index 00000000000..a45321e0cd9 --- /dev/null +++ b/idea/idea-completion/testData/keywords/Else2.kt @@ -0,0 +1,28 @@ +fun foo(p: Int) { + if (p > 0) + foo() + +} + +// EXIST: else +// EXIST: class +// EXIST: do +// EXIST: false +// EXIST: for +// EXIST: fun +// EXIST: if +// EXIST: null +// EXIST: object +// EXIST: return +// EXIST: super +// EXIST: throw +// EXIST: interface +// EXIST: true +// EXIST: try +// EXIST: val +// EXIST: var +// EXIST: when +// EXIST: while +// EXIST: typealias +// EXIST: as +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/ElseAfterBlocklessIf.kt b/idea/idea-completion/testData/keywords/ElseAfterBlocklessIf.kt deleted file mode 100644 index f3dde8775b3..00000000000 --- a/idea/idea-completion/testData/keywords/ElseAfterBlocklessIf.kt +++ /dev/null @@ -1,8 +0,0 @@ -fun foo(p: Int) { - var x = 0 - if (p > 0) - x += p - el -} - -//EXIST: else \ No newline at end of file diff --git a/idea/idea-completion/testData/keywords/ElseOnOtherLine.kt b/idea/idea-completion/testData/keywords/ElseOnOtherLine.kt deleted file mode 100644 index 682fc0f505a..00000000000 --- a/idea/idea-completion/testData/keywords/ElseOnOtherLine.kt +++ /dev/null @@ -1,8 +0,0 @@ -fun foo(p: Int) { - if (p > 0) { - - } - el -} - -//EXIST: else \ No newline at end of file diff --git a/idea/idea-completion/testData/keywords/IfTry.kt b/idea/idea-completion/testData/keywords/IfTry.kt new file mode 100644 index 00000000000..b151448ec09 --- /dev/null +++ b/idea/idea-completion/testData/keywords/IfTry.kt @@ -0,0 +1,13 @@ +fun foo(p: Int) { + if (p > 0) + try { + } + +} + +// EXIST: catch +// EXIST: finally +// EXIST: false +// EXIST: null +// EXIST: true +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/IfTryCatch.kt b/idea/idea-completion/testData/keywords/IfTryCatch.kt new file mode 100644 index 00000000000..720a13208da --- /dev/null +++ b/idea/idea-completion/testData/keywords/IfTryCatch.kt @@ -0,0 +1,33 @@ +fun foo(p: Int) { + if (p > 0) + try { + } + catch (e: Exception) { + } + +} + +// EXIST: catch +// EXIST: finally +// EXIST: else +// EXIST: class +// EXIST: do +// EXIST: false +// EXIST: for +// EXIST: fun +// EXIST: if +// EXIST: null +// EXIST: object +// EXIST: return +// EXIST: super +// EXIST: throw +// EXIST: interface +// EXIST: true +// EXIST: try +// EXIST: val +// EXIST: var +// EXIST: when +// EXIST: while +// EXIST: typealias +// EXIST: as +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/InElse.kt b/idea/idea-completion/testData/keywords/InElse.kt index 2f3322e7473..ccfc027ab49 100644 --- a/idea/idea-completion/testData/keywords/InElse.kt +++ b/idea/idea-completion/testData/keywords/InElse.kt @@ -10,9 +10,7 @@ fun some() { // EXIST: do -// EXIST: as // EXIST: class -// EXIST: else // EXIST: false // EXIST: for // EXIST: fun diff --git a/idea/idea-completion/testData/keywords/InIf.kt b/idea/idea-completion/testData/keywords/InIf.kt index 6e496c67d19..801cdac65fc 100644 --- a/idea/idea-completion/testData/keywords/InIf.kt +++ b/idea/idea-completion/testData/keywords/InIf.kt @@ -10,9 +10,7 @@ fun some() { // EXIST: do -// EXIST: as // EXIST: class -// EXIST: else // EXIST: false // EXIST: for // EXIST: fun diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KeywordCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KeywordCompletionTestGenerated.java index f44d4bbf283..3ad7f7a1ae8 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KeywordCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KeywordCompletionTestGenerated.java @@ -150,15 +150,15 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes doTest(fileName); } - @TestMetadata("ElseAfterBlocklessIf.kt") - public void testElseAfterBlocklessIf() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ElseAfterBlocklessIf.kt"); + @TestMetadata("Else1.kt") + public void testElse1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/Else1.kt"); doTest(fileName); } - @TestMetadata("ElseOnOtherLine.kt") - public void testElseOnOtherLine() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ElseOnOtherLine.kt"); + @TestMetadata("Else2.kt") + public void testElse2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/Else2.kt"); doTest(fileName); } @@ -174,6 +174,18 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes doTest(fileName); } + @TestMetadata("IfTry.kt") + public void testIfTry() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/IfTry.kt"); + doTest(fileName); + } + + @TestMetadata("IfTryCatch.kt") + public void testIfTryCatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/IfTryCatch.kt"); + doTest(fileName); + } + @TestMetadata("InAnnotationClassScope.kt") public void testInAnnotationClassScope() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/InAnnotationClassScope.kt");