Implement 'Surround expression with if' surrounder

#KT-3363 Fixed
This commit is contained in:
Denis Zharkov
2016-05-24 16:34:17 +03:00
committed by Nikolay Krasko
parent f18b9cceb3
commit 09266b222b
13 changed files with 150 additions and 5 deletions
@@ -509,6 +509,8 @@ fun main(args: Array<String>) {
model("codeInsight/surroundWith/tryCatchFinally", testMethod = "doTestWithTryCatchFinallySurrounder")
model("codeInsight/surroundWith/tryFinally", testMethod = "doTestWithTryFinallySurrounder")
model("codeInsight/surroundWith/functionLiteral", testMethod = "doTestWithFunctionLiteralSurrounder")
model("codeInsight/surroundWith/withIfExpression", testMethod = "doTestWithSurroundWithIfExpression")
model("codeInsight/surroundWith/withIfElseExpression", testMethod = "doTestWithSurroundWithIfElseExpression")
}
testClass<AbstractJoinLinesTest>() {
@@ -31,7 +31,9 @@ public class KotlinExpressionSurroundDescriptor implements SurroundDescriptor {
new KotlinStringTemplateSurrounder(),
new KotlinParenthesesSurrounder(),
new KotlinWhenSurrounder() ,
new KotlinRuntimeTypeCastSurrounder()
new KotlinRuntimeTypeCastSurrounder(),
new KotlinWithIfExpressionSurrounder(/* withElse = */false),
new KotlinWithIfExpressionSurrounder(/* withElse = */true)
};
@Override
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.codeInsight.surroundWith.expression
import com.intellij.codeInsight.CodeInsightUtilBase
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.conversion.copy.range
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.typeUtil.isBoolean
import org.jetbrains.kotlin.utils.sure
class KotlinWithIfExpressionSurrounder(val withElse: Boolean) : KotlinExpressionSurrounder() {
override fun isApplicable(expression: KtExpression) =
expression.analyze(BodyResolveMode.PARTIAL).getType(expression)?.isBoolean() ?: false
override fun surroundExpression(project: Project, editor: Editor, expression: KtExpression): TextRange? {
val factory = KtPsiFactory(project)
val ifExpression =
expression.replace(
factory.createIf(
expression,
factory.createBlock("blockStubContentToBeRemovedLater"),
if (withElse) factory.createEmptyBody() else null
)
) as KtIfExpression
CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(ifExpression)
val firstStatementInThenRange = (ifExpression.then as? KtBlockExpression).sure {
"Then branch should exist and be a block expression"
}.statements.first().range
editor.document.deleteString(firstStatementInThenRange.startOffset, firstStatementInThenRange.endOffset)
return TextRange(firstStatementInThenRange.startOffset, firstStatementInThenRange.startOffset)
}
override fun getTemplateDescription() = "if (expr) { ... }" + (if (withElse) " else { ... }" else "")
}
@@ -0,0 +1,3 @@
fun foo(x: Boolean, y: Boolean) {
<selection>x || y && x</selection>
}
@@ -0,0 +1,6 @@
fun foo(x: Boolean, y: Boolean) {
if (x || y && x) {
<caret>
} else {
}
}
@@ -0,0 +1,3 @@
fun foo(x: Boolean) {
<caret>x
}
@@ -0,0 +1,6 @@
fun foo(x: Boolean) {
if (x) {
<caret>
} else {
}
}
@@ -0,0 +1,3 @@
fun foo(x: Boolean, y: Boolean) {
<selection>x || y && x</selection>
}
@@ -0,0 +1,5 @@
fun foo(x: Boolean, y: Boolean) {
if (x || y && x) {
<caret>
}
}
@@ -0,0 +1,3 @@
fun foo(x: Boolean) {
<caret>x
}
@@ -0,0 +1,5 @@
fun foo(x: Boolean) {
if (x) {
<caret>
}
}
@@ -26,10 +26,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.testFramework.LightCodeInsightTestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.codeInsight.surroundWith.expression.KotlinNotSurrounder;
import org.jetbrains.kotlin.idea.codeInsight.surroundWith.expression.KotlinParenthesesSurrounder;
import org.jetbrains.kotlin.idea.codeInsight.surroundWith.expression.KotlinStringTemplateSurrounder;
import org.jetbrains.kotlin.idea.codeInsight.surroundWith.expression.KotlinWhenSurrounder;
import org.jetbrains.kotlin.idea.codeInsight.surroundWith.expression.*;
import org.jetbrains.kotlin.idea.codeInsight.surroundWith.statement.*;
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
@@ -78,6 +75,14 @@ public abstract class AbstractSurroundWithTest extends LightCodeInsightTestCase
doTest(path, new KotlinFunctionLiteralSurrounder());
}
public void doTestWithSurroundWithIfExpression(String path) throws Exception {
doTest(path, new KotlinWithIfExpressionSurrounder(false));
}
public void doTestWithSurroundWithIfElseExpression(String path) throws Exception {
doTest(path, new KotlinWithIfExpressionSurrounder(true));
}
private void doTest(String path, Surrounder surrounder) throws Exception {
configureByFile(path);
@@ -613,4 +613,46 @@ public class SurroundWithTestGenerated extends AbstractSurroundWithTest {
doTestWithFunctionLiteralSurrounder(fileName);
}
}
@TestMetadata("idea/testData/codeInsight/surroundWith/withIfExpression")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class WithIfExpression extends AbstractSurroundWithTest {
public void testAllFilesPresentInWithIfExpression() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/codeInsight/surroundWith/withIfExpression"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("complexBoolean.kt")
public void testComplexBoolean() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/surroundWith/withIfExpression/complexBoolean.kt");
doTestWithSurroundWithIfExpression(fileName);
}
@TestMetadata("variable.kt")
public void testVariable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/surroundWith/withIfExpression/variable.kt");
doTestWithSurroundWithIfExpression(fileName);
}
}
@TestMetadata("idea/testData/codeInsight/surroundWith/withIfElseExpression")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class WithIfElseExpression extends AbstractSurroundWithTest {
public void testAllFilesPresentInWithIfElseExpression() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/codeInsight/surroundWith/withIfElseExpression"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("complexBoolean.kt")
public void testComplexBoolean() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/surroundWith/withIfElseExpression/complexBoolean.kt");
doTestWithSurroundWithIfElseExpression(fileName);
}
@TestMetadata("variable.kt")
public void testVariable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/surroundWith/withIfElseExpression/variable.kt");
doTestWithSurroundWithIfElseExpression(fileName);
}
}
}