diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUnparsingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUnparsingUtils.java index e3d86c3f0f0..1172d51f842 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUnparsingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUnparsingUtils.java @@ -16,7 +16,6 @@ package org.jetbrains.jet.lang.psi; -import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt index 60fe8c11e64..ad15ae7c2e2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt @@ -70,3 +70,6 @@ fun JetClassOrObject.effectiveDeclarations(): List = } fun JetClass.isAbstract() = isTrait() || hasModifier(JetTokens.ABSTRACT_KEYWORD) + +[suppress("UNCHECKED_CAST")] +fun PsiElement.replaced(newElement: T): T = replace(newElement)!! as T diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/IfWhenUtils.java b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/IfWhenUtils.java index aaeeb741fe1..b01d4678138 100644 --- a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/IfWhenUtils.java +++ b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/IfWhenUtils.java @@ -110,8 +110,8 @@ public class IfWhenUtils { } while (currIfExpression != null); JetWhenExpression whenExpression = builder.toExpression(ifExpression.getProject()); - if (WhenUtils.checkIntroduceWhenSubject(whenExpression)) { - whenExpression = WhenUtils.introduceWhenSubject(whenExpression); + if (BranchedTransformationsPackage.canIntroduceSubject(whenExpression)) { + whenExpression = BranchedTransformationsPackage.introduceSubject(whenExpression); } ifExpression.replace(whenExpression); @@ -126,7 +126,7 @@ public class IfWhenUtils { StringBuilder sb = new StringBuilder(); - String text = WhenUtils.whenConditionToExpressionText(condition, subject); + String text = BranchedTransformationsPackage.toExpressionText(condition, subject); if (n > 1) { text = parenthesizeTextIfNeeded(text); } @@ -136,7 +136,7 @@ public class IfWhenUtils { JetWhenCondition currCondition = conditions[i]; assert currCondition != null : TRANSFORM_WITHOUT_CHECK; - sb.append(" || ").append(parenthesizeTextIfNeeded(WhenUtils.whenConditionToExpressionText(currCondition, subject))); + sb.append(" || ").append(parenthesizeTextIfNeeded(BranchedTransformationsPackage.toExpressionText(currCondition, subject))); } return sb.toString(); diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/WhenUtils.java b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/WhenUtils.java deleted file mode 100644 index 08ddc198924..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/WhenUtils.java +++ /dev/null @@ -1,233 +0,0 @@ -package org.jetbrains.jet.plugin.intentions.branchedTransformations; - -import com.intellij.psi.tree.IElementType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lexer.JetTokens; -import org.jetbrains.jet.plugin.util.JetPsiMatcher; - -import static org.jetbrains.jet.lang.psi.JetPsiUnparsingUtils.*; - -import java.util.List; - -public class WhenUtils { - private WhenUtils() { - } - - public static final String TRANSFORM_WITHOUT_CHECK = - "Expression must be checked before applying transformation"; - - private static void assertNotNull(Object expression) { - assert expression != null : TRANSFORM_WITHOUT_CHECK; - } - - private static JetExpression getWhenConditionSubjectCandidate(JetExpression condition) { - if (condition instanceof JetIsExpression) { - return ((JetIsExpression) condition).getLeftHandSide(); - } - - if (condition instanceof JetBinaryExpression) { - JetBinaryExpression binaryExpression = (JetBinaryExpression) condition; - JetExpression lhs = binaryExpression.getLeft(); - - IElementType op = binaryExpression.getOperationToken(); - if (op == JetTokens.IN_KEYWORD || op == JetTokens.NOT_IN) { - return lhs; - } - if (op == JetTokens.EQEQ) { - return lhs instanceof JetSimpleNameExpression ? lhs : binaryExpression.getRight(); - } - } - - return null; - } - - private static JetExpression getWhenSubjectCandidate(@NotNull JetWhenExpression whenExpression) { - if (whenExpression.getSubjectExpression() != null) return null; - - JetExpression lastCandidate = null; - for (JetWhenEntry entry : whenExpression.getEntries()) { - JetWhenCondition[] conditions = entry.getConditions(); - - if (!entry.isElse() && conditions.length == 0) return null; - - for (JetWhenCondition condition : conditions) { - if (!(condition instanceof JetWhenConditionWithExpression)) return null; - - JetExpression currCandidate = getWhenConditionSubjectCandidate(((JetWhenConditionWithExpression) condition).getExpression()); - - if (!(currCandidate instanceof JetSimpleNameExpression)) return null; - - if (lastCandidate == null) { - lastCandidate = currCandidate; - } - else if (!JetPsiMatcher.checkElementMatch(lastCandidate, currCandidate)) return null; - } - } - - return lastCandidate; - } - - public static boolean checkFlattenWhen(@NotNull JetWhenExpression whenExpression) { - JetExpression subject = whenExpression.getSubjectExpression(); - - if (subject != null && !(subject instanceof JetSimpleNameExpression)) return false; - - if (!JetPsiUtil.checkWhenExpressionHasSingleElse(whenExpression)) return false; - - JetExpression elseBranch = whenExpression.getElseExpression(); - if (!(elseBranch instanceof JetWhenExpression)) return false; - - JetWhenExpression nestedWhenExpression = (JetWhenExpression) elseBranch; - - return JetPsiUtil.checkWhenExpressionHasSingleElse(nestedWhenExpression) && - JetPsiMatcher.checkElementMatch(subject, nestedWhenExpression.getSubjectExpression()); - } - - public static boolean checkIntroduceWhenSubject(@NotNull JetWhenExpression whenExpression) { - return getWhenSubjectCandidate(whenExpression) != null; - } - - public static boolean checkEliminateWhenSubject(@NotNull JetWhenExpression whenExpression) { - return whenExpression.getSubjectExpression() instanceof JetSimpleNameExpression; - } - - @NotNull - public static JetWhenExpression flattenWhen(@NotNull JetWhenExpression whenExpression) { - JetExpression subjectExpression = whenExpression.getSubjectExpression(); - - JetExpression elseBranch = whenExpression.getElseExpression(); - assert elseBranch instanceof JetWhenExpression : TRANSFORM_WITHOUT_CHECK; - - JetWhenExpression nestedWhenExpression = (JetWhenExpression) elseBranch; - - List outerEntries = whenExpression.getEntries(); - List innerEntries = nestedWhenExpression.getEntries(); - - JetPsiFactory.WhenBuilder builder = new JetPsiFactory.WhenBuilder(subjectExpression); - - for (JetWhenEntry entry : outerEntries) { - if (entry.isElse()) continue; - - builder.entry(entry); - } - - for (JetWhenEntry entry : innerEntries) { - builder.entry(entry); - } - - JetWhenExpression newWhenExpression = builder.toExpression(whenExpression.getProject()); - whenExpression.replace(newWhenExpression); - - return newWhenExpression; - } - - @NotNull - public static JetWhenExpression introduceWhenSubject(@NotNull JetWhenExpression whenExpression) { - JetExpression subject = getWhenSubjectCandidate(whenExpression); - assertNotNull(subject); - - JetPsiFactory.WhenBuilder builder = new JetPsiFactory.WhenBuilder(subject); - - for (JetWhenEntry entry : whenExpression.getEntries()) { - JetExpression branchExpression = entry.getExpression(); - - if (entry.isElse()) { - builder.elseEntry(branchExpression); - continue; - } - - for (JetWhenCondition condition : entry.getConditions()) { - assert condition instanceof JetWhenConditionWithExpression : TRANSFORM_WITHOUT_CHECK; - - JetExpression conditionExpression = ((JetWhenConditionWithExpression) condition).getExpression(); - - if (conditionExpression instanceof JetIsExpression) { - JetIsExpression isExpression = (JetIsExpression) conditionExpression; - builder.pattern(isExpression.getTypeRef(), isExpression.isNegated()); - } - else if (conditionExpression instanceof JetBinaryExpression) { - JetBinaryExpression binaryExpression = (JetBinaryExpression) conditionExpression; - - JetExpression lhs = binaryExpression.getLeft(); - JetExpression rhs = binaryExpression.getRight(); - - IElementType op = binaryExpression.getOperationToken(); - if (op == JetTokens.IN_KEYWORD) { - builder.range(rhs, false); - } - else if (op == JetTokens.NOT_IN) { - builder.range(rhs, true); - } - else if (op == JetTokens.EQEQ) { - if (JetPsiMatcher.checkElementMatch(subject, lhs)) { - builder.condition(rhs); - } else { - builder.condition(lhs); - } - } - else assert false : TRANSFORM_WITHOUT_CHECK; - } - else assert false : TRANSFORM_WITHOUT_CHECK; - } - - builder.branchExpression(branchExpression); - } - - JetWhenExpression newWhenExpression = builder.toExpression(whenExpression.getProject()); - whenExpression.replace(newWhenExpression); - - return newWhenExpression; - } - - @NotNull - static String whenConditionToExpressionText(@NotNull JetWhenCondition condition, JetExpression subject) { - if (condition instanceof JetWhenConditionIsPattern) { - JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition; - return toBinaryExpression(subject, (patternCondition.isNegated() ? "!is" : "is"), patternCondition.getTypeRef()); - } - - if (condition instanceof JetWhenConditionInRange) { - JetWhenConditionInRange rangeCondition = (JetWhenConditionInRange) condition; - return toBinaryExpression(subject, rangeCondition.getOperationReference().getText(), rangeCondition.getRangeExpression()); - } - - assert condition instanceof JetWhenConditionWithExpression : TRANSFORM_WITHOUT_CHECK; - - JetExpression conditionExpression = ((JetWhenConditionWithExpression) condition).getExpression(); - - if (subject != null) { - return toBinaryExpression(parenthesizeIfNeeded(subject), "==", parenthesizeIfNeeded(conditionExpression)); - } - return JetPsiUtil.getText(conditionExpression); - } - - @NotNull - public static JetWhenExpression eliminateWhenSubject(@NotNull JetWhenExpression whenExpression) { - JetExpression subject = whenExpression.getSubjectExpression(); - assertNotNull(subject); - - JetPsiFactory.WhenBuilder builder = new JetPsiFactory.WhenBuilder(); - - for (JetWhenEntry entry : whenExpression.getEntries()) { - JetExpression branchExpression = entry.getExpression(); - - if (entry.isElse()) { - builder.elseEntry(branchExpression); - - continue; - } - - for (JetWhenCondition condition : entry.getConditions()) { - builder.condition(whenConditionToExpressionText(condition, subject)); - } - - builder.branchExpression(branchExpression); - } - - JetWhenExpression newWhenExpression = builder.toExpression(whenExpression.getProject()); - whenExpression.replace(newWhenExpression); - - return newWhenExpression; - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/WhenUtils.kt b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/WhenUtils.kt new file mode 100644 index 00000000000..5a27f66d8b2 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/WhenUtils.kt @@ -0,0 +1,218 @@ +/* + * 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.intentions.branchedTransformations + +import com.intellij.psi.tree.IElementType +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lexer.JetTokens +import org.jetbrains.jet.plugin.util.JetPsiMatcher +import org.jetbrains.jet.lang.psi.JetPsiUnparsingUtils.* +import org.jetbrains.jet.lang.psi.psiUtil.* + +public val TRANSFORM_WITHOUT_CHECK: String = "Expression must be checked before applying transformation" + +fun JetWhenCondition.toExpressionText(subject: JetExpression?): String { + return when (this) { + is JetWhenConditionIsPattern -> { + val op = if (isNegated()) "!is" else "is" + toBinaryExpression(subject, op, getTypeRef()) + } + is JetWhenConditionInRange -> { + toBinaryExpression(subject, getOperationReference()!!.getText()!!, getRangeExpression()) + } + is JetWhenConditionWithExpression -> { + val conditionExpression = getExpression() + if (subject != null) { + toBinaryExpression(parenthesizeIfNeeded(subject), "==", parenthesizeIfNeeded(conditionExpression)) + } + else { + JetPsiUtil.getText(this) + } + } + else -> { + assert(this is JetWhenConditionWithExpression, TRANSFORM_WITHOUT_CHECK) + + val conditionExpression = (this as JetWhenConditionWithExpression).getExpression() + if (subject != null) { + toBinaryExpression(parenthesizeIfNeeded(subject), "==", parenthesizeIfNeeded(conditionExpression)) + } + else { + JetPsiUtil.getText(this) + } + } + } +} + +public fun JetWhenExpression.canFlatten(): Boolean { + val subject = getSubjectExpression() + if (subject != null && subject !is JetSimpleNameExpression) return false + + if (!JetPsiUtil.checkWhenExpressionHasSingleElse(this)) return false + + val elseBranch = getElseExpression() + if (elseBranch !is JetWhenExpression) return false + + return JetPsiUtil.checkWhenExpressionHasSingleElse(elseBranch) && + JetPsiMatcher.checkElementMatch(subject, elseBranch.getSubjectExpression()) +} + +fun JetWhenExpression.getSubjectCandidate(): JetExpression? { + fun JetExpression?.getWhenConditionSubjectCandidate(): JetExpression? { + return when(this) { + is JetIsExpression -> getLeftHandSide() + is JetBinaryExpression -> { + val lhs = getLeft() + val op = getOperationToken() + when (op) { + JetTokens.IN_KEYWORD, JetTokens.NOT_IN -> lhs + JetTokens.EQEQ -> { + if (lhs is JetSimpleNameExpression) + lhs + else + getRight() + } + else -> null + } + + } + else -> null + } + } + + if (getSubjectExpression() != null) return null + + var lastCandidate: JetExpression? = null + for (entry in getEntries()) { + val conditions = entry.getConditions() + if (!entry.isElse() && conditions.size == 0) return null + + for (condition in conditions) { + if (condition !is JetWhenConditionWithExpression) return null + + val currCandidate = condition.getExpression().getWhenConditionSubjectCandidate() + if (currCandidate !is JetSimpleNameExpression) return null + + if (lastCandidate == null) { + lastCandidate = currCandidate + } + else if (!JetPsiMatcher.checkElementMatch(lastCandidate, currCandidate)) return null + + } + } + + return lastCandidate +} + +public fun JetWhenExpression.canIntroduceSubject(): Boolean { + return getSubjectCandidate() != null +} + +public fun JetWhenExpression.canEliminateSubject(): Boolean { + return getSubjectExpression() is JetSimpleNameExpression +} + +public fun JetWhenExpression.flatten(): JetWhenExpression { + val subjectExpression = getSubjectExpression() + val elseBranch = getElseExpression() + + assert(elseBranch is JetWhenExpression, TRANSFORM_WITHOUT_CHECK) + + val nestedWhenExpression = (elseBranch as JetWhenExpression) + + val outerEntries = getEntries() + val innerEntries = nestedWhenExpression.getEntries() + val builder = JetPsiFactory.WhenBuilder(subjectExpression) + for (entry in outerEntries) { + if (entry.isElse()) + continue + + builder.entry(entry) + } + for (entry in innerEntries) { + builder.entry(entry) + } + + return replaced(builder.toExpression(getProject())) +} + +public fun JetWhenExpression.introduceSubject(): JetWhenExpression { + val subject = getSubjectCandidate()!! + + val builder = JetPsiFactory.WhenBuilder(subject) + for (entry in getEntries()) { + val branchExpression = entry.getExpression() + if (entry.isElse()) { + builder.elseEntry(branchExpression) + continue + } + + for (condition in entry.getConditions()) { + assert(condition is JetWhenConditionWithExpression, TRANSFORM_WITHOUT_CHECK) + + val conditionExpression = ((condition as JetWhenConditionWithExpression)).getExpression() + when (conditionExpression) { + is JetIsExpression -> { + builder.pattern(conditionExpression.getTypeRef(), conditionExpression.isNegated()) + } + is JetBinaryExpression -> { + val lhs = conditionExpression.getLeft() + val rhs = conditionExpression.getRight() + val op = conditionExpression.getOperationToken() + when (op) { + JetTokens.IN_KEYWORD -> builder.range(rhs, false) + JetTokens.NOT_IN -> builder.range(rhs, true) + JetTokens.EQEQ -> { + if (JetPsiMatcher.checkElementMatch(subject, lhs)) { + builder.condition(rhs) + } + else { + builder.condition(lhs) + } + } + else -> assert(false, TRANSFORM_WITHOUT_CHECK) + } + } + else -> assert(false, TRANSFORM_WITHOUT_CHECK) + } + + } + builder.branchExpression(branchExpression) + } + + return replaced(builder.toExpression(getProject())) +} + +public fun JetWhenExpression.eliminateSubject(): JetWhenExpression { + val subject = getSubjectExpression()!! + + val builder = JetPsiFactory.WhenBuilder() + for (entry in getEntries()) { + val branchExpression = entry.getExpression() + + if (entry.isElse()) { + builder.elseEntry(branchExpression) + continue + } + for (condition in entry.getConditions()) { + builder.condition(condition.toExpressionText(subject)) + } + + builder.branchExpression(branchExpression) + } + + return replaced(builder.toExpression(getProject())) +} diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/EliminateWhenSubjectIntention.kt b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/EliminateWhenSubjectIntention.kt index c13b375076a..16b735aefa0 100644 --- a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/EliminateWhenSubjectIntention.kt +++ b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/EliminateWhenSubjectIntention.kt @@ -17,14 +17,14 @@ package org.jetbrains.jet.plugin.intentions.branchedTransformations.intentions import org.jetbrains.jet.plugin.intentions.JetSelfTargetingIntention -import org.jetbrains.jet.plugin.intentions.branchedTransformations.WhenUtils +import org.jetbrains.jet.plugin.intentions.branchedTransformations.* import org.jetbrains.jet.lang.psi.JetWhenExpression import com.intellij.openapi.editor.Editor public class EliminateWhenSubjectIntention : JetSelfTargetingIntention("eliminate.when.subject", javaClass()) { - override fun isApplicableTo(element: JetWhenExpression): Boolean = WhenUtils.checkEliminateWhenSubject(element) + override fun isApplicableTo(element: JetWhenExpression): Boolean = element.canEliminateSubject() override fun applyTo(element: JetWhenExpression, editor: Editor) { - WhenUtils.eliminateWhenSubject(element) + element.eliminateSubject() } } diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/FlattenWhenIntention.kt b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/FlattenWhenIntention.kt index 19f0c34fcf2..e64974e67db 100644 --- a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/FlattenWhenIntention.kt +++ b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/FlattenWhenIntention.kt @@ -17,14 +17,14 @@ package org.jetbrains.jet.plugin.intentions.branchedTransformations.intentions import org.jetbrains.jet.plugin.intentions.JetSelfTargetingIntention -import org.jetbrains.jet.plugin.intentions.branchedTransformations.WhenUtils +import org.jetbrains.jet.plugin.intentions.branchedTransformations.* import org.jetbrains.jet.lang.psi.JetWhenExpression import com.intellij.openapi.editor.Editor public class FlattenWhenIntention : JetSelfTargetingIntention("flatten.when", javaClass()) { - override fun isApplicableTo(element: JetWhenExpression): Boolean = WhenUtils.checkFlattenWhen(element) + override fun isApplicableTo(element: JetWhenExpression): Boolean = element.canFlatten() override fun applyTo(element: JetWhenExpression, editor: Editor) { - WhenUtils.flattenWhen(element) + element.flatten() } } diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/IntroduceWhenSubjectIntention.kt b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/IntroduceWhenSubjectIntention.kt index 77796818029..552d6696273 100644 --- a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/IntroduceWhenSubjectIntention.kt +++ b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/IntroduceWhenSubjectIntention.kt @@ -17,14 +17,14 @@ package org.jetbrains.jet.plugin.intentions.branchedTransformations.intentions import org.jetbrains.jet.plugin.intentions.JetSelfTargetingIntention -import org.jetbrains.jet.plugin.intentions.branchedTransformations.WhenUtils +import org.jetbrains.jet.plugin.intentions.branchedTransformations.* import org.jetbrains.jet.lang.psi.JetWhenExpression import com.intellij.openapi.editor.Editor public class IntroduceWhenSubjectIntention : JetSelfTargetingIntention("introduce.when.subject", javaClass()) { - override fun isApplicableTo(element: JetWhenExpression): Boolean = WhenUtils.checkIntroduceWhenSubject(element) + override fun isApplicableTo(element: JetWhenExpression): Boolean = element.canIntroduceSubject() override fun applyTo(element: JetWhenExpression, editor: Editor) { - WhenUtils.introduceWhenSubject(element) + element.introduceSubject() } }