From 1268684ced3b85e516eed050293d6a7536d01011 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 14 Apr 2015 17:59:52 +0300 Subject: [PATCH] Smaller availability range for RemoveBracesIntention + refactored it and AddBracesIntention --- .../kotlin/idea/JetBundle.properties | 4 -- .../idea/intentions/AddBracesIntention.kt | 64 ++++++++++--------- .../idea/intentions/RemoveBracesIntention.kt | 55 ++++++++-------- .../jetbrains/kotlin/idea/intentions/Utils.kt | 62 ++++++------------ idea/testData/intentions/removeBraces/else.kt | 2 +- idea/testData/intentions/removeBraces/for.kt | 2 +- .../removeBraces/forWithLocalVariable.kt | 2 +- .../forWithLocalVariable.kt.after | 2 +- idea/testData/intentions/removeBraces/if.kt | 4 +- .../intentions/removeBraces/ifWithComment.kt | 2 +- .../removeBraces/ifWithNoStatement.kt | 2 +- .../removeBraces/ifWithSemicolon.kt | 4 +- .../removeBraces/ifWithTwoStatements.kt | 2 +- .../removeBraces/whileWithTwoStatements.kt | 2 +- 14 files changed, 92 insertions(+), 117 deletions(-) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties index b547b99140a..15750755521 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties @@ -315,10 +315,6 @@ move.lambda.outside.parentheses=Move lambda expression out of parentheses move.lambda.outside.parentheses.family=Move Lambda Expression out of Parentheses replace.it.with.explicit.function.literal.param=Replace 'it' with explicit parameter replace.it.with.explicit.function.literal.param.family=Replace 'it' with Explicit Parameter -remove.braces=Remove braces -remove.braces.family=Remove Braces -add.braces=Add braces -add.braces.family=Add Braces convert.negated.boolean.sequence=Replace negated sequence with DeMorgan equivalent convert.negated.boolean.sequence.family=Replace Negated Sequence with DeMorgan Equivalent convert.negated.expression.with.demorgans.law=DeMorgan Law diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/AddBracesIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/AddBracesIntention.kt index 7761b68b2cf..a4f29e15ecd 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/AddBracesIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/AddBracesIntention.kt @@ -16,49 +16,53 @@ package org.jetbrains.kotlin.idea.intentions -import org.jetbrains.kotlin.psi.JetExpressionImpl -import org.jetbrains.kotlin.psi.JetPsiFactory import com.intellij.openapi.editor.Editor -import com.intellij.lang.ASTNode -import org.jetbrains.kotlin.JetNodeTypes import com.intellij.psi.PsiWhiteSpace +import org.jetbrains.kotlin.psi.* -public class AddBracesIntention : JetSelfTargetingIntention("add.braces", javaClass()) { - override fun isApplicableTo(element: JetExpressionImpl, caretOffset: Int): Boolean { - val expressionKind = element.getExpressionKind(caretOffset) ?: return false +public class AddBracesIntention : JetSelfTargetingIntention(javaClass(), "Add braces") { + override fun isApplicableTo(element: JetExpression, caretOffset: Int): Boolean { + val expression = element.getTargetExpression(caretOffset) ?: return false + if (expression is JetBlockExpression) return false - if (element.findBlockInExpression(expressionKind) != null) return false - - setText("Add braces to '${expressionKind.text}' statement") + val description = (expression.getParent() as JetContainerNode).description() + setText("Add braces to '$description' statement") return true } - override fun applyTo(element: JetExpressionImpl, editor: Editor) { - val expressionKind = element.getExpressionKind(editor.getCaretModel().getOffset())!! - val bodyNode = when (expressionKind) { - ExpressionKind.ELSE -> element.getNode().findChildByType(JetNodeTypes.ELSE) - ExpressionKind.IF -> element.getNode().findChildByType(JetNodeTypes.THEN) - else -> element.getNode().findChildByType(JetNodeTypes.BODY) - } - generateCleanOutput(element, bodyNode, expressionKind) - } + override fun applyTo(element: JetExpression, editor: Editor) { + val expression = element.getTargetExpression(editor.getCaretModel().getOffset())!! - fun generateCleanOutput(element: JetExpressionImpl, bodyNode: ASTNode?, expressionKind: ExpressionKind) { if (element.getNextSibling()?.getText() == ";") { element.getNextSibling()!!.delete() } - val psiFactory = JetPsiFactory(element) - val newElement = bodyNode!!.getPsi()!!.replace(psiFactory.createFunctionBody(bodyNode.getText())) - //handles the case of the block statement being on a new line - if (newElement.getPrevSibling() is PsiWhiteSpace) { - newElement.getPrevSibling()!!.replace(psiFactory.createWhiteSpace()) - } else { - //handles the case of no space between condition and statement - newElement.addBefore(psiFactory.createWhiteSpace(), newElement.getFirstChild()) + val psiFactory = JetPsiFactory(element) + expression.replace(psiFactory.createFunctionBody(expression.getText())) + + if (element is JetDoWhileExpression) { // remove new line between '}' and while + (element.getBody()!!.getParent().getNextSibling() as? PsiWhiteSpace)?.delete() } - if (expressionKind == ExpressionKind.DOWHILE) { - newElement.getNextSibling()?.delete() + } + + private fun JetExpression.getTargetExpression(caretLocation: Int): JetExpression? { + when (this) { + is JetIfExpression -> { + val thenExpr = getThen() ?: return null + val elseExpr = getElse() + if (elseExpr != null && caretLocation >= getElseKeyword()!!.getTextRange().getStartOffset()) { + return elseExpr + } + return thenExpr + } + + is JetWhileExpression -> return getBody() + + is JetDoWhileExpression -> return getBody() + + is JetForExpression -> return getBody() + + else -> return null } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveBracesIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveBracesIntention.kt index 38db8edf2f8..00a2c383bcc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveBracesIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveBracesIntention.kt @@ -16,53 +16,52 @@ package org.jetbrains.kotlin.idea.intentions -import org.jetbrains.kotlin.psi.JetBlockExpression -import org.jetbrains.kotlin.psi.JetPsiFactory -import org.jetbrains.kotlin.psi.JetExpressionImpl import com.intellij.openapi.editor.Editor -import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.PsiComment +import com.intellij.psi.PsiWhiteSpace +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType -public class RemoveBracesIntention : JetSelfTargetingIntention("remove.braces", javaClass()) { - override fun isApplicableTo(element: JetExpressionImpl, caretOffset: Int): Boolean { - val expressionKind = element.getExpressionKind(caretOffset) ?: return false +public class RemoveBracesIntention : JetSelfTargetingIntention(javaClass(), "Remove braces") { + override fun isApplicableTo(element: JetBlockExpression, caretOffset: Int): Boolean { + if (element.getStatements().size() != 1) return false - val jetBlockElement = element.findBlockInExpression(expressionKind) ?: return false + val containerNode = element.getParent() as? JetContainerNode ?: return false - if (jetBlockElement.getStatements().size == 1) { - setText("Remove braces from '${expressionKind.text}' statement") - return true - } - return false + val lBrace = element.getLBrace() ?: return false + val rBrace = element.getRBrace() ?: return false + if (!lBrace.getTextRange().containsOffset(caretOffset) && !rBrace.getTextRange().containsOffset(caretOffset)) return false + + setText("Remove braces from '${containerNode.description()}' statement") + return true } - override fun applyTo(element: JetExpressionImpl, editor: Editor) { - val expressionKind = element.getExpressionKind(editor.getCaretModel().getOffset())!! + override fun applyTo(element: JetBlockExpression, editor: Editor) { + val statement = element.getStatements().single() - val jetBlockElement = element.findBlockInExpression(expressionKind) - val firstStatement = jetBlockElement!!.getStatements().first() + val containerNode = element.getParent() as JetContainerNode + val construct = containerNode.getParent() as JetExpression + handleComments(construct, element) - handleComments(element, jetBlockElement) + val newElement = element.replace(statement.copy()) - val newElement = jetBlockElement.replace(firstStatement.copy()) - - if (expressionKind == ExpressionKind.DOWHILE) { + if (construct is JetDoWhileExpression) { newElement.getParent()!!.addAfter(JetPsiFactory(element).createNewLine(), newElement) } } - fun handleComments(element: JetExpressionImpl, blockElement: JetBlockExpression) { - var sibling = blockElement.getFirstChild()?.getNextSibling() + private fun handleComments(construct: JetExpression, block: JetBlockExpression) { + var sibling = block.getFirstChild()?.getNextSibling() while (sibling != null) { if (sibling is PsiComment) { //cleans up extra whitespace - val psiFactory = JetPsiFactory(element) - if (element.getPrevSibling() is PsiWhiteSpace) { - element.getPrevSibling()!!.replace(psiFactory.createNewLine()) + val psiFactory = JetPsiFactory(construct) + if (construct.getPrevSibling() is PsiWhiteSpace) { + construct.getPrevSibling()!!.replace(psiFactory.createNewLine()) } - val commentElement = element.getParent()!!.addBefore(sibling as PsiComment, element.getPrevSibling()) - element.getParent()!!.addBefore(psiFactory.createNewLine(), commentElement) + val commentElement = construct.getParent()!!.addBefore(sibling as PsiComment, construct.getPrevSibling()) + construct.getParent()!!.addBefore(psiFactory.createNewLine(), commentElement) } sibling = sibling!!.getNextSibling() } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt index 988f6d33d25..f6ce908c506 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt @@ -16,15 +16,17 @@ package org.jetbrains.kotlin.idea.intentions -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.types.JetType -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.idea.util.ShortenReferences import org.jetbrains.kotlin.JetNodeTypes -import org.jetbrains.kotlin.lexer.JetTokens -import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers +import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers +import org.jetbrains.kotlin.idea.util.ShortenReferences +import org.jetbrains.kotlin.lexer.JetTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.parents +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull fun specifyTypeExplicitly(declaration: JetNamedFunction, typeText: String) { specifyTypeExplicitly(declaration, JetPsiFactory(declaration).createType(typeText)) @@ -55,43 +57,17 @@ fun functionReturnType(function: JetNamedFunction): JetType? { return (descriptor as FunctionDescriptor).getReturnType() } -enum class ExpressionKind(val text: String) { - IF : ExpressionKind("if") - ELSE : ExpressionKind("else") - WHILE : ExpressionKind("while") - DOWHILE : ExpressionKind("do...while") - FOR : ExpressionKind("for") -} - -fun JetExpressionImpl.findBlockInExpression(expressionKind: ExpressionKind?): JetBlockExpression? { - val bodyNode = when (expressionKind) { - ExpressionKind.IF -> this.getNode().findChildByType(JetNodeTypes.THEN) - ExpressionKind.ELSE -> this.getNode().findChildByType(JetNodeTypes.ELSE) - else -> this.getNode().findChildByType(JetNodeTypes.BODY) - } - return bodyNode!!.getPsi()!!.getFirstChild() as? JetBlockExpression -} - -fun JetExpressionImpl.getExpressionKind(caretLocation: Int): ExpressionKind? { - when (this) { - is JetIfExpression -> { - if (this.getElse() != null) { - val elseLocation = this.getNode().findChildByType(JetTokens.ELSE_KEYWORD)!!.getPsi()!!.getTextOffset() - if (caretLocation >= elseLocation) return ExpressionKind.ELSE +fun JetContainerNode.description(): String? { + when (getNode().getElementType()) { + JetNodeTypes.THEN -> return "if" + JetNodeTypes.ELSE -> return "else" + JetNodeTypes.BODY -> { + when (getParent()) { + is JetWhileExpression -> return "while" + is JetDoWhileExpression -> return "do...while" + is JetForExpression -> return "for" } - return ExpressionKind.IF - } - is JetWhileExpression -> { - return ExpressionKind.WHILE - } - is JetDoWhileExpression -> { - return ExpressionKind.DOWHILE - } - is JetForExpression -> { - return ExpressionKind.FOR - } - else -> { - return null } } + return null } diff --git a/idea/testData/intentions/removeBraces/else.kt b/idea/testData/intentions/removeBraces/else.kt index 38b1801e62c..47c02397c9e 100644 --- a/idea/testData/intentions/removeBraces/else.kt +++ b/idea/testData/intentions/removeBraces/else.kt @@ -3,7 +3,7 @@ fun doSomething(a: T) {} fun foo() { if (true) { doSomething("test") - } else { + } else { doSomething("test2") } } diff --git a/idea/testData/intentions/removeBraces/for.kt b/idea/testData/intentions/removeBraces/for.kt index ff9fb40ee8a..36bb446f12f 100644 --- a/idea/testData/intentions/removeBraces/for.kt +++ b/idea/testData/intentions/removeBraces/for.kt @@ -1,7 +1,7 @@ fun doSomething(a: T) {} fun foo() { - for (i in 1..4) { + for (i in 1..4) { doSomething("test") } } diff --git a/idea/testData/intentions/removeBraces/forWithLocalVariable.kt b/idea/testData/intentions/removeBraces/forWithLocalVariable.kt index 3d4d7c5b4d5..c50a753eb23 100644 --- a/idea/testData/intentions/removeBraces/forWithLocalVariable.kt +++ b/idea/testData/intentions/removeBraces/forWithLocalVariable.kt @@ -1,5 +1,5 @@ fun foo(a: List) { - for (x in a) { + for (x in a) { val y = x } } \ No newline at end of file diff --git a/idea/testData/intentions/removeBraces/forWithLocalVariable.kt.after b/idea/testData/intentions/removeBraces/forWithLocalVariable.kt.after index 53a8246dff9..268be1f0616 100644 --- a/idea/testData/intentions/removeBraces/forWithLocalVariable.kt.after +++ b/idea/testData/intentions/removeBraces/forWithLocalVariable.kt.after @@ -1,3 +1,3 @@ fun foo(a: List) { - for (x in a) val y = x + for (x in a) val y = x } \ No newline at end of file diff --git a/idea/testData/intentions/removeBraces/if.kt b/idea/testData/intentions/removeBraces/if.kt index 3c452d03977..1fec3b66c2f 100644 --- a/idea/testData/intentions/removeBraces/if.kt +++ b/idea/testData/intentions/removeBraces/if.kt @@ -1,7 +1,7 @@ fun doSomething(a: T) {} fun foo() { - if (true) { + if (true) { doSomething("test") - } + } } diff --git a/idea/testData/intentions/removeBraces/ifWithComment.kt b/idea/testData/intentions/removeBraces/ifWithComment.kt index 24e2680c29f..801f06d30ae 100644 --- a/idea/testData/intentions/removeBraces/ifWithComment.kt +++ b/idea/testData/intentions/removeBraces/ifWithComment.kt @@ -1,7 +1,7 @@ fun doSomething(a: T) {} fun foo() { - if (true) { + if (true) { //comment doSomething("test") } diff --git a/idea/testData/intentions/removeBraces/ifWithNoStatement.kt b/idea/testData/intentions/removeBraces/ifWithNoStatement.kt index 820d2486a00..a894fe8017e 100644 --- a/idea/testData/intentions/removeBraces/ifWithNoStatement.kt +++ b/idea/testData/intentions/removeBraces/ifWithNoStatement.kt @@ -1,4 +1,4 @@ // IS_APPLICABLE: false fun foo() { - if (true) { } + if (true) { } } \ No newline at end of file diff --git a/idea/testData/intentions/removeBraces/ifWithSemicolon.kt b/idea/testData/intentions/removeBraces/ifWithSemicolon.kt index c7c92569e13..b292cdda027 100644 --- a/idea/testData/intentions/removeBraces/ifWithSemicolon.kt +++ b/idea/testData/intentions/removeBraces/ifWithSemicolon.kt @@ -1,7 +1,7 @@ fun doSomething(a: T) {} fun foo() { - if (true) { + if (true) { doSomething("test"); - } + } } diff --git a/idea/testData/intentions/removeBraces/ifWithTwoStatements.kt b/idea/testData/intentions/removeBraces/ifWithTwoStatements.kt index 7a75713f943..a7f1bb1a9fa 100644 --- a/idea/testData/intentions/removeBraces/ifWithTwoStatements.kt +++ b/idea/testData/intentions/removeBraces/ifWithTwoStatements.kt @@ -5,5 +5,5 @@ fun foo() { if (true) { doSomething("test") doSomething("test2") - } + } } diff --git a/idea/testData/intentions/removeBraces/whileWithTwoStatements.kt b/idea/testData/intentions/removeBraces/whileWithTwoStatements.kt index b2da2ed4763..8a9aeb861b2 100644 --- a/idea/testData/intentions/removeBraces/whileWithTwoStatements.kt +++ b/idea/testData/intentions/removeBraces/whileWithTwoStatements.kt @@ -5,5 +5,5 @@ fun foo() { while (true) { doSomething("test") doSomething("test2") - } + } }