Implement if-to-when and when-to-if transformations

This commit is contained in:
Alexey Sedunov
2013-04-26 14:10:00 +04:00
parent c054c0cdbe
commit 3c691062ad
9 changed files with 340 additions and 0 deletions
@@ -0,0 +1,11 @@
when (n) {
1 -> {
res = "one"
}
2 -> {
res = "two"
}
else -> {
res = "???"
}
}
@@ -0,0 +1,7 @@
if (n == 1) {
res = "one"
} else if (n == 2) {
res = "two"
} else {
res = "???"
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts 'if' expression to equivalent 'when' expression
</body>
</html>
@@ -0,0 +1,7 @@
if (n == 1) {
res = "one"
} else if (n == 2) {
res = "two"
} else {
res = "???"
}
@@ -0,0 +1,11 @@
when (n) {
1 -> {
res = "one"
}
2 -> {
res = "two"
}
else -> {
res = "???"
}
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts 'when' expression to one or more 'if' expressions
</body>
</html>
@@ -0,0 +1,206 @@
package org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.ArrayList;
import java.util.List;
public class IfWhenUtils {
public static final String TRANSFORM_WITHOUT_CHECK =
"Expression must be checked before applying transformation";
private IfWhenUtils() {
}
public static boolean checkIfToWhen(@NotNull JetIfExpression ifExpression) {
return ifExpression.getCondition() != null && ifExpression.getThen() != null && ifExpression.getElse() != null;
}
public static boolean checkWhenToIf(@NotNull JetWhenExpression whenExpression) {
return !whenExpression.getEntries().isEmpty() && JetPsiUtil.checkWhenExpressionHasSingleElse(whenExpression);
}
private static void assertNotNull(JetExpression expression) {
assert expression != null : TRANSFORM_WITHOUT_CHECK;
}
private static List<JetExpression> splitExpressionToOrBranches(JetExpression expression) {
final List<JetExpression> branches = new ArrayList<JetExpression>();
expression.accept(
new JetVisitorVoid() {
@Override
public void visitBinaryExpression(JetBinaryExpression expression) {
if (expression.getOperationToken() == JetTokens.OROR) {
JetExpression left = expression.getLeft();
JetExpression right = expression.getRight();
if (left != null) {
left.accept(this);
}
if (right != null) {
right.accept(this);
}
} else {
visitExpression(expression);
}
}
@Override
public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
JetExpression baseExpression = expression.getExpression();
if (baseExpression != null) {
baseExpression.accept(this);
}
}
@Override
public void visitExpression(JetExpression expression) {
branches.add(expression);
}
}
);
return branches;
}
public static void transformIfToWhen(@NotNull JetIfExpression ifExpression) {
List<MultiGuardedExpression> positiveBranches = new ArrayList<MultiGuardedExpression>();
JetExpression elseExpression = null;
JetIfExpression currIfExpression = ifExpression;
do {
JetExpression condition = currIfExpression.getCondition();
JetExpression thenBranch = currIfExpression.getThen();
JetExpression elseBranch = currIfExpression.getElse();
assertNotNull(condition);
assertNotNull(thenBranch);
assertNotNull(elseBranch);
//noinspection ConstantConditions
positiveBranches.add(new MultiGuardedExpression(splitExpressionToOrBranches(condition), thenBranch));
if (elseBranch instanceof JetIfExpression) {
currIfExpression = (JetIfExpression) elseBranch;
}
else {
currIfExpression = null;
elseExpression = elseBranch;
}
} while (currIfExpression != null);
JetPsiFactory.WhenTemplateBuilder builder = new JetPsiFactory.WhenTemplateBuilder(false);
for (MultiGuardedExpression positiveBranch : positiveBranches) {
builder.addBranchWithMultiCondition(positiveBranch.getConditions().size());
}
JetWhenExpression whenExpression = builder.toExpression(ifExpression.getProject());
int i = 0;
List<JetWhenEntry> entries = whenExpression.getEntries();
for (JetWhenEntry entry : entries) {
if (entry.isElse()) {
//noinspection ConstantConditions
entry.getExpression().replace(elseExpression);
break;
}
MultiGuardedExpression branch = positiveBranches.get(i++);
//noinspection ConstantConditions
entry.getExpression().replace(branch.getBaseExpression());
int j = 0;
JetWhenCondition[] conditions = entry.getConditions();
for (JetWhenCondition condition : conditions) {
assert condition instanceof JetWhenConditionWithExpression : TRANSFORM_WITHOUT_CHECK;
JetExpression conditionExpression = ((JetWhenConditionWithExpression) condition).getExpression();
assertNotNull(conditionExpression);
//noinspection ConstantConditions
conditionExpression.replace(branch.getConditions().get(j++));
}
}
ifExpression.replace(whenExpression);
}
@SuppressWarnings("ConstantConditions")
private static JetExpression combineWhenConditions(Project project, JetWhenCondition[] conditions, JetExpression subject) {
int n = conditions.length;
assert n > 0 : TRANSFORM_WITHOUT_CHECK;
JetWhenCondition condition = conditions[n - 1];
assert condition != null : TRANSFORM_WITHOUT_CHECK;
JetExpression resultExpr = WhenUtils.whenConditionToExpression(condition, subject);
if (n > 1) {
resultExpr = JetPsiFactory.createParenthesizedExpressionIfNeeded(project, resultExpr);
}
for (int i = n - 2; i >= 0; i--) {
JetWhenCondition currCondition = conditions[i];
assert currCondition != null : TRANSFORM_WITHOUT_CHECK;
resultExpr = JetPsiFactory.createBinaryExpression(
project,
JetPsiFactory.createParenthesizedExpressionIfNeeded(project, WhenUtils.whenConditionToExpression(currCondition, subject)),
"||",
resultExpr);
}
return resultExpr;
}
public static void transformWhenToIf(@NotNull JetWhenExpression whenExpression) {
Project project = whenExpression.getProject();
JetExpression elseExpression = null;
List<GuardedExpression> positiveBranches = new ArrayList<GuardedExpression>();
List<JetWhenEntry> entries = whenExpression.getEntries();
for (JetWhenEntry entry : entries) {
JetExpression branch = entry.getExpression();
assertNotNull(branch);
if (entry.isElse()) {
elseExpression = branch;
} else {
JetExpression branchCondition = combineWhenConditions(project, entry.getConditions(), whenExpression.getSubjectExpression());
JetExpression branchExpression = entry.getExpression();
assertNotNull(branchExpression);
//noinspection ConstantConditions
positiveBranches.add(new GuardedExpression(branchCondition, branchExpression));
}
}
assertNotNull(elseExpression);
assert !positiveBranches.isEmpty() : TRANSFORM_WITHOUT_CHECK;
JetExpression outerExpression = elseExpression;
for (int i = positiveBranches.size() - 1; i >= 0; i--) {
GuardedExpression branch = positiveBranches.get(i);
outerExpression = JetPsiFactory.createIf(
project,
branch.getCondition(), branch.getBaseExpression(), outerExpression,
!(branch.getBaseExpression() instanceof JetBlockExpression), !(outerExpression instanceof JetBlockExpression));
}
//noinspection ConstantConditions
whenExpression.replace(outerExpression);
}
}
@@ -0,0 +1,36 @@
package org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions;
import com.google.common.base.Predicate;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetIfExpression;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.AbstractCodeTransformationIntention;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.IfWhenUtils;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.core.Transformer;
public class IfToWhenIntention extends AbstractCodeTransformationIntention<Transformer> {
private static final Transformer TRANSFORMER = new Transformer() {
@NotNull
@Override
public String getKey() {
return "if.to.when";
}
@Override
public void transform(@NotNull PsiElement element) {
IfWhenUtils.transformIfToWhen((JetIfExpression) element);
}
};
private static final Predicate<PsiElement> IS_APPLICABLE = new Predicate<PsiElement>() {
@Override
public boolean apply(@Nullable PsiElement input) {
return (input instanceof JetIfExpression) && IfWhenUtils.checkIfToWhen((JetIfExpression) input);
}
};
public IfToWhenIntention() {
super(TRANSFORMER, IS_APPLICABLE);
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2013 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.jet.plugin.codeInsight.codeTransformations.branchedTransformations.intentions;
import com.google.common.base.Predicate;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetWhenExpression;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.AbstractCodeTransformationIntention;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.IfWhenUtils;
import org.jetbrains.jet.plugin.codeInsight.codeTransformations.branchedTransformations.core.Transformer;
public class WhenToIfIntention extends AbstractCodeTransformationIntention<Transformer> {
private static final Transformer TRANSFORMER = new Transformer() {
@NotNull
@Override
public String getKey() {
return "when.to.if";
}
@Override
public void transform(@NotNull PsiElement element) {
IfWhenUtils.transformWhenToIf((JetWhenExpression) element);
}
};
private static final Predicate<PsiElement> IS_APPLICABLE = new Predicate<PsiElement>() {
@Override
public boolean apply(@Nullable PsiElement input) {
return (input instanceof JetWhenExpression) && IfWhenUtils.checkWhenToIf((JetWhenExpression) input);
}
};
public WhenToIfIntention() {
super(TRANSFORMER, IS_APPLICABLE);
}
}