diff --git a/.idea/dictionaries/valentin.xml b/.idea/dictionaries/valentin.xml index 8fee9efdd5d..fd8f3810478 100644 --- a/.idea/dictionaries/valentin.xml +++ b/.idea/dictionaries/valentin.xml @@ -6,6 +6,7 @@ inserter pparent processings + rbracket rparenth selectioner diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/OperatorToFunctionIntention.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/OperatorToFunctionIntention.kt index e9da59a840c..ea22b5f9dca 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/OperatorToFunctionIntention.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/OperatorToFunctionIntention.kt @@ -57,7 +57,8 @@ public class OperatorToFunctionIntention : JetSelfTargetingIntention(javaC val expression = element.getTargetExpression(caretOffset) ?: return false if (expression is JetBlockExpression) return false - val description = (expression.getParent() as JetContainerNode).description() + val description = (expression.getParent() as JetContainerNode).description()!! setText("Add braces to '$description' statement") return true } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertAssertToIfWithThrowIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertAssertToIfWithThrowIntention.kt index 9b4f3ffc3d4..37c7035c561 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertAssertToIfWithThrowIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertAssertToIfWithThrowIntention.kt @@ -28,12 +28,13 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall public class ConvertAssertToIfWithThrowIntention : JetSelfTargetingIntention(javaClass(), "Replace 'assert' with 'if' statement") { override fun isApplicableTo(element: JetCallExpression, caretOffset: Int): Boolean { val callee = element.getCalleeExpression() ?: return false - if (callee.getText() != "assert") return false if (!callee.getTextRange().containsOffset(caretOffset)) return false val argumentSize = element.getValueArguments().size() if (argumentSize !in 1..2) return false - if (element.getFunctionLiteralArguments().size() == 1 && argumentSize == 1) return false + val functionLiterals = element.getFunctionLiteralArguments() + if (functionLiterals.size() > 1) return false + if (functionLiterals.size() == 1 && argumentSize == 1) return false // "assert {...}" is incorrect val resolvedCall = element.getResolvedCall(element.analyze()) ?: return false return DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).asString() == "kotlin.assert" @@ -42,14 +43,14 @@ public class ConvertAssertToIfWithThrowIntention : JetSelfTargetingIntention args[1]?.getArgumentExpression() ?: return - functionLiterals.isNotEmpty() -> functionLiterals.first() + functionLiteral != null -> functionLiteral!! else -> psiFactory.createExpression("\"Assertion failed\"") } @@ -58,34 +59,27 @@ public class ConvertAssertToIfWithThrowIntention : JetSelfTargetingIntention(javaClass(), "Replace with a for each loop") { +public class ConvertForEachToForLoopIntention : JetSelfTargetingIntention(javaClass(), "Replace with a for loop") { override fun isApplicableTo(element: JetExpression, caretOffset: Int): Boolean { - val data = extractData(element) ?: return false - if (data.functionLiteral.getValueParameters().size() > 1) return false - if (data.functionLiteral.getValueParameters().size() > 1 || data.functionLiteral.getBodyExpression() == null) return false + val functionLiteral = extractFunctionLiteral(element) ?: return false + if (functionLiteral.getValueParameters().size() > 1) return false + if (functionLiteral.getBodyExpression() == null) return false - if (caretOffset > data.functionLiteral.getTextRange().getStartOffset()) return false // not available within function literal body + if (caretOffset > functionLiteral.getTextRange().getStartOffset()) return false // not available within function literal body val resolvedCall = element.getResolvedCall(element.analyze()) ?: return false - return DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).toString() == "kotlin.forEach" + if (DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).toString() != "kotlin.forEach") return false + return resolvedCall.getCall().getExplicitReceiver() is ExpressionReceiver } override fun applyTo(element: JetExpression, editor: Editor) { - val data = extractData(element)!! - val loopText = generateLoopText(data.functionLiteral, data.receiver) - element.replace(JetPsiFactory(element).createExpression(loopText)) + val functionLiteral = extractFunctionLiteral(element)!! + val receiver = element.getCall(element.analyze())!!.getExplicitReceiver() as ExpressionReceiver + val receiverExpression = receiver.getExpression() + val loopText = generateLoopText(functionLiteral, receiverExpression) + val expressionToReplace = receiverExpression.getParent() // it's correct for both JetDotQualifiedExpression and JetBinaryExpression + expressionToReplace.replace(JetPsiFactory(element).createExpression(loopText)) } - private data class Data(val functionLiteral: JetFunctionLiteralExpression, val receiver: JetExpression) - - private fun extractData(element: JetExpression): Data? { - when (element) { - is JetDotQualifiedExpression -> { - val selector = element.getSelectorExpression() as? JetCallExpression ?: return null - val argument = selector.getValueArguments().singleOrNull() ?: return null - val functionLiteral = argument.getArgumentExpression() as? JetFunctionLiteralExpression ?: return null - return Data(functionLiteral, element.getReceiverExpression()) - } - - is JetBinaryExpression -> { - val functionLiteral = element.getRight() as? JetFunctionLiteralExpression ?: return null - return Data(functionLiteral, element.getLeft() ?: return null) - } - - else -> return null - } + private fun extractFunctionLiteral(element: JetExpression): JetFunctionLiteralExpression? { + return when (element) { + is JetCallExpression -> element.getValueArguments().singleOrNull()?.getArgumentExpression() + is JetBinaryExpression -> element.getRight() + else -> null + } as? JetFunctionLiteralExpression } private fun generateLoopText(functionLiteral: JetFunctionLiteralExpression, receiver: JetExpression): String { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertNegatedBooleanSequenceIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertNegatedBooleanSequenceIntention.kt index 5a9404568a4..d5e1ccc850b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertNegatedBooleanSequenceIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertNegatedBooleanSequenceIntention.kt @@ -38,7 +38,7 @@ public class ConvertNegatedBooleanSequenceIntention : JetSelfTargetingOffsetInde val operatorText = when(element.getOperationToken()) { JetTokens.ANDAND -> JetTokens.OROR.getValue() JetTokens.OROR -> JetTokens.ANDAND.getValue() - else -> throw IllegalArgumentException() + else -> throw IllegalArgumentException() // checked in isApplicableTo } val elements = splitBooleanSequence(element)!! diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt index d820a34632e..b5dc1077e85 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import kotlin.platform.platformName diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToForEachFunctionCallIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToForEachFunctionCallIntention.kt index f44f6075017..6549009f932 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToForEachFunctionCallIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToForEachFunctionCallIntention.kt @@ -35,17 +35,10 @@ public class ConvertToForEachFunctionCallIntention : JetSelfTargetingIntention body.getStatements().map { it.getText() }.joinToString("\n") else -> body.getText() } - val bodyText = buildFunctionLiteralBodyText(loopParameter, functionBodyText) + val bodyText = "${loopParameter.getText()} -> $functionBodyText" val foreachExpression = factory.createExpression("x.forEach { $bodyText }") as JetDotQualifiedExpression foreachExpression.getReceiverExpression().replace(element.getLoopRange()!!) element.replace(foreachExpression) } - - private fun buildFunctionLiteralBodyText(loopParameter: JetParameter, functionBodyText: String): String { - return when { - loopParameter.getTypeReference() != null -> " (${loopParameter.getText()}) -> $functionBodyText" - else -> "${loopParameter.getText()} -> $functionBodyText" - } - } } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveBracesIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveBracesIntention.kt index 00a2c383bcc..449fad1e2f1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveBracesIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveBracesIntention.kt @@ -32,7 +32,8 @@ public class RemoveBracesIntention : JetSelfTargetingIntentionx.reverse().forEach { it } + x.reverse().forEach { it } } \ No newline at end of file diff --git a/idea/testData/intentions/convertForEachToForLoop/explicitFunctionLiteral.kt b/idea/testData/intentions/convertForEachToForLoop/explicitFunctionLiteral.kt index c801e547fda..7edcaea43af 100644 --- a/idea/testData/intentions/convertForEachToForLoop/explicitFunctionLiteral.kt +++ b/idea/testData/intentions/convertForEachToForLoop/explicitFunctionLiteral.kt @@ -2,5 +2,5 @@ fun foo() { val x = 1..4 - x.forEach({ y -> y }) + x.forEach({ y -> y }) } \ No newline at end of file diff --git a/idea/testData/intentions/convertForEachToForLoop/implicitFunctionLiteralParameter.kt b/idea/testData/intentions/convertForEachToForLoop/implicitFunctionLiteralParameter.kt index e6ba3880d2d..d163c979777 100644 --- a/idea/testData/intentions/convertForEachToForLoop/implicitFunctionLiteralParameter.kt +++ b/idea/testData/intentions/convertForEachToForLoop/implicitFunctionLiteralParameter.kt @@ -2,5 +2,5 @@ fun foo() { val x = 1..4 - x.forEach { it } + x.forEach { it } } \ No newline at end of file diff --git a/idea/testData/intentions/convertForEachToForLoop/parenthesizedExpression.kt b/idea/testData/intentions/convertForEachToForLoop/parenthesizedExpression.kt index a6137d098a9..67b40498721 100644 --- a/idea/testData/intentions/convertForEachToForLoop/parenthesizedExpression.kt +++ b/idea/testData/intentions/convertForEachToForLoop/parenthesizedExpression.kt @@ -1,4 +1,4 @@ // WITH_RUNTIME fun main() { - (1 rangeTo 2).forEach { x -> x } + (1 rangeTo 2).forEach { x -> x } } \ No newline at end of file diff --git a/idea/testData/intentions/convertForEachToForLoop/simple.kt b/idea/testData/intentions/convertForEachToForLoop/simple.kt index fec99e3a5a8..54a3627b76d 100644 --- a/idea/testData/intentions/convertForEachToForLoop/simple.kt +++ b/idea/testData/intentions/convertForEachToForLoop/simple.kt @@ -2,5 +2,5 @@ fun foo() { val x = 1..4 - x.forEach { it.equals(1) } + x.forEach { it.equals(1) } } \ No newline at end of file diff --git a/idea/testData/intentions/convertForEachToForLoop/typeArgumentPresent.kt b/idea/testData/intentions/convertForEachToForLoop/typeArgumentPresent.kt index 543204fe6a8..d5cc7b393fb 100644 --- a/idea/testData/intentions/convertForEachToForLoop/typeArgumentPresent.kt +++ b/idea/testData/intentions/convertForEachToForLoop/typeArgumentPresent.kt @@ -2,5 +2,5 @@ fun foo() { val x = 1..4 - x.forEach({ it }) + x.forEach({ it }) } \ No newline at end of file diff --git a/idea/testData/intentions/convertToForEachFunctionCall/iterativeElementTypeSpecified.kt.after b/idea/testData/intentions/convertToForEachFunctionCall/iterativeElementTypeSpecified.kt.after index 1183a23711b..e800c27fe50 100644 --- a/idea/testData/intentions/convertToForEachFunctionCall/iterativeElementTypeSpecified.kt.after +++ b/idea/testData/intentions/convertToForEachFunctionCall/iterativeElementTypeSpecified.kt.after @@ -2,5 +2,5 @@ fun main() { val list = 1..4 - list.forEach {(x: Int) -> x } + list.forEach { x: Int -> x } } \ No newline at end of file diff --git a/idea/testData/intentions/convertToForEachFunctionCall/typeAnnotatedWithNonBlockBody.kt.after b/idea/testData/intentions/convertToForEachFunctionCall/typeAnnotatedWithNonBlockBody.kt.after index b3babbdc94a..5f8d6656adf 100644 --- a/idea/testData/intentions/convertToForEachFunctionCall/typeAnnotatedWithNonBlockBody.kt.after +++ b/idea/testData/intentions/convertToForEachFunctionCall/typeAnnotatedWithNonBlockBody.kt.after @@ -2,5 +2,5 @@ fun main() { val list = 1..4 - list.forEach {(x: Int) -> 11 } + list.forEach { x: Int -> 11 } } \ No newline at end of file