From 3f7b8554dd18f8afd89c0651d2befd6ce4e8836b Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Tue, 15 Dec 2015 16:16:16 +0300 Subject: [PATCH] J2K: parenthesize receiver if needed #KT-10121 Fixed --- .../RemoveUnnecessaryParenthesesIntention.kt | 15 ++++++++++----- .../kotlin/idea/j2k/J2kPostProcessings.kt | 1 + j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt | 8 ++++++-- .../jetbrains/kotlin/j2k/ExpressionConverter.kt | 6 +++--- j2k/src/org/jetbrains/kotlin/j2k/SpecialMethod.kt | 8 ++++---- .../assertStatement/onlyConditionWithBraces.kt | 2 +- .../methodCallExpression/parameterToReceiver.java | 7 +++++++ .../methodCallExpression/parameterToReceiver.kt | 6 ++++++ .../VariableInitializedWithTernaryNull.kt | 2 +- .../parenthesizedExpression/parenthesized.java | 2 +- .../parenthesizedExpression/parenthesized.kt | 2 +- .../parenthesizedExpression/parenthesized2.java | 2 +- .../parenthesizedExpression/parenthesized2.kt | 2 +- ...aToKotlinConverterForWebDemoTestGenerated.java | 6 ++++++ ...aToKotlinConverterSingleFileTestGenerated.java | 6 ++++++ 15 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 j2k/testData/fileOrElement/methodCallExpression/parameterToReceiver.java create mode 100644 j2k/testData/fileOrElement/methodCallExpression/parameterToReceiver.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveUnnecessaryParenthesesIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveUnnecessaryParenthesesIntention.kt index 176fd972983..1297f884d33 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveUnnecessaryParenthesesIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveUnnecessaryParenthesesIntention.kt @@ -17,18 +17,23 @@ package org.jetbrains.kotlin.idea.intentions import com.intellij.openapi.editor.Editor +import com.intellij.openapi.util.TextRange import org.jetbrains.kotlin.psi.KtParenthesizedExpression import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.psiUtil.containsInside -public class RemoveUnnecessaryParenthesesIntention : SelfTargetingIntention(javaClass(), "Remove unnecessary parentheses") { - override fun isApplicableTo(element: KtParenthesizedExpression, caretOffset: Int): Boolean { - val expression = element.getExpression() ?: return false - if (!KtPsiUtil.areParenthesesUseless(element)) return false - return !expression.getTextRange().containsInside(caretOffset) +public class RemoveUnnecessaryParenthesesIntention : SelfTargetingRangeIntention(KtParenthesizedExpression::class.java, "Remove unnecessary parentheses") { + override fun applicabilityRange(element: KtParenthesizedExpression): TextRange? { + element.getExpression() ?: return null + if (!KtPsiUtil.areParenthesesUseless(element)) return null + return element.getTextRange() } override fun applyTo(element: KtParenthesizedExpression, editor: Editor) { + applyTo(element) + } + + fun applyTo(element: KtParenthesizedExpression) { element.replace(element.getExpression()!!) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt b/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt index d087ae3eb8c..451ca1b13bb 100644 --- a/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt +++ b/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt @@ -64,6 +64,7 @@ object J2KPostProcessingRegistrar { registerIntentionBasedProcessing(AddOperatorModifierIntention()) { applyTo(it) } registerIntentionBasedProcessing(ObjectLiteralToLambdaIntention()) { applyTo(it) } registerIntentionBasedProcessing(AnonymousFunctionToLambdaIntention()) { applyTo(it) } + registerIntentionBasedProcessing(RemoveUnnecessaryParenthesesIntention()) { applyTo(it) } registerDiagnosticBasedProcessing(Errors.USELESS_CAST) { element, diagnostic -> val expression = RemoveRightPartOfBinaryExpressionFix(element, "").invoke() diff --git a/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt index 15af7a1df3c..2ce3f49fdc4 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt @@ -63,10 +63,14 @@ class CodeConverter( public fun convertExpressions(expressions: List): List = expressions.map { convertExpression(it) } - public fun convertExpression(expression: PsiExpression?): Expression { + public fun convertExpression(expression: PsiExpression?, shouldParenthesize: Boolean = false): Expression { if (expression == null) return Expression.Empty - return expressionConverter.convertExpression(expression, this).assignPrototype(expression) + val converted = expressionConverter.convertExpression(expression, this).assignPrototype(expression) + if (shouldParenthesize) { + return ParenthesizedExpression(converted).assignNoPrototype() + } + return converted } public fun convertLocalVariable(variable: PsiLocalVariable): LocalVariable { diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt index 7d6644f80ff..09bdfabdc22 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt @@ -268,7 +268,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { val isExtension = property.isExtensionDeclaration() val propertyAccess = if (isTopLevel) { if (isExtension) - QualifiedExpression(codeConverter.convertExpression(arguments.firstOrNull()), propertyName).assignNoPrototype() + QualifiedExpression(codeConverter.convertExpression(arguments.firstOrNull(), true), propertyName).assignNoPrototype() else propertyName } @@ -293,7 +293,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { else if (origin is KtFunction) { if (isTopLevel) { result = if (origin.isExtensionDeclaration()) { - val qualifier = codeConverter.convertExpression(arguments.firstOrNull()) + val qualifier = codeConverter.convertExpression(arguments.firstOrNull(), true) MethodCallExpression.build(qualifier, origin.name!!, convertArguments(expression, isExtension = true), @@ -314,7 +314,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { val resolvedQualifier = (methodExpr.qualifier as? PsiReferenceExpression)?.resolve() if (isFacadeClassFromLibrary(resolvedQualifier)) { result = if (target.isKotlinExtensionFunction()) { - val qualifier = codeConverter.convertExpression(arguments.firstOrNull()) + val qualifier = codeConverter.convertExpression(arguments.firstOrNull(), true) MethodCallExpression.build(qualifier, methodExpr.referenceName!!, convertArguments(expression, isExtension = true), diff --git a/j2k/src/org/jetbrains/kotlin/j2k/SpecialMethod.kt b/j2k/src/org/jetbrains/kotlin/j2k/SpecialMethod.kt index 202b477e196..1c79e9cbdca 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/SpecialMethod.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/SpecialMethod.kt @@ -306,7 +306,7 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): Expression? { if (arguments.size < 2) return null // incorrect call - return MethodCallExpression.build(codeConverter.convertExpression(arguments[1]), "format", codeConverter.convertExpressions(listOf(arguments[0]) + arguments.drop(2)), emptyList(), false) + return MethodCallExpression.build(codeConverter.convertExpression(arguments[1], true), "format", codeConverter.convertExpressions(listOf(arguments[0]) + arguments.drop(2)), emptyList(), false) } }, @@ -319,7 +319,7 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): Expression? { if (arguments.isEmpty()) return null // incorrect call - return MethodCallExpression.build(codeConverter.convertExpression(arguments.first()), "format", codeConverter.convertExpressions(arguments.drop(1)), emptyList(), false) + return MethodCallExpression.build(codeConverter.convertExpression(arguments.first(), true), "format", codeConverter.convertExpressions(arguments.drop(1)), emptyList(), false) } }, @@ -347,7 +347,7 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String STRING_VALUE_OF(JAVA_LANG_STRING, "valueOf", 1) { override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.build(codeConverter.convertExpression(arguments.single()), "toString", emptyList(), emptyList(), false) + = MethodCallExpression.build(codeConverter.convertExpression(arguments.single(), true), "toString", emptyList(), emptyList(), false) }, SYSTEM_OUT_PRINTLN(PrintStream::class.java.name, "println", null) { @@ -412,7 +412,7 @@ private fun convertSystemOutMethodCall( } private fun CodeConverter.convertToRegex(expression: PsiExpression?): Expression - = MethodCallExpression.build(convertExpression(expression), "toRegex", emptyList(), emptyList(), false).assignNoPrototype() + = MethodCallExpression.build(convertExpression(expression, true), "toRegex", emptyList(), emptyList(), false).assignNoPrototype() private fun addIgnoreCaseArgument( qualifier: PsiExpression?, diff --git a/j2k/testData/fileOrElement/assertStatement/onlyConditionWithBraces.kt b/j2k/testData/fileOrElement/assertStatement/onlyConditionWithBraces.kt index 9c9d8fecb83..8d54af49a99 100644 --- a/j2k/testData/fileOrElement/assertStatement/onlyConditionWithBraces.kt +++ b/j2k/testData/fileOrElement/assertStatement/onlyConditionWithBraces.kt @@ -1 +1 @@ -assert((boolMethod())) \ No newline at end of file +assert(boolMethod()) \ No newline at end of file diff --git a/j2k/testData/fileOrElement/methodCallExpression/parameterToReceiver.java b/j2k/testData/fileOrElement/methodCallExpression/parameterToReceiver.java new file mode 100644 index 00000000000..ba8e02c3eb7 --- /dev/null +++ b/j2k/testData/fileOrElement/methodCallExpression/parameterToReceiver.java @@ -0,0 +1,7 @@ +//method +public static void adjust(String name, int maxLen) { + String.format("%-" + maxLen + "s", name); + String.valueOf(1 + 1); + "a".split("\\s+" + "\\s+", 2) + kotlinApi.KotlinApiKt.extensionFunction(1 + 1) +} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/methodCallExpression/parameterToReceiver.kt b/j2k/testData/fileOrElement/methodCallExpression/parameterToReceiver.kt new file mode 100644 index 00000000000..bd385f4873e --- /dev/null +++ b/j2k/testData/fileOrElement/methodCallExpression/parameterToReceiver.kt @@ -0,0 +1,6 @@ +fun adjust(name: String, maxLen: Int) { + ("%-" + maxLen + "s").format(name) + (1 + 1).toString() + "a".split(("\\s+" + "\\s+").toRegex(), 2).toTypedArray() + (1 + 1).extensionFunction() +} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/nullability/VariableInitializedWithTernaryNull.kt b/j2k/testData/fileOrElement/nullability/VariableInitializedWithTernaryNull.kt index caa9571090f..7d3a861da9c 100644 --- a/j2k/testData/fileOrElement/nullability/VariableInitializedWithTernaryNull.kt +++ b/j2k/testData/fileOrElement/nullability/VariableInitializedWithTernaryNull.kt @@ -1,4 +1,4 @@ // !specifyLocalVariableTypeByDefault: true fun foo(b: Boolean) { - val s: String? = (if (b) "abc" else null) + val s: String? = if (b) "abc" else null } \ No newline at end of file diff --git a/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized.java b/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized.java index d678a57c711..a8d1e2c8a5c 100644 --- a/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized.java +++ b/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized.java @@ -1,2 +1,2 @@ //expression -(1 + 2) \ No newline at end of file +(1 + 2).foo() \ No newline at end of file diff --git a/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized.kt b/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized.kt index 0a911375668..2fb3f6930b5 100644 --- a/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized.kt +++ b/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized.kt @@ -1 +1 @@ -(1 + 2) \ No newline at end of file +(1 + 2).foo() \ No newline at end of file diff --git a/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized2.java b/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized2.java index b6ac6039930..2b1f91ae256 100644 --- a/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized2.java +++ b/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized2.java @@ -1,2 +1,2 @@ //expression -(str.toString() + "abc") \ No newline at end of file +(str.toString() + "abc").foo() \ No newline at end of file diff --git a/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized2.kt b/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized2.kt index 01d3d19b7d8..b46f6389c44 100644 --- a/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized2.kt +++ b/j2k/testData/fileOrElement/parenthesizedExpression/parenthesized2.kt @@ -1 +1 @@ -(str.toString() + "abc") \ No newline at end of file +(str.toString() + "abc").foo() \ No newline at end of file diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java index eb4abc607c4..14ce0f06730 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java @@ -3091,6 +3091,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("parameterToReceiver.java") + public void testParameterToReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/methodCallExpression/parameterToReceiver.java"); + doTest(fileName); + } + @TestMetadata("simpleCall.java") public void testSimpleCall() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/methodCallExpression/simpleCall.java"); diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java index db9bc76fa94..32d451135ba 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java @@ -3091,6 +3091,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("parameterToReceiver.java") + public void testParameterToReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/methodCallExpression/parameterToReceiver.java"); + doTest(fileName); + } + @TestMetadata("simpleCall.java") public void testSimpleCall() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/methodCallExpression/simpleCall.java");