From 67606c55e75300ff42d8b5ef6d2d457d155f0204 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 7 Aug 2014 14:32:19 +0400 Subject: [PATCH] Rename: Initial support of naming conventions --- .../refactoring/rename/annotations.xml | 23 ++ .../intentions/OperatorToFunctionIntention.kt | 300 +++++++++--------- .../JetRefactoringBundle.properties | 4 +- .../rename/RenameJetClassProcessor.java | 2 +- .../rename/RenameKotlinFunctionProcessor.kt | 5 +- .../rename/RenameKotlinPsiProcessor.kt | 37 +++ .../plugin/refactoring/rename/renameUtil.kt | 57 ++++ .../references/JetArrayAccessReference.java | 20 +- .../JetInvokeFunctionReference.java | 17 + .../JetMultiDeclarationReference.kt | 14 + .../jet/plugin/references/JetReference.kt | 3 +- .../references/JetSimpleNameReference.kt | 51 ++- .../jet/plugin/references/referenceUtil.kt | 14 + .../rename/renameCompareTo/after/compareTo.kt | 11 + .../renameCompareTo/before/compareTo.kt | 11 + .../rename/renameCompareTo/compareTo.test | 7 + .../rename/renameContains/after/contains.kt | 9 + .../rename/renameContains/before/contains.kt | 9 + .../rename/renameContains/contains.test | 7 + .../before/containsWithConflicts.kt | 13 + .../containsWithConflicts.test | 8 + .../rename/renameEquals/after/equals.kt | 11 + .../rename/renameEquals/before/equals.kt | 11 + .../rename/renameEquals/equals.test | 7 + .../before/explicitComponentFunction.kt | 12 + .../explicitComponentFunction.test | 8 + .../refactoring/rename/renameGet/after/get.kt | 8 + .../rename/renameGet/before/get.kt | 8 + .../refactoring/rename/renameGet/get.test | 7 + .../rename/renameInc/before/inc.kt | 10 + .../refactoring/rename/renameInc/inc.test | 8 + .../rename/renameInvoke/after/invoke.kt | 8 + .../rename/renameInvoke/before/invoke.kt | 8 + .../rename/renameInvoke/invoke.test | 7 + .../rename/renameIterator/before/iterator.kt | 8 + .../rename/renameIterator/iterator.test | 8 + .../rename/renamePlus/after/plus.kt | 12 + .../rename/renamePlus/before/plus.kt | 12 + .../refactoring/rename/renamePlus/plus.test | 7 + .../renamePlusAssign/after/plusAssign.kt | 11 + .../renamePlusAssign/before/plusAssign.kt | 11 + .../rename/renamePlusAssign/plusAssign.test | 7 + .../refactoring/rename/renameSet/after/set.kt | 10 + .../rename/renameSet/before/set.kt | 10 + .../refactoring/rename/renameSet/set.test | 7 + .../after/synthesizedComponentFunction.kt | 8 + .../before/synthesizedComponentFunction.kt | 8 + .../synthesizedComponentFunction.test | 7 + .../renameUnaryMinus/after/unaryMinus.kt | 8 + .../renameUnaryMinus/before/unaryMinus.kt | 8 + .../rename/renameUnaryMinus/unaryMinus.test | 7 + .../refactoring/rename/AbstractRenameTest.kt | 8 +- .../rename/RenameTestGenerated.java | 70 ++++ 53 files changed, 804 insertions(+), 158 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinPsiProcessor.kt create mode 100644 idea/src/org/jetbrains/jet/plugin/refactoring/rename/renameUtil.kt create mode 100644 idea/testData/refactoring/rename/renameCompareTo/after/compareTo.kt create mode 100644 idea/testData/refactoring/rename/renameCompareTo/before/compareTo.kt create mode 100644 idea/testData/refactoring/rename/renameCompareTo/compareTo.test create mode 100644 idea/testData/refactoring/rename/renameContains/after/contains.kt create mode 100644 idea/testData/refactoring/rename/renameContains/before/contains.kt create mode 100644 idea/testData/refactoring/rename/renameContains/contains.test create mode 100644 idea/testData/refactoring/rename/renameContainsWithConflicts/before/containsWithConflicts.kt create mode 100644 idea/testData/refactoring/rename/renameContainsWithConflicts/containsWithConflicts.test create mode 100644 idea/testData/refactoring/rename/renameEquals/after/equals.kt create mode 100644 idea/testData/refactoring/rename/renameEquals/before/equals.kt create mode 100644 idea/testData/refactoring/rename/renameEquals/equals.test create mode 100644 idea/testData/refactoring/rename/renameExplicitComponentFunction/before/explicitComponentFunction.kt create mode 100644 idea/testData/refactoring/rename/renameExplicitComponentFunction/explicitComponentFunction.test create mode 100644 idea/testData/refactoring/rename/renameGet/after/get.kt create mode 100644 idea/testData/refactoring/rename/renameGet/before/get.kt create mode 100644 idea/testData/refactoring/rename/renameGet/get.test create mode 100644 idea/testData/refactoring/rename/renameInc/before/inc.kt create mode 100644 idea/testData/refactoring/rename/renameInc/inc.test create mode 100644 idea/testData/refactoring/rename/renameInvoke/after/invoke.kt create mode 100644 idea/testData/refactoring/rename/renameInvoke/before/invoke.kt create mode 100644 idea/testData/refactoring/rename/renameInvoke/invoke.test create mode 100644 idea/testData/refactoring/rename/renameIterator/before/iterator.kt create mode 100644 idea/testData/refactoring/rename/renameIterator/iterator.test create mode 100644 idea/testData/refactoring/rename/renamePlus/after/plus.kt create mode 100644 idea/testData/refactoring/rename/renamePlus/before/plus.kt create mode 100644 idea/testData/refactoring/rename/renamePlus/plus.test create mode 100644 idea/testData/refactoring/rename/renamePlusAssign/after/plusAssign.kt create mode 100644 idea/testData/refactoring/rename/renamePlusAssign/before/plusAssign.kt create mode 100644 idea/testData/refactoring/rename/renamePlusAssign/plusAssign.test create mode 100644 idea/testData/refactoring/rename/renameSet/after/set.kt create mode 100644 idea/testData/refactoring/rename/renameSet/before/set.kt create mode 100644 idea/testData/refactoring/rename/renameSet/set.test create mode 100644 idea/testData/refactoring/rename/renameSynthesizedComponentFunction/after/synthesizedComponentFunction.kt create mode 100644 idea/testData/refactoring/rename/renameSynthesizedComponentFunction/before/synthesizedComponentFunction.kt create mode 100644 idea/testData/refactoring/rename/renameSynthesizedComponentFunction/synthesizedComponentFunction.test create mode 100644 idea/testData/refactoring/rename/renameUnaryMinus/after/unaryMinus.kt create mode 100644 idea/testData/refactoring/rename/renameUnaryMinus/before/unaryMinus.kt create mode 100644 idea/testData/refactoring/rename/renameUnaryMinus/unaryMinus.test diff --git a/annotations/com/intellij/refactoring/rename/annotations.xml b/annotations/com/intellij/refactoring/rename/annotations.xml index 019c99d18fb..443386dab53 100644 --- a/annotations/com/intellij/refactoring/rename/annotations.xml +++ b/annotations/com/intellij/refactoring/rename/annotations.xml @@ -1,4 +1,27 @@ + + + + + + + + + + + + + + + + + diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/OperatorToFunctionIntention.kt b/idea/src/org/jetbrains/jet/plugin/intentions/OperatorToFunctionIntention.kt index f1c2b2d6b94..ccffcb2befb 100644 --- a/idea/src/org/jetbrains/jet/plugin/intentions/OperatorToFunctionIntention.kt +++ b/idea/src/org/jetbrains/jet/plugin/intentions/OperatorToFunctionIntention.kt @@ -31,40 +31,169 @@ import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache import org.jetbrains.jet.lang.resolve.BindingContext import org.jetbrains.jet.lang.descriptors.FunctionDescriptor import org.jetbrains.jet.lang.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.jet.lang.psi.JetQualifiedExpression public class OperatorToFunctionIntention : JetSelfTargetingIntention("operator.to.function", javaClass()) { - fun isApplicablePrefix(element: JetPrefixExpression): Boolean { - return when (element.getOperationReference().getReferencedNameElementType()) { - JetTokens.PLUS, JetTokens.MINUS, JetTokens.PLUSPLUS, JetTokens.MINUSMINUS, JetTokens.EXCL -> true - else -> false + class object { + private fun isApplicablePrefix(element: JetPrefixExpression): Boolean { + return when (element.getOperationReference().getReferencedNameElementType()) { + JetTokens.PLUS, JetTokens.MINUS, JetTokens.PLUSPLUS, JetTokens.MINUSMINUS, JetTokens.EXCL -> true + else -> false + } } - } - fun isApplicablePostfix(element: JetPostfixExpression): Boolean { - return when (element.getOperationReference().getReferencedNameElementType()) { - JetTokens.PLUSPLUS, JetTokens.MINUSMINUS -> true - else -> false + private fun isApplicablePostfix(element: JetPostfixExpression): Boolean { + return when (element.getOperationReference().getReferencedNameElementType()) { + JetTokens.PLUSPLUS, JetTokens.MINUSMINUS -> true + else -> false + } } - } - fun isApplicableBinary(element: JetBinaryExpression): Boolean { - return when (element.getOperationReference().getReferencedNameElementType()) { - JetTokens.PLUS, JetTokens.MINUS, JetTokens.MUL, JetTokens.DIV, JetTokens.PERC, JetTokens.RANGE, JetTokens.IN_KEYWORD, JetTokens.NOT_IN, JetTokens.PLUSEQ, JetTokens.MINUSEQ, JetTokens.MULTEQ, JetTokens.DIVEQ, JetTokens.PERCEQ, JetTokens.EQEQ, JetTokens.EXCLEQ, JetTokens.GT, JetTokens.LT, JetTokens.GTEQ, JetTokens.LTEQ -> true - JetTokens.EQ -> element.getLeft() is JetArrayAccessExpression - else -> false + private fun isApplicableBinary(element: JetBinaryExpression): Boolean { + return when (element.getOperationReference().getReferencedNameElementType()) { + JetTokens.PLUS, JetTokens.MINUS, JetTokens.MUL, JetTokens.DIV, JetTokens.PERC, JetTokens.RANGE, JetTokens.IN_KEYWORD, JetTokens.NOT_IN, JetTokens.PLUSEQ, JetTokens.MINUSEQ, JetTokens.MULTEQ, JetTokens.DIVEQ, JetTokens.PERCEQ, JetTokens.EQEQ, JetTokens.EXCLEQ, JetTokens.GT, JetTokens.LT, JetTokens.GTEQ, JetTokens.LTEQ -> true + JetTokens.EQ -> element.getLeft() is JetArrayAccessExpression + else -> false + } } - } - fun isApplicableCall(element: JetCallExpression): Boolean { - val bindingContext = AnalyzerFacadeWithCache.getContextForElement(element) - val resolvedCall = element.getResolvedCall(bindingContext) - val descriptor = resolvedCall?.getResultingDescriptor() - if (descriptor is FunctionDescriptor && descriptor.getName().asString() == "invoke") { + private fun isApplicableCall(element: JetCallExpression): Boolean { + val bindingContext = AnalyzerFacadeWithCache.getContextForElement(element) + val resolvedCall = element.getResolvedCall(bindingContext) + val descriptor = resolvedCall?.getResultingDescriptor() + if (descriptor is FunctionDescriptor && descriptor.getName().asString() == "invoke") { + val parent = element.getParent() + if (parent is JetDotQualifiedExpression && element.getCalleeExpression()?.getText() == "invoke") return false + return !(element.getValueArgumentList() == null && element.getFunctionLiteralArguments().isEmpty()) + } + return false + } + + private fun convertPrefix(element: JetPrefixExpression): JetExpression { + val op = element.getOperationReference().getReferencedNameElementType() + val base = element.getBaseExpression()!!.getText() + + val call = when (op) { + JetTokens.PLUS -> "plus()" + JetTokens.MINUS -> "minus()" + JetTokens.PLUSPLUS -> "inc()" + JetTokens.MINUSMINUS -> "dec()" + JetTokens.EXCL -> "not()" + else -> return element + } + + val transformation = "$base.$call" + val transformed = JetPsiFactory(element).createExpression(transformation) + return element.replace(transformed) as JetExpression + } + + private fun convertPostFix(element: JetPostfixExpression): JetExpression { + val op = element.getOperationReference().getReferencedNameElementType() + val base = element.getBaseExpression().getText() + + val call = when (op) { + JetTokens.PLUSPLUS -> "inc()" + JetTokens.MINUSMINUS -> "dec()" + else -> return element + } + + val transformation = "$base.$call" + val transformed = JetPsiFactory(element).createExpression(transformation) + return element.replace(transformed) as JetExpression + } + + private fun convertBinary(element: JetBinaryExpression): JetExpression { + val op = element.getOperationReference().getReferencedNameElementType() + val left = element.getLeft()!! + val right = element.getRight()!! + val leftText = left.getText() + val rightText = right.getText() + + if (op == JetTokens.EQ) { + if (left is JetArrayAccessExpression) { + convertArrayAccess(left as JetArrayAccessExpression) + } + return element + } + + val context = AnalyzerFacadeWithCache.getContextForElement(element) + val functionCandidate = element.getResolvedCall(context) + val functionName = functionCandidate?.getCandidateDescriptor()?.getName().toString() + val elemType = context[BindingContext.EXPRESSION_TYPE, left] + + val transformation = when (op) { + JetTokens.PLUS -> "$leftText.plus($rightText)" + JetTokens.MINUS -> "$leftText.minus($rightText)" + JetTokens.MUL -> "$leftText.times($rightText)" + JetTokens.DIV -> "$leftText.div($rightText)" + JetTokens.PERC -> "$leftText.mod($rightText)" + JetTokens.RANGE -> "$leftText.rangeTo($rightText)" + JetTokens.IN_KEYWORD -> "$rightText.contains($leftText)" + JetTokens.NOT_IN -> "!$rightText.contains($leftText)" + JetTokens.PLUSEQ -> if (functionName == "plusAssign") "$leftText.plusAssign($rightText)" else "$leftText = $leftText.plus($rightText)" + JetTokens.MINUSEQ -> if (functionName == "minusAssign") "$leftText.minusAssign($rightText)" else "$leftText = $leftText.minus($rightText)" + JetTokens.MULTEQ -> if (functionName == "multAssign") "$leftText.multAssign($rightText)" else "$leftText = $leftText.mult($rightText)" + JetTokens.DIVEQ -> if (functionName == "divAssign") "$leftText.divAssign($rightText)" else "$leftText = $leftText.div($rightText)" + JetTokens.PERCEQ -> if (functionName == "modAssign") "$leftText.modAssign($rightText)" else "$leftText = $leftText.mod($rightText)" + JetTokens.EQEQ -> if (elemType?.isNullable() ?: true) "$leftText?.equals($rightText) ?: $rightText.identityEquals(null)" else "$leftText.equals($rightText)" + JetTokens.EXCLEQ -> if (elemType?.isNullable() ?: true) "!($leftText?.equals($rightText) ?: $rightText.identityEquals(null))" else "!$leftText.equals($rightText)" + JetTokens.GT -> "$leftText.compareTo($rightText) > 0" + JetTokens.LT -> "$leftText.compareTo($rightText) < 0" + JetTokens.GTEQ -> "$leftText.compareTo($rightText) >= 0" + JetTokens.LTEQ -> "$leftText.compareTo($rightText) <= 0" + else -> return element + } + + val transformed = JetPsiFactory(element).createExpression(transformation) + + return element.replace(transformed) as JetExpression + } + + private fun convertArrayAccess(element: JetArrayAccessExpression): JetExpression { val parent = element.getParent() - if (parent is JetDotQualifiedExpression && element.getCalleeExpression()?.getText() == "invoke") return false - return !(element.getValueArgumentList() == null && element.getFunctionLiteralArguments().isEmpty()) + val array = element.getArrayExpression()!!.getText() + val indices = element.getIndicesNode() + val indicesText = indices.getText()?.trim("[","]") ?: throw AssertionError("Indices node of ArrayExpression shouldn't be null: JetArrayAccessExpression = ${element.getText()}") + + val transformation : String + val replaced : JetElement + if (parent is JetBinaryExpression && parent.getOperationReference().getReferencedNameElementType() == JetTokens.EQ) { + // part of an assignment + val right = parent.getRight()!!.getText() + transformation = "$array.set($indicesText, $right)" + replaced = parent + } + else { + transformation = "$array.get($indicesText)" + replaced = element + } + + val transformed = JetPsiFactory(element).createExpression(transformation) + return replaced.replace(transformed) as JetExpression + } + + private fun convertCall(element: JetCallExpression): JetExpression { + val callee = element.getCalleeExpression()!! + val arguments = element.getValueArgumentList() + val argumentString = arguments?.getText()?.trim("(", ")") + val funcLitArgs = element.getFunctionLiteralArguments() + val calleeText = callee.getText() + val transformation = if (argumentString == null) "$calleeText.invoke" else "$calleeText.invoke($argumentString)" + val transformed = JetPsiFactory(element).createExpression(transformation) + funcLitArgs.forEach { transformed.add(it) } + return callee.getParent()!!.replace(transformed) as JetExpression + } + + public fun convert(element: JetExpression): JetExpression { + return when (element) { + is JetPrefixExpression -> convertPrefix(element) + is JetPostfixExpression -> convertPostFix(element) + is JetBinaryExpression -> convertBinary(element) + is JetArrayAccessExpression -> convertArrayAccess(element) + is JetCallExpression -> convertCall(element) + else -> element + } } - return false } override fun isApplicableTo(element: JetExpression): Boolean { @@ -78,128 +207,7 @@ public class OperatorToFunctionIntention : JetSelfTargetingIntention "plus()" - JetTokens.MINUS -> "minus()" - JetTokens.PLUSPLUS -> "inc()" - JetTokens.MINUSMINUS -> "dec()" - JetTokens.EXCL -> "not()" - else -> return - } - - val transformation = "$base.$call" - val transformed = JetPsiFactory(element).createExpression(transformation) - element.replace(transformed) - } - - fun convertPostFix(element: JetPostfixExpression) { - val op = element.getOperationReference().getReferencedNameElementType() - val base = element.getBaseExpression().getText() - - val call = when (op) { - JetTokens.PLUSPLUS -> "inc()" - JetTokens.MINUSMINUS -> "dec()" - else -> return - } - - val transformation = "$base.$call" - val transformed = JetPsiFactory(element).createExpression(transformation) - element.replace(transformed) - } - - fun convertBinary(element: JetBinaryExpression) { - val op = element.getOperationReference().getReferencedNameElementType() - val left = element.getLeft()!! - val right = element.getRight()!! - val leftText = left.getText() - val rightText = right.getText() - - if (op == JetTokens.EQ) { - if (left is JetArrayAccessExpression) { - convertArrayAccess(left as JetArrayAccessExpression) - } - return - } - - val context = AnalyzerFacadeWithCache.getContextForElement(element) - val functionCandidate = element.getResolvedCall(context) - val functionName = functionCandidate?.getCandidateDescriptor()?.getName().toString() - val elemType = context[BindingContext.EXPRESSION_TYPE, left] - - val transformation = when (op) { - JetTokens.PLUS -> "$leftText.plus($rightText)" - JetTokens.MINUS -> "$leftText.minus($rightText)" - JetTokens.MUL -> "$leftText.times($rightText)" - JetTokens.DIV -> "$leftText.div($rightText)" - JetTokens.PERC -> "$leftText.mod($rightText)" - JetTokens.RANGE -> "$leftText.rangeTo($rightText)" - JetTokens.IN_KEYWORD -> "$rightText.contains($leftText)" - JetTokens.NOT_IN -> "!$rightText.contains($leftText)" - JetTokens.PLUSEQ -> if (functionName == "plusAssign") "$leftText.plusAssign($rightText)" else "$leftText = $leftText.plus($rightText)" - JetTokens.MINUSEQ -> if (functionName == "minusAssign") "$leftText.minusAssign($rightText)" else "$leftText = $leftText.minus($rightText)" - JetTokens.MULTEQ -> if (functionName == "multAssign") "$leftText.multAssign($rightText)" else "$leftText = $leftText.mult($rightText)" - JetTokens.DIVEQ -> if (functionName == "divAssign") "$leftText.divAssign($rightText)" else "$leftText = $leftText.div($rightText)" - JetTokens.PERCEQ -> if (functionName == "modAssign") "$leftText.modAssign($rightText)" else "$leftText = $leftText.mod($rightText)" - JetTokens.EQEQ -> if (elemType?.isNullable() ?: true) "$leftText?.equals($rightText) ?: $rightText.identityEquals(null)" else "$leftText.equals($rightText)" - JetTokens.EXCLEQ -> if (elemType?.isNullable() ?: true) "!($leftText?.equals($rightText) ?: $rightText.identityEquals(null))" else "!$leftText.equals($rightText)" - JetTokens.GT -> "$leftText.compareTo($rightText) > 0" - JetTokens.LT -> "$leftText.compareTo($rightText) < 0" - JetTokens.GTEQ -> "$leftText.compareTo($rightText) >= 0" - JetTokens.LTEQ -> "$leftText.compareTo($rightText) <= 0" - else -> return - } - - val transformed = JetPsiFactory(element).createExpression(transformation) - - element.replace(transformed) - } - - fun convertArrayAccess(element: JetArrayAccessExpression) { - val parent = element.getParent() - val array = element.getArrayExpression()!!.getText() - val indices = element.getIndicesNode() - val indicesText = indices.getText()?.trim("[","]") ?: throw AssertionError("Indices node of ArrayExpression shouldn't be null: JetArrayAccessExpression = ${element.getText()}") - - val transformation : String - val replaced : JetElement - if (parent is JetBinaryExpression && parent.getOperationReference().getReferencedNameElementType() == JetTokens.EQ) { - // part of an assignment - val right = parent.getRight()!!.getText() - transformation = "$array.set($indicesText, $right)" - replaced = parent - } - else { - transformation = "$array.get($indicesText)" - replaced = element - } - - val transformed = JetPsiFactory(element).createExpression(transformation) - replaced.replace(transformed) - } - - fun convertCall(element: JetCallExpression) { - val callee = element.getCalleeExpression()!! - val arguments = element.getValueArgumentList() - val argumentString = arguments?.getText()?.trim("(", ")") - val funcLitArgs = element.getFunctionLiteralArguments() - val calleeText = callee.getText() - val transformation = if (argumentString == null) "$calleeText.invoke" else "$calleeText.invoke($argumentString)" - val transformed = JetPsiFactory(element).createExpression(transformation) - funcLitArgs.forEach { transformed.add(it) } - callee.getParent()!!.replace(transformed) - } - override fun applyTo(element: JetExpression, editor: Editor) { - return when (element) { - is JetPrefixExpression -> convertPrefix(element) - is JetPostfixExpression -> convertPostFix(element) - is JetBinaryExpression -> convertBinary(element) - is JetArrayAccessExpression -> convertArrayAccess(element) - is JetCallExpression -> convertCall(element) - } + convert(element) } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringBundle.properties b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringBundle.properties index a4d682dd8e1..2f60b4d0d88 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringBundle.properties +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringBundle.properties @@ -37,4 +37,6 @@ refactoring.move.non.kotlin.file=Target must be a Kotlin file package.private.0.will.no.longer.be.accessible.from.1=Package-private {0} will no longer be accessible from {1} 0.uses.package.private.1={0} uses package-private {1} 0.will.no.longer.be.accessible.after.extraction={0} will no longer be accessible after extraction -0.will.become.invisible.after.extraction={0} will become invisible after extraction \ No newline at end of file +0.will.become.invisible.after.extraction={0} will become invisible after extraction + +naming.convention.will.be.violated.after.rename=Naming conventions will be violated after rename \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameJetClassProcessor.java b/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameJetClassProcessor.java index 0be616c3d0f..2b6e4eb0f87 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameJetClassProcessor.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameJetClassProcessor.java @@ -33,7 +33,7 @@ import org.jetbrains.jet.plugin.JetBundle; import java.util.Map; -public class RenameJetClassProcessor extends RenamePsiElementProcessor { +public class RenameJetClassProcessor extends RenameKotlinPsiProcessor { @Override public boolean canProcessElement(@NotNull PsiElement element) { return element instanceof JetClassOrObject || element instanceof KotlinLightClass; diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinFunctionProcessor.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinFunctionProcessor.kt index b5a338c0700..6ce36bb8d67 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinFunctionProcessor.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinFunctionProcessor.kt @@ -19,7 +19,6 @@ package org.jetbrains.jet.plugin.refactoring.rename; import com.intellij.openapi.editor.Editor import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod -import com.intellij.refactoring.rename.RenamePsiElementProcessor import com.intellij.psi.search.SearchScope import org.jetbrains.jet.asJava.LightClassUtil import org.jetbrains.jet.lang.psi.JetNamedFunction @@ -28,7 +27,7 @@ import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod import kotlin.properties.Delegates import org.jetbrains.jet.plugin.refactoring.runReadAction -public class RenameKotlinFunctionProcessor : RenamePsiElementProcessor() { +public class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() { private val javaMethodProcessorInstance by Delegates.lazy { // KT-4250 // RenamePsiElementProcessor.EP_NAME.findExtension(javaClass())!! @@ -65,4 +64,4 @@ public class RenameKotlinFunctionProcessor : RenamePsiElementProcessor() { is JetNamedFunction -> runReadAction { LightClassUtil.getLightClassMethod(element) } else -> throw IllegalStateException("Can't be for element $element there because of canProcessElement()") } -} +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinPsiProcessor.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinPsiProcessor.kt new file mode 100644 index 00000000000..e57a2876017 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinPsiProcessor.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2014 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.refactoring.rename + +import com.intellij.refactoring.rename.RenamePsiElementProcessor +import com.intellij.psi.PsiElement +import com.intellij.usageView.UsageInfo +import org.jetbrains.jet.lang.psi.JetNamedFunction +import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod +import org.jetbrains.jet.lang.psi.JetNamedDeclaration + +abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() { + override fun canProcessElement(element: PsiElement): Boolean = element is JetNamedDeclaration + + override fun findCollisions( + element: PsiElement?, + newName: String?, + allRenames: Map, + result: MutableList + ) { + checkConflictsAndReplaceUsageInfos(result) + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/rename/renameUtil.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/rename/renameUtil.kt new file mode 100644 index 00000000000..68b83424d44 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/rename/renameUtil.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2010-2014 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.refactoring.rename + +import com.intellij.psi.PsiElement +import com.intellij.usageView.UsageInfo +import java.util.ArrayList +import com.intellij.refactoring.util.MoveRenameUsageInfo +import org.jetbrains.jet.plugin.references.JetMultiDeclarationReference +import org.jetbrains.jet.lang.psi.psiUtil.getParentByTypeAndBranch +import org.jetbrains.jet.lang.psi.JetWhenConditionInRange +import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo +import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle +import org.jetbrains.jet.plugin.references.JetForLoopInReference +import org.jetbrains.jet.plugin.references.JetReference +import org.jetbrains.jet.plugin.references.AbstractJetReference + +fun checkConflictsAndReplaceUsageInfos(result: MutableList) { + val usagesToAdd = ArrayList() + val usagesToRemove = ArrayList() + + for (usageInfo in result) { + val ref = usageInfo.getReference() + if (usageInfo !is MoveRenameUsageInfo || ref !is AbstractJetReference<*> || ref.canRename()) continue + + val refElement = usageInfo.getElement() + val referencedElement = usageInfo.getReferencedElement() + if (refElement != null && referencedElement != null) { + usagesToAdd.add(UnresolvableConventionViolationUsageInfo(refElement, referencedElement)) + usagesToRemove.add(usageInfo) + } + } + + result.removeAll(usagesToRemove) + result.addAll(usagesToAdd) +} + +class UnresolvableConventionViolationUsageInfo( + element: PsiElement, + referencedElement: PsiElement +) : UnresolvableCollisionUsageInfo(element, referencedElement) { + override fun getDescription(): String = JetRefactoringBundle.message("naming.convention.will.be.violated.after.rename") +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java index 0af9ec1cdce..429a3c907bc 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java @@ -20,14 +20,18 @@ import com.google.common.collect.Lists; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.psi.MultiRangeReference; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import jet.runtime.typeinfo.JetValueParameter; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.psi.JetArrayAccessExpression; -import org.jetbrains.jet.lang.psi.JetContainerNode; +import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.jet.plugin.intentions.OperatorToFunctionIntention; import java.util.ArrayList; import java.util.Collection; @@ -84,4 +88,16 @@ public class JetArrayAccessReference extends JetSimpleReference(element) { override fun getTargetDescriptors(context: BindingContext): Collection { @@ -38,4 +43,13 @@ class JetMultiDeclarationReference(element: JetMultiDeclaration) : JetMultiRefer if (start == null || end == null) return TextRange.EMPTY_RANGE return TextRange(start.getStartOffsetInParent(), end.getStartOffsetInParent()) } + + override fun canRename(): Boolean { + return resolveToDescriptors().all { it is CallableMemberDescriptor && it.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED} + } + + override fun handleElementRename(newElementName: String?): PsiElement? { + if (canRename()) return expression + throw IncorrectOperationException() + } } diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetReference.kt b/idea/src/org/jetbrains/jet/plugin/references/JetReference.kt index 4072f2fe7db..0f21abdb81a 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetReference.kt +++ b/idea/src/org/jetbrains/jet/plugin/references/JetReference.kt @@ -43,7 +43,7 @@ public trait JetReference : PsiPolyVariantReference { public fun resolveMap(): Map> } -abstract class AbstractJetReference(element: T) +public abstract class AbstractJetReference(element: T) : PsiPolyVariantReferenceBase(element), JetReference { val expression: T @@ -67,6 +67,7 @@ abstract class AbstractJetReference(element: T) override fun getCanonicalText(): String = "" + open fun canRename(): Boolean = false override fun handleElementRename(newElementName: String?): PsiElement? = throw IncorrectOperationException() override fun bindToElement(element: PsiElement): PsiElement = throw IncorrectOperationException() diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.kt b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.kt index f43858f1c6f..07cade2d14d 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.kt +++ b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.kt @@ -28,6 +28,15 @@ import org.jetbrains.jet.lang.psi.psiUtil.getQualifiedElementSelector import org.jetbrains.jet.lang.psi.psiUtil.getOutermostNonInterleavingQualifiedElement import org.jetbrains.jet.plugin.codeInsight.addToShorteningWaitSet import org.jetbrains.jet.plugin.refactoring.getKotlinFqName +import org.jetbrains.jet.lang.types.expressions.OperatorConventions +import org.jetbrains.jet.lexer.JetToken +import org.jetbrains.jet.plugin.intentions.OperatorToFunctionIntention +import org.jetbrains.jet.lang.psi.psiUtil.getParentByType +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.DescriptorResolver +import com.intellij.util.IncorrectOperationException +import org.jetbrains.jet.lang.psi.psiUtil.getParentByTypeAndBranch public class JetSimpleNameReference( jetSimpleNameExpression: JetSimpleNameExpression @@ -35,8 +44,23 @@ public class JetSimpleNameReference( override fun getRangeInElement(): TextRange = TextRange(0, getElement().getTextLength()) + override fun canRename(): Boolean { + if (expression.getParentByTypeAndBranch(javaClass()) { getOperationReference() } != null) return false + + val elementType = expression.getReferencedNameElementType() + if (elementType == JetTokens.PLUSPLUS || elementType == JetTokens.MINUSMINUS) return false + + return true + } + public override fun handleElementRename(newElementName: String?): PsiElement? { - if (newElementName == null) return null; + if (!canRename()) throw IncorrectOperationException() + if (newElementName == null) return expression; + + // Do not rename if the reference corresponds to synthesized component function + if ((expression.getText() ?: "").startsWith(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX) && resolve() is JetParameter) { + return expression + } val psiFactory = JetPsiFactory(expression) val element = when (expression.getReferencedNameElementType()) { @@ -45,7 +69,30 @@ public class JetSimpleNameReference( else -> psiFactory.createNameIdentifier(newElementName) } - return expression.getReferencedNameElement().replace(element) + var nameElement = expression.getReferencedNameElement() + + val elementType = nameElement.getNode()?.getElementType() + val opExpression = + PsiTreeUtil.getParentOfType(expression, javaClass(), javaClass()) + if (elementType is JetToken && OperatorConventions.getNameForOperationSymbol(elementType) != null && opExpression != null) { + val oldDescriptor = AnalyzerFacadeWithCache.getContextForElement(expression)[BindingContext.REFERENCE_TARGET, expression] + val newExpression = OperatorToFunctionIntention.convert(opExpression) + newExpression.accept( + object: JetTreeVisitorVoid() { + override fun visitCallExpression(expression: JetCallExpression) { + val callee = expression.getCalleeExpression() as? JetSimpleNameExpression + if (callee != null && AnalyzerFacadeWithCache.getContextForElement(callee)[BindingContext.REFERENCE_TARGET, callee] == oldDescriptor) { + nameElement = callee.getReferencedNameElement() + } + else { + super.visitCallExpression(expression) + } + } + } + ) + } + + return nameElement.replace(element) } public enum class ShorteningMode { diff --git a/idea/src/org/jetbrains/jet/plugin/references/referenceUtil.kt b/idea/src/org/jetbrains/jet/plugin/references/referenceUtil.kt index cd9ac1bc044..e32d659f97b 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/referenceUtil.kt +++ b/idea/src/org/jetbrains/jet/plugin/references/referenceUtil.kt @@ -29,6 +29,12 @@ import org.jetbrains.jet.lang.psi.JetProperty import java.util.HashSet import com.intellij.util.containers.ContainerUtil import org.jetbrains.jet.lang.psi.JetNamedDeclaration +import org.jetbrains.jet.lang.psi.JetExpression +import org.jetbrains.jet.lang.psi.JetElement +import org.jetbrains.jet.plugin.intentions.OperatorToFunctionIntention +import org.jetbrains.jet.lang.psi.JetQualifiedExpression +import org.jetbrains.jet.lang.psi.JetCallExpression +import com.intellij.psi.util.PsiTreeUtil // Navigation element of the resolved reference // For property accessor return enclosing property @@ -59,3 +65,11 @@ fun PsiReference.matchesTarget(target: PsiElement): Boolean { false } } + +fun AbstractJetReference.renameImplicitConventionalCall(newName: String?): JetExpression { + if (newName == null) return expression + + val expr = OperatorToFunctionIntention.convert(expression) as JetQualifiedExpression + val newCallee = (expr.getSelectorExpression() as JetCallExpression).getCalleeExpression()!!.getReference()!!.handleElementRename(newName) + return PsiTreeUtil.getParentOfType(newCallee, javaClass()) as JetExpression +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameCompareTo/after/compareTo.kt b/idea/testData/refactoring/rename/renameCompareTo/after/compareTo.kt new file mode 100644 index 00000000000..8f8df778252 --- /dev/null +++ b/idea/testData/refactoring/rename/renameCompareTo/after/compareTo.kt @@ -0,0 +1,11 @@ +class A(val n: Int) { + fun foo(other: A): Int = n.compareTo(other.n) +} + +fun test() { + A(0) foo A(1) + A(0).foo(A(1)) < 0 + A(0).foo(A(1)) <= 0 + A(0).foo(A(1)) > 0 + A(0).foo(A(1)) >= 0 +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameCompareTo/before/compareTo.kt b/idea/testData/refactoring/rename/renameCompareTo/before/compareTo.kt new file mode 100644 index 00000000000..11886186fa1 --- /dev/null +++ b/idea/testData/refactoring/rename/renameCompareTo/before/compareTo.kt @@ -0,0 +1,11 @@ +class A(val n: Int) { + fun compareTo(other: A): Int = n.compareTo(other.n) +} + +fun test() { + A(0) compareTo A(1) + A(0) < A(1) + A(0) <= A(1) + A(0) > A(1) + A(0) >= A(1) +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameCompareTo/compareTo.test b/idea/testData/refactoring/rename/renameCompareTo/compareTo.test new file mode 100644 index 00000000000..6ccee8cbbc4 --- /dev/null +++ b/idea/testData/refactoring/rename/renameCompareTo/compareTo.test @@ -0,0 +1,7 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "compareTo", + "newName": "foo", + "mainFile": "compareTo.kt" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameContains/after/contains.kt b/idea/testData/refactoring/rename/renameContains/after/contains.kt new file mode 100644 index 00000000000..65889e6424e --- /dev/null +++ b/idea/testData/refactoring/rename/renameContains/after/contains.kt @@ -0,0 +1,9 @@ +class A(val n: Int) { + fun foo(k: Int): Boolean = k <= n +} + +fun test() { + A(2) foo 1 + A(2).foo(1) + !A(2).foo(1) +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameContains/before/contains.kt b/idea/testData/refactoring/rename/renameContains/before/contains.kt new file mode 100644 index 00000000000..0163dd5e1ba --- /dev/null +++ b/idea/testData/refactoring/rename/renameContains/before/contains.kt @@ -0,0 +1,9 @@ +class A(val n: Int) { + fun contains(k: Int): Boolean = k <= n +} + +fun test() { + A(2) contains 1 + 1 in A(2) + 1 !in A(2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameContains/contains.test b/idea/testData/refactoring/rename/renameContains/contains.test new file mode 100644 index 00000000000..c80f2715acc --- /dev/null +++ b/idea/testData/refactoring/rename/renameContains/contains.test @@ -0,0 +1,7 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "contains", + "newName": "foo", + "mainFile": "contains.kt" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameContainsWithConflicts/before/containsWithConflicts.kt b/idea/testData/refactoring/rename/renameContainsWithConflicts/before/containsWithConflicts.kt new file mode 100644 index 00000000000..ab1e6d6a826 --- /dev/null +++ b/idea/testData/refactoring/rename/renameContainsWithConflicts/before/containsWithConflicts.kt @@ -0,0 +1,13 @@ +class A(val n: Int) { + fun contains(k: Int): Boolean = k <= n +} + +fun test() { + A(2) contains 1 + 1 in A(2) + 1 !in A(2) + when (1) { + in A(2) -> {} + !in A(2) -> {} + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameContainsWithConflicts/containsWithConflicts.test b/idea/testData/refactoring/rename/renameContainsWithConflicts/containsWithConflicts.test new file mode 100644 index 00000000000..719f77c2707 --- /dev/null +++ b/idea/testData/refactoring/rename/renameContainsWithConflicts/containsWithConflicts.test @@ -0,0 +1,8 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "contains", + "newName": "foo", + "mainFile": "containsWithConflicts.kt", + "hint": "Naming conventions will be violated after rename\nNaming conventions will be violated after rename" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameEquals/after/equals.kt b/idea/testData/refactoring/rename/renameEquals/after/equals.kt new file mode 100644 index 00000000000..e48e4e842da --- /dev/null +++ b/idea/testData/refactoring/rename/renameEquals/after/equals.kt @@ -0,0 +1,11 @@ +class A(val n: Int) { + override fun foo(other: Any?): Boolean = other is A && other.n == n +} + +fun test() { + A(0).foo(A(1)) + !A(0).foo(A(1)) + A(0) foo A(1) + A(0) === A(1) + A(0) !== A(1) +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameEquals/before/equals.kt b/idea/testData/refactoring/rename/renameEquals/before/equals.kt new file mode 100644 index 00000000000..0a3dd16e317 --- /dev/null +++ b/idea/testData/refactoring/rename/renameEquals/before/equals.kt @@ -0,0 +1,11 @@ +class A(val n: Int) { + override fun equals(other: Any?): Boolean = other is A && other.n == n +} + +fun test() { + A(0) == A(1) + A(0) != A(1) + A(0) equals A(1) + A(0) === A(1) + A(0) !== A(1) +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameEquals/equals.test b/idea/testData/refactoring/rename/renameEquals/equals.test new file mode 100644 index 00000000000..06ad435519b --- /dev/null +++ b/idea/testData/refactoring/rename/renameEquals/equals.test @@ -0,0 +1,7 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "equals", + "newName": "foo", + "mainFile": "equals.kt" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameExplicitComponentFunction/before/explicitComponentFunction.kt b/idea/testData/refactoring/rename/renameExplicitComponentFunction/before/explicitComponentFunction.kt new file mode 100644 index 00000000000..64c676ef4d1 --- /dev/null +++ b/idea/testData/refactoring/rename/renameExplicitComponentFunction/before/explicitComponentFunction.kt @@ -0,0 +1,12 @@ +class A(val n: Int, val s: String, val o: Any) { + fun component1(): Int = n + fun component2(): String = s + fun component3(): Any = o +} + +fun test() { + val a = A(1, "2", Any()) + a.n + a.component1() + val (x, y, z) = a +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameExplicitComponentFunction/explicitComponentFunction.test b/idea/testData/refactoring/rename/renameExplicitComponentFunction/explicitComponentFunction.test new file mode 100644 index 00000000000..0c5ed8aea5c --- /dev/null +++ b/idea/testData/refactoring/rename/renameExplicitComponentFunction/explicitComponentFunction.test @@ -0,0 +1,8 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "component1", + "newName": "foo", + "mainFile": "explicitComponentFunction.kt", + "hint": "Naming conventions will be violated after rename" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameGet/after/get.kt b/idea/testData/refactoring/rename/renameGet/after/get.kt new file mode 100644 index 00000000000..d620b43aa28 --- /dev/null +++ b/idea/testData/refactoring/rename/renameGet/after/get.kt @@ -0,0 +1,8 @@ +class A(val n: Int) { + fun foo(i: Int): A = A(i) +} + +fun test() { + A(1).foo(2) + A(1).foo(2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameGet/before/get.kt b/idea/testData/refactoring/rename/renameGet/before/get.kt new file mode 100644 index 00000000000..0d6c8ad4f08 --- /dev/null +++ b/idea/testData/refactoring/rename/renameGet/before/get.kt @@ -0,0 +1,8 @@ +class A(val n: Int) { + fun get(i: Int): A = A(i) +} + +fun test() { + A(1).get(2) + A(1)[2] +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameGet/get.test b/idea/testData/refactoring/rename/renameGet/get.test new file mode 100644 index 00000000000..5a018eca58e --- /dev/null +++ b/idea/testData/refactoring/rename/renameGet/get.test @@ -0,0 +1,7 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "get", + "newName": "foo", + "mainFile": "get.kt" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameInc/before/inc.kt b/idea/testData/refactoring/rename/renameInc/before/inc.kt new file mode 100644 index 00000000000..6fd9af98845 --- /dev/null +++ b/idea/testData/refactoring/rename/renameInc/before/inc.kt @@ -0,0 +1,10 @@ +class A(val n: Int) { + fun inc(): A = A(n + 1) +} + +fun test() { + var a = A(1) + a.inc() + ++a + a++ +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameInc/inc.test b/idea/testData/refactoring/rename/renameInc/inc.test new file mode 100644 index 00000000000..1d1f30df8c2 --- /dev/null +++ b/idea/testData/refactoring/rename/renameInc/inc.test @@ -0,0 +1,8 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "inc", + "newName": "foo", + "mainFile": "inc.kt", + "hint": "Naming conventions will be violated after rename\nNaming conventions will be violated after rename" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameInvoke/after/invoke.kt b/idea/testData/refactoring/rename/renameInvoke/after/invoke.kt new file mode 100644 index 00000000000..d620b43aa28 --- /dev/null +++ b/idea/testData/refactoring/rename/renameInvoke/after/invoke.kt @@ -0,0 +1,8 @@ +class A(val n: Int) { + fun foo(i: Int): A = A(i) +} + +fun test() { + A(1).foo(2) + A(1).foo(2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameInvoke/before/invoke.kt b/idea/testData/refactoring/rename/renameInvoke/before/invoke.kt new file mode 100644 index 00000000000..a589143887e --- /dev/null +++ b/idea/testData/refactoring/rename/renameInvoke/before/invoke.kt @@ -0,0 +1,8 @@ +class A(val n: Int) { + fun invoke(i: Int): A = A(i) +} + +fun test() { + A(1).invoke(2) + A(1)(2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameInvoke/invoke.test b/idea/testData/refactoring/rename/renameInvoke/invoke.test new file mode 100644 index 00000000000..77375211b4f --- /dev/null +++ b/idea/testData/refactoring/rename/renameInvoke/invoke.test @@ -0,0 +1,7 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "invoke", + "newName": "foo", + "mainFile": "invoke.kt" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameIterator/before/iterator.kt b/idea/testData/refactoring/rename/renameIterator/before/iterator.kt new file mode 100644 index 00000000000..9a8c721a05f --- /dev/null +++ b/idea/testData/refactoring/rename/renameIterator/before/iterator.kt @@ -0,0 +1,8 @@ +class A { + public fun iterator(): Iterator = throw IllegalStateException("") +} + +fun test() { + for (a in A()) {} + a.iterator() +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameIterator/iterator.test b/idea/testData/refactoring/rename/renameIterator/iterator.test new file mode 100644 index 00000000000..8fd734de611 --- /dev/null +++ b/idea/testData/refactoring/rename/renameIterator/iterator.test @@ -0,0 +1,8 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "iterator", + "newName": "foo", + "mainFile": "iterator.kt", + "hint": "Naming conventions will be violated after rename" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renamePlus/after/plus.kt b/idea/testData/refactoring/rename/renamePlus/after/plus.kt new file mode 100644 index 00000000000..22e33fbbdec --- /dev/null +++ b/idea/testData/refactoring/rename/renamePlus/after/plus.kt @@ -0,0 +1,12 @@ +class A(val n: Int) { + fun foo(m: Int): A = A(n + m) +} + +fun test() { + A(1).foo(2) + A(1) foo 2 + A(1).foo(2) + + var a = A(0) + a = a.foo(1) +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renamePlus/before/plus.kt b/idea/testData/refactoring/rename/renamePlus/before/plus.kt new file mode 100644 index 00000000000..c202a28b32f --- /dev/null +++ b/idea/testData/refactoring/rename/renamePlus/before/plus.kt @@ -0,0 +1,12 @@ +class A(val n: Int) { + fun plus(m: Int): A = A(n + m) +} + +fun test() { + A(1) + 2 + A(1) plus 2 + A(1).plus(2) + + var a = A(0) + a += 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renamePlus/plus.test b/idea/testData/refactoring/rename/renamePlus/plus.test new file mode 100644 index 00000000000..894c27a333f --- /dev/null +++ b/idea/testData/refactoring/rename/renamePlus/plus.test @@ -0,0 +1,7 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "plus", + "newName": "foo", + "mainFile": "plus.kt" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renamePlusAssign/after/plusAssign.kt b/idea/testData/refactoring/rename/renamePlusAssign/after/plusAssign.kt new file mode 100644 index 00000000000..7929f53bc6a --- /dev/null +++ b/idea/testData/refactoring/rename/renamePlusAssign/after/plusAssign.kt @@ -0,0 +1,11 @@ +class A(var n: Int) { + fun foo(m: Int) { + n += m + } +} + +fun test() { + val a = A(0) + a.foo(1) + a.foo(1) +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renamePlusAssign/before/plusAssign.kt b/idea/testData/refactoring/rename/renamePlusAssign/before/plusAssign.kt new file mode 100644 index 00000000000..f0a0b17069a --- /dev/null +++ b/idea/testData/refactoring/rename/renamePlusAssign/before/plusAssign.kt @@ -0,0 +1,11 @@ +class A(var n: Int) { + fun plusAssign(m: Int) { + n += m + } +} + +fun test() { + val a = A(0) + a.plusAssign(1) + a += 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renamePlusAssign/plusAssign.test b/idea/testData/refactoring/rename/renamePlusAssign/plusAssign.test new file mode 100644 index 00000000000..26135dac894 --- /dev/null +++ b/idea/testData/refactoring/rename/renamePlusAssign/plusAssign.test @@ -0,0 +1,7 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "plusAssign", + "newName": "foo", + "mainFile": "plusAssign.kt" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameSet/after/set.kt b/idea/testData/refactoring/rename/renameSet/after/set.kt new file mode 100644 index 00000000000..5daf54cf8b8 --- /dev/null +++ b/idea/testData/refactoring/rename/renameSet/after/set.kt @@ -0,0 +1,10 @@ +class A(val n: Int) { + fun foo(i: Int, a: A) {} +} + +fun test() { + var a = A(1) + a.foo(2, A(2)) + a.foo(2, A(2)) + a[2] +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameSet/before/set.kt b/idea/testData/refactoring/rename/renameSet/before/set.kt new file mode 100644 index 00000000000..9a9f4b61f51 --- /dev/null +++ b/idea/testData/refactoring/rename/renameSet/before/set.kt @@ -0,0 +1,10 @@ +class A(val n: Int) { + fun set(i: Int, a: A) {} +} + +fun test() { + var a = A(1) + a.set(2, A(2)) + a[2] = A(2) + a[2] +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameSet/set.test b/idea/testData/refactoring/rename/renameSet/set.test new file mode 100644 index 00000000000..ab45896ef59 --- /dev/null +++ b/idea/testData/refactoring/rename/renameSet/set.test @@ -0,0 +1,7 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "set", + "newName": "foo", + "mainFile": "set.kt" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameSynthesizedComponentFunction/after/synthesizedComponentFunction.kt b/idea/testData/refactoring/rename/renameSynthesizedComponentFunction/after/synthesizedComponentFunction.kt new file mode 100644 index 00000000000..352a58e361b --- /dev/null +++ b/idea/testData/refactoring/rename/renameSynthesizedComponentFunction/after/synthesizedComponentFunction.kt @@ -0,0 +1,8 @@ +data class A(val foo: Int, val s: String, val o: Any) + +fun test() { + val a = A(1, "2", Any()) + a.foo + a.component1() + val (x, y, z) = a +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameSynthesizedComponentFunction/before/synthesizedComponentFunction.kt b/idea/testData/refactoring/rename/renameSynthesizedComponentFunction/before/synthesizedComponentFunction.kt new file mode 100644 index 00000000000..73a12db9c7f --- /dev/null +++ b/idea/testData/refactoring/rename/renameSynthesizedComponentFunction/before/synthesizedComponentFunction.kt @@ -0,0 +1,8 @@ +data class A(val n: Int, val s: String, val o: Any) + +fun test() { + val a = A(1, "2", Any()) + a.n + a.component1() + val (x, y, z) = a +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameSynthesizedComponentFunction/synthesizedComponentFunction.test b/idea/testData/refactoring/rename/renameSynthesizedComponentFunction/synthesizedComponentFunction.test new file mode 100644 index 00000000000..097e87861f0 --- /dev/null +++ b/idea/testData/refactoring/rename/renameSynthesizedComponentFunction/synthesizedComponentFunction.test @@ -0,0 +1,7 @@ +{ + "type": "KOTLIN_PROPERTY", + "classFQN": "A", + "oldName": "n", + "newName": "foo", + "mainFile": "synthesizedComponentFunction.kt" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameUnaryMinus/after/unaryMinus.kt b/idea/testData/refactoring/rename/renameUnaryMinus/after/unaryMinus.kt new file mode 100644 index 00000000000..42e9b82a1c9 --- /dev/null +++ b/idea/testData/refactoring/rename/renameUnaryMinus/after/unaryMinus.kt @@ -0,0 +1,8 @@ +class A(val n: Int) { + fun foo(): A = this +} + +fun test() { + A(1).foo() + A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameUnaryMinus/before/unaryMinus.kt b/idea/testData/refactoring/rename/renameUnaryMinus/before/unaryMinus.kt new file mode 100644 index 00000000000..fc104dc18ff --- /dev/null +++ b/idea/testData/refactoring/rename/renameUnaryMinus/before/unaryMinus.kt @@ -0,0 +1,8 @@ +class A(val n: Int) { + fun minus(): A = this +} + +fun test() { + A(1).minus() + -A(1) +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/renameUnaryMinus/unaryMinus.test b/idea/testData/refactoring/rename/renameUnaryMinus/unaryMinus.test new file mode 100644 index 00000000000..d14734240d6 --- /dev/null +++ b/idea/testData/refactoring/rename/renameUnaryMinus/unaryMinus.test @@ -0,0 +1,7 @@ +{ + "type": "KOTLIN_FUNCTION", + "classFQN": "A", + "oldName": "minus", + "newName": "foo", + "mainFile": "unaryMinus.kt" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/AbstractRenameTest.kt b/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/AbstractRenameTest.kt index d72d6480b71..acf4d380a43 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/AbstractRenameTest.kt +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/AbstractRenameTest.kt @@ -48,6 +48,8 @@ import org.jetbrains.jet.getNullableString import org.jetbrains.jet.plugin.search.allScope import org.jetbrains.jet.plugin.caches.resolve.getBindingContext import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils +import com.intellij.refactoring.BaseRefactoringProcessor.ConflictsInTestsException +import com.intellij.refactoring.util.CommonRefactoringUtil.RefactoringErrorHintException private enum class RenameType { JAVA_CLASS @@ -90,8 +92,10 @@ public abstract class AbstractRenameTest : MultiFileTestCase() { Assert.fail("""Hint "$hintDirective" was expected""") } } - catch (hintException : CommonRefactoringUtil.RefactoringErrorHintException) { - val hintExceptionUnquoted = StringUtil.unquoteString(hintException.getMessage()!!) + catch (e : Exception) { + if (e !is RefactoringErrorHintException && e !is ConflictsInTestsException) throw e + + val hintExceptionUnquoted = StringUtil.unquoteString(e.getMessage()!!) if (hintDirective != null) { Assert.assertEquals(hintDirective, hintExceptionUnquoted) } diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/RenameTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/RenameTestGenerated.java index 577c8ca7c66..2fe2b14e5b3 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/RenameTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/RenameTestGenerated.java @@ -36,6 +36,51 @@ public class RenameTestGenerated extends AbstractRenameTest { JetTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/rename"), Pattern.compile("^(.+)\\.test$")); } + @TestMetadata("renameCompareTo/compareTo.test") + public void testRenameCompareTo_CompareTo() throws Exception { + doTest("idea/testData/refactoring/rename/renameCompareTo/compareTo.test"); + } + + @TestMetadata("renameContains/contains.test") + public void testRenameContains_Contains() throws Exception { + doTest("idea/testData/refactoring/rename/renameContains/contains.test"); + } + + @TestMetadata("renameContainsWithConflicts/containsWithConflicts.test") + public void testRenameContainsWithConflicts_ContainsWithConflicts() throws Exception { + doTest("idea/testData/refactoring/rename/renameContainsWithConflicts/containsWithConflicts.test"); + } + + @TestMetadata("renameEquals/equals.test") + public void testRenameEquals_Equals() throws Exception { + doTest("idea/testData/refactoring/rename/renameEquals/equals.test"); + } + + @TestMetadata("renameExplicitComponentFunction/explicitComponentFunction.test") + public void testRenameExplicitComponentFunction_ExplicitComponentFunction() throws Exception { + doTest("idea/testData/refactoring/rename/renameExplicitComponentFunction/explicitComponentFunction.test"); + } + + @TestMetadata("renameGet/get.test") + public void testRenameGet_Get() throws Exception { + doTest("idea/testData/refactoring/rename/renameGet/get.test"); + } + + @TestMetadata("renameInc/inc.test") + public void testRenameInc_Inc() throws Exception { + doTest("idea/testData/refactoring/rename/renameInc/inc.test"); + } + + @TestMetadata("renameInvoke/invoke.test") + public void testRenameInvoke_Invoke() throws Exception { + doTest("idea/testData/refactoring/rename/renameInvoke/invoke.test"); + } + + @TestMetadata("renameIterator/iterator.test") + public void testRenameIterator_Iterator() throws Exception { + doTest("idea/testData/refactoring/rename/renameIterator/iterator.test"); + } + @TestMetadata("renameJavaClass/renameJavaClass.test") public void testRenameJavaClass_RenameJavaClass() throws Exception { doTest("idea/testData/refactoring/rename/renameJavaClass/renameJavaClass.test"); @@ -161,4 +206,29 @@ public class RenameTestGenerated extends AbstractRenameTest { doTest("idea/testData/refactoring/rename/renameKotlinVarProperty/renameOverriden.test"); } + @TestMetadata("renamePlus/plus.test") + public void testRenamePlus_Plus() throws Exception { + doTest("idea/testData/refactoring/rename/renamePlus/plus.test"); + } + + @TestMetadata("renamePlusAssign/plusAssign.test") + public void testRenamePlusAssign_PlusAssign() throws Exception { + doTest("idea/testData/refactoring/rename/renamePlusAssign/plusAssign.test"); + } + + @TestMetadata("renameSet/set.test") + public void testRenameSet_Set() throws Exception { + doTest("idea/testData/refactoring/rename/renameSet/set.test"); + } + + @TestMetadata("renameSynthesizedComponentFunction/synthesizedComponentFunction.test") + public void testRenameSynthesizedComponentFunction_SynthesizedComponentFunction() throws Exception { + doTest("idea/testData/refactoring/rename/renameSynthesizedComponentFunction/synthesizedComponentFunction.test"); + } + + @TestMetadata("renameUnaryMinus/unaryMinus.test") + public void testRenameUnaryMinus_UnaryMinus() throws Exception { + doTest("idea/testData/refactoring/rename/renameUnaryMinus/unaryMinus.test"); + } + }